Merge branch 'main' into electron-19.x.y

This commit is contained in:
Robo 2022-08-03 17:50:53 -07:00 committed by GitHub
commit afdf486c1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
96 changed files with 948 additions and 643 deletions

View file

@ -259,6 +259,7 @@
"windows-process-tree",
"worker_threads",
"xterm",
"xterm-addon-canvas",
"xterm-addon-search",
"xterm-addon-serialize",
"xterm-addon-unicode11",

View file

@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"July 2022\""
"value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"August 2022\""
},
{
"kind": 1,

View file

@ -20,6 +20,9 @@ vscode-textmate/webpack.config.js
xterm/src/**
xterm-addon-canvas/src/**
xterm-addon-canvas/out/**
xterm-addon-search/src/**
xterm-addon-search/out/**
xterm-addon-search/fixtures/**

View file

@ -65,7 +65,7 @@
"emmet.showAbbreviationSuggestions": {
"type": "boolean",
"default": true,
"scope": "language-overridable",
"scope": "resource",
"markdownDescription": "%emmetShowAbbreviationSuggestions%"
},
"emmet.includeLanguages": {

View file

@ -264,47 +264,47 @@ export async function wrapWithAbbreviation(args: any): Promise<boolean> {
}
export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined> {
if (!validate() || !vscode.window.activeTextEditor) {
return fallbackTab();
if (!validate()) {
return Promise.resolve(undefined);
}
const editor = vscode.window.activeTextEditor!;
args = args || {};
if (!args['language']) {
args['language'] = editor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ?? [];
if (excludedLanguages.includes(args['language'])) {
return fallbackTab(args['language']);
}
}
const languageId: string = args['language'];
/**
* Short circuit the parsing. If previous character is space, do not expand.
*/
if (vscode.window.activeTextEditor.selections.length === 1 &&
vscode.window.activeTextEditor.selection.isEmpty
if (editor.selections.length === 1 && editor.selection.isEmpty
) {
const anchor = vscode.window.activeTextEditor.selection.anchor;
const anchor = editor.selection.anchor;
if (anchor.character === 0) {
return fallbackTab();
return fallbackTab(languageId);
}
const prevPositionAnchor = anchor.translate(0, -1);
const prevText = vscode.window.activeTextEditor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
const prevText = editor.document.getText(new vscode.Range(prevPositionAnchor, anchor));
if (prevText === ' ' || prevText === '\t') {
return fallbackTab();
return fallbackTab(languageId);
}
}
args = args || {};
if (!args['language']) {
args['language'] = vscode.window.activeTextEditor.document.languageId;
} else {
const excludedLanguages = vscode.workspace.getConfiguration('emmet')['excludeLanguages'] ? vscode.workspace.getConfiguration('emmet')['excludeLanguages'] : [];
if (excludedLanguages.indexOf(vscode.window.activeTextEditor.document.languageId) > -1) {
return fallbackTab();
}
}
const syntax = getSyntaxFromArgs(args);
if (!syntax) {
return fallbackTab();
return fallbackTab(languageId);
}
const editor = vscode.window.activeTextEditor;
// When tabbed on a non empty selection, do not treat it as an emmet abbreviation, and fallback to tab instead
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab();
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true && editor.selections.find(x => !x.isEmpty)) {
return fallbackTab(languageId);
}
const abbreviationList: ExpandAbbreviationInput[] = [];
@ -325,7 +325,7 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
}
const currentLine = editor.document.lineAt(position.line).text;
const textTillPosition = currentLine.substr(0, position.character);
const textTillPosition = currentLine.substring(0, position.character);
// Expand cases like <div to <div></div> explicitly
// else we will end up with <<div></div>
@ -415,12 +415,12 @@ export function expandEmmetAbbreviation(args: any): Thenable<boolean | undefined
});
return expandAbbreviationInRange(editor, abbreviationList, allAbbreviationsSame).then(success => {
return success ? Promise.resolve(undefined) : fallbackTab();
return success ? Promise.resolve(undefined) : fallbackTab(languageId);
});
}
function fallbackTab(): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet')['triggerExpansionOnTab'] === true) {
function fallbackTab(languageId: string): Thenable<boolean | undefined> {
if (vscode.workspace.getConfiguration('emmet', { languageId })['triggerExpansionOnTab'] === true) {
return vscode.commands.executeCommand('tab');
}
return Promise.resolve(true);
@ -470,13 +470,13 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& offset <= propertyNode.terminatorToken.start
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (!propertyNode.terminatorToken
&& propertyNode.separator
&& offset >= propertyNode.separatorToken.end
&& abbreviation.indexOf(':') === -1) {
&& !abbreviation.includes(':')) {
return hexColorRegex.test(abbreviation) || abbreviation === '!';
}
if (hexColorRegex.test(abbreviation) || abbreviation === '!') {
@ -529,7 +529,7 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen
const typeAttribute = (currentHtmlNode.attributes || []).filter(x => x.name.toString() === 'type')[0];
const typeValue = typeAttribute ? typeAttribute.value.toString() : '';
if (allowedMimeTypesInScriptTag.indexOf(typeValue) > -1) {
if (allowedMimeTypesInScriptTag.includes(typeValue)) {
return true;
}

View file

@ -31,7 +31,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
if (expandedText.startsWith('<')) {
this.lastCompletionType = 'html';
} else if (expandedText.indexOf(':') > 0 && expandedText.endsWith(';')) {
} else if (expandedText.includes(':') && expandedText.endsWith(';')) {
this.lastCompletionType = 'css';
} else {
this.lastCompletionType = undefined;
@ -43,7 +43,7 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi
private provideCompletionItemsInternal(document: vscode.TextDocument, position: vscode.Position, context: vscode.CompletionContext): Thenable<vscode.CompletionList | undefined> | undefined {
const emmetConfig = vscode.workspace.getConfiguration('emmet');
const excludedLanguages = emmetConfig['excludeLanguages'] ? emmetConfig['excludeLanguages'] : [];
if (excludedLanguages.indexOf(document.languageId) > -1) {
if (excludedLanguages.includes(document.languageId)) {
return;
}

View file

@ -140,7 +140,7 @@ function getNextAttribute(document: vscode.TextDocument, selectionStart: number,
}
// Fetch the next word in the attr value
if (attr.value.toString().indexOf(' ') === -1) {
if (!attr.value.toString().includes(' ')) {
// attr value does not have space, so no next word to find
continue;
}

View file

@ -22,7 +22,7 @@ export async function activate(ctx: RendererContext<void>) {
md.renderer.rules.image = (tokens: MarkdownItToken[], idx: number, options, env, self) => {
const token = tokens[idx];
const src = token.attrGet('src');
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata?.custom?.attachments; // this stores attachment entries for every image in the cell
const attachments: Record<string, Record<string, string>> = env.outputItem.metadata().custom?.attachments;
if (attachments && src) {
const imageAttachment = attachments[src.replace('attachment:', '')];
if (imageAttachment) {

View file

@ -44,7 +44,7 @@ export interface CellOutputMetadata {
/**
* Metadata we store in VS Code cells.
* This contains the original metadata from the Jupyuter cells.
* This contains the original metadata from the Jupyter cells.
*/
export interface CellMetadata {
/**

View file

@ -164,17 +164,6 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await saveAllFilesAndCloseAll();
});
test('edit API batch edits', async function () {
const notebook = await openRandomNotebookDocument();
const edit = new vscode.WorkspaceEdit();
const metdataEdit = vscode.NotebookEdit.updateNotebookMetadata({ ...notebook.metadata, custom: { ...(notebook.metadata.custom || {}), extraNotebookMetadata: true } });
edit.set(notebook.uri, [metdataEdit]);
const success = await vscode.workspace.applyEdit(edit);
assert.equal(success, true);
assert.ok(notebook.metadata.custom.extraNotebookMetadata, `Test metadata not found`);
});
test('notebook open', async function () {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
@ -298,7 +287,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', apiTestContentProvider));
});
test.skip('provideCellStatusBarItems called on metadata change', async function () { // TODO@roblourens https://github.com/microsoft/vscode/issues/139324
test('provideCellStatusBarItems called on metadata change', async function () {
const provideCalled = asPromise(onDidCallProvide);
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
@ -306,7 +295,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
const edit = new vscode.WorkspaceEdit();
edit.replaceNotebookCellMetadata(notebook.uri, 0, { inputCollapsed: true });
vscode.workspace.applyEdit(edit);
await vscode.workspace.applyEdit(edit);
await provideCalled;
});
});

View file

@ -315,6 +315,18 @@ suite('Notebook Document', function () {
assert.strictEqual(data.cellChanges[0].cell.index, 0);
});
test('workspace edit API (notebookMetadata)', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const document = await vscode.workspace.openNotebookDocument(uri);
const edit = new vscode.WorkspaceEdit();
const metdataEdit = vscode.NotebookEdit.updateNotebookMetadata({ ...document.metadata, custom: { ...(document.metadata.custom || {}), extraNotebookMetadata: true } });
edit.set(document.uri, [metdataEdit]);
const success = await vscode.workspace.applyEdit(edit);
assert.equal(success, true);
assert.ok(document.metadata.custom.extraNotebookMetadata, `Test metadata not found`);
});
test('document save API', async function () {
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const notebook = await vscode.workspace.openNotebookDocument(uri);

View file

@ -65,39 +65,6 @@ import * as utils from '../utils';
testDisposables.length = 0;
});
test.skip('showNotebookDocument', async function () { // TODO@rebornix https://github.com/microsoft/vscode/issues/139078
const notebookDocumentsFromOnDidOpen = new Set<vscode.NotebookDocument>();
const sub = vscode.workspace.onDidOpenNotebookDocument(e => {
notebookDocumentsFromOnDidOpen.add(e);
});
const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor = await vscode.window.showNotebookDocument(uri);
assert.strictEqual(uri.toString(), editor.notebook.uri.toString());
assert.strictEqual(notebookDocumentsFromOnDidOpen.has(editor.notebook), true);
const includes = vscode.workspace.notebookDocuments.includes(editor.notebook);
assert.strictEqual(true, includes);
sub.dispose();
});
// TODO@rebornix deal with getting started
test.skip('notebook editor has viewColumn', async function () {
const uri1 = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor1 = await vscode.window.showNotebookDocument(uri1);
assert.strictEqual(editor1.viewColumn, vscode.ViewColumn.One);
const uri2 = await utils.createRandomFile(undefined, undefined, '.nbdtest');
const editor2 = await vscode.window.showNotebookDocument(uri2, { viewColumn: vscode.ViewColumn.Beside });
assert.strictEqual(editor2.viewColumn, vscode.ViewColumn.Two);
});
// #138683
test('Opening a notebook should fire activeNotebook event changed only once', async function () {
const openedEditor = onDidOpenNotebookEditor();

View file

@ -174,19 +174,7 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
await saveAllFilesAndCloseAll();
});
// TODO@rebornix this is wrong, `await vscode.commands.executeCommand('notebook.execute');` doesn't wait until the workspace edit is applied
test.skip('cell execute command takes arguments', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
const editor = vscode.window.activeNotebookEditor!;
const cell = editor.notebook.cellAt(0);
await vscode.commands.executeCommand('notebook.execute');
assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work
});
test('cell execute command takes arguments 2', async () => {
test('cell execute command takes arguments', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first');
@ -217,11 +205,10 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
});
// #126371
test.skip('cell execute command takes arguments ICellRange[]', async () => {
test('cell execute command takes arguments', async () => {
const notebook = await openRandomNotebookDocument();
await vscode.window.showNotebookDocument(notebook);
vscode.commands.executeCommand('notebook.cell.execute', { ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] });
let firstCellExecuted = false;
let secondCellExecuted = false;
let resolve: () => void;
@ -242,6 +229,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
}
});
vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] });
await p;
listener.dispose();
await saveAllFilesAndCloseAll();
@ -306,12 +295,11 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
});
});
test.skip('onDidChangeCellExecutionState is fired', async () => { // TODO@rebornix https://github.com/microsoft/vscode/issues/139350
test('onDidChangeCellExecutionState is fired', async () => {
const notebook = await openRandomNotebookDocument();
const editor = await vscode.window.showNotebookDocument(notebook);
const cell = editor.notebook.cellAt(0);
vscode.commands.executeCommand('notebook.cell.execute');
let eventCount = 0;
let resolve: () => void;
const p = new Promise<void>(r => resolve = r);
@ -330,6 +318,8 @@ const apiTestContentProvider: vscode.NotebookContentProvider = {
eventCount++;
});
vscode.commands.executeCommand('notebook.cell.execute', { document: notebook.uri, ranges: [{ start: 0, end: 1 }] });
await p;
listener.dispose();
});

View file

@ -86,12 +86,13 @@
"vscode-proxy-agent": "^0.12.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "7.0.1",
"xterm": "4.20.0-beta.20",
"xterm": "5.0.0-beta.32",
"xterm-addon-canvas": "0.2.0-beta.15",
"xterm-addon-search": "0.10.0-beta.3",
"xterm-addon-serialize": "0.8.0-beta.3",
"xterm-addon-unicode11": "0.4.0-beta.3",
"xterm-addon-webgl": "0.13.0-beta.9",
"xterm-headless": "4.20.0-beta.20",
"xterm-addon-webgl": "0.13.0-beta.32",
"xterm-headless": "5.0.0-beta.5",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
},
@ -124,7 +125,7 @@
"@types/yazl": "^2.4.2",
"@typescript-eslint/eslint-plugin": "^5.10.0",
"@typescript-eslint/parser": "^5.10.0",
"@vscode/telemetry-extractor": "^1.9.6",
"@vscode/telemetry-extractor": "^1.9.8",
"@vscode/test-web": "^0.0.29",
"ansi-colors": "^3.2.3",
"asar": "^3.0.3",

View file

@ -24,12 +24,13 @@
"vscode-proxy-agent": "^0.12.0",
"vscode-regexpp": "^3.1.0",
"vscode-textmate": "7.0.1",
"xterm": "4.20.0-beta.20",
"xterm": "5.0.0-beta.32",
"xterm-addon-canvas": "0.2.0-beta.15",
"xterm-addon-search": "0.10.0-beta.3",
"xterm-addon-serialize": "0.8.0-beta.3",
"xterm-addon-unicode11": "0.4.0-beta.3",
"xterm-addon-webgl": "0.13.0-beta.9",
"xterm-headless": "4.20.0-beta.20",
"xterm-addon-webgl": "0.13.0-beta.32",
"xterm-headless": "5.0.0-beta.5",
"yauzl": "^2.9.2",
"yazl": "^2.4.3"
},

View file

@ -11,9 +11,10 @@
"tas-client-umd": "0.1.6",
"vscode-oniguruma": "1.6.1",
"vscode-textmate": "7.0.1",
"xterm": "4.20.0-beta.20",
"xterm": "5.0.0-beta.32",
"xterm-addon-canvas": "0.2.0-beta.15",
"xterm-addon-search": "0.10.0-beta.3",
"xterm-addon-unicode11": "0.4.0-beta.3",
"xterm-addon-webgl": "0.13.0-beta.9"
"xterm-addon-webgl": "0.13.0-beta.32"
}
}

View file

@ -68,6 +68,11 @@ vscode-textmate@7.0.1:
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79"
integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw==
xterm-addon-canvas@0.2.0-beta.15:
version "0.2.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4"
integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw==
xterm-addon-search@0.10.0-beta.3:
version "0.10.0-beta.3"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a"
@ -78,12 +83,12 @@ xterm-addon-unicode11@0.4.0-beta.3:
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa"
integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q==
xterm-addon-webgl@0.13.0-beta.9:
version "0.13.0-beta.9"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.9.tgz#66a9ac142ae347d0548abbf4e66bb2f35f415adb"
integrity sha512-x1o1tpCqIsICvhcRsZs+BLcwUIdizYS2G4TIH0KBnUDiSN+oSqpVBQNG8qKg56xbK8WtpdbQ9dLB7JR2W5cX0g==
xterm-addon-webgl@0.13.0-beta.32:
version "0.13.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.32.tgz#ae7335f788ae611733e03f6ca38280ab7b86d212"
integrity sha512-xOudNzYXaRh9QZ+IigXM5EB3bM8l3/F8F35EpJRYvvsylVxiB6Km8X8l7+nxlWt+uYdnHZs0ka2rvtL8kOP/uw==
xterm@4.20.0-beta.20:
version "4.20.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.20.tgz#2979a31839f7b8ee3ffe4f063b40c02facdb0fed"
integrity sha512-ltDtTquH+33tXQPFSDqenbgz6LkvIob6l6Rac85L4aX5Ve7P3ubVLrq+lTFJGQn3iiwGqNmnE1t1EUuGhxsXcQ==
xterm@5.0.0-beta.32:
version "5.0.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0-beta.32.tgz#62bb9902429c0055fd2fd85c9eecfbf1756ed31c"
integrity sha512-OAM1GaBs/chK63Cr86XbVhfVCLLXLpNxxFrv3RK9xoyb9dwiY3gaMxK9jeGzTnrbGLWJb+k5nxaC0rx2YsHvUA==

View file

@ -788,6 +788,11 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
xterm-addon-canvas@0.2.0-beta.15:
version "0.2.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4"
integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw==
xterm-addon-search@0.10.0-beta.3:
version "0.10.0-beta.3"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a"
@ -803,20 +808,20 @@ xterm-addon-unicode11@0.4.0-beta.3:
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa"
integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q==
xterm-addon-webgl@0.13.0-beta.9:
version "0.13.0-beta.9"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.9.tgz#66a9ac142ae347d0548abbf4e66bb2f35f415adb"
integrity sha512-x1o1tpCqIsICvhcRsZs+BLcwUIdizYS2G4TIH0KBnUDiSN+oSqpVBQNG8qKg56xbK8WtpdbQ9dLB7JR2W5cX0g==
xterm-addon-webgl@0.13.0-beta.32:
version "0.13.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.32.tgz#ae7335f788ae611733e03f6ca38280ab7b86d212"
integrity sha512-xOudNzYXaRh9QZ+IigXM5EB3bM8l3/F8F35EpJRYvvsylVxiB6Km8X8l7+nxlWt+uYdnHZs0ka2rvtL8kOP/uw==
xterm-headless@4.20.0-beta.20:
version "4.20.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.20.0-beta.20.tgz#da2d8131b02d6f1e37f47cc17e578f2c2980fbb6"
integrity sha512-JK4jUIiUH7TdzvMrpfDnbGxTuC4s7byjqnMHR8+gIpY8qCFjz0xcMFSbp+ZshxGwVyziI4jtJqTHZjFToT2/kw==
xterm-headless@5.0.0-beta.5:
version "5.0.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.0.0-beta.5.tgz#e29b6c5081f31f887122b7263ba996b0c46b3c22"
integrity sha512-CMQ1+prBNF92oBMeZzc2rfTcmOaCGfwwSaoPYNTjyziZT6mZsEg7amajYkb0YAnqJ29MFm4kPGZbU78/dX4k2A==
xterm@4.20.0-beta.20:
version "4.20.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.20.tgz#2979a31839f7b8ee3ffe4f063b40c02facdb0fed"
integrity sha512-ltDtTquH+33tXQPFSDqenbgz6LkvIob6l6Rac85L4aX5Ve7P3ubVLrq+lTFJGQn3iiwGqNmnE1t1EUuGhxsXcQ==
xterm@5.0.0-beta.32:
version "5.0.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0-beta.32.tgz#62bb9902429c0055fd2fd85c9eecfbf1756ed31c"
integrity sha512-OAM1GaBs/chK63Cr86XbVhfVCLLXLpNxxFrv3RK9xoyb9dwiY3gaMxK9jeGzTnrbGLWJb+k5nxaC0rx2YsHvUA==
yallist@^4.0.0:
version "4.0.0"

View file

@ -11,7 +11,7 @@ Icon: @@NAME@@.xpm
Requires: @@DEPENDENCIES@@
AutoReq: 0
%global __provides_exclude_from ^%{_datadir}/@@NAME@@/.*\\.so.*$
%global __provides_exclude_from ^%{_datadir}/%{name}/.*\\.so.*$
%description
Visual Studio Code is a new choice of tool that combines the simplicity of a code editor with what developers need for the core edit-build-debug cycle. See https://code.visualstudio.com/docs/setup/linux for installation instructions and FAQ.
@ -21,25 +21,29 @@ Visual Studio Code is a new choice of tool that combines the simplicity of a cod
%define _build_id_links none
%install
mkdir -p %{buildroot}/usr/bin
mkdir -p %{buildroot}/usr/share/@@NAME@@
mkdir -p %{buildroot}/usr/share/applications
mkdir -p %{buildroot}/usr/share/pixmaps
mkdir -p %{buildroot}/usr/share/bash-completion/completions
mkdir -p %{buildroot}/usr/share/zsh/site-functions
mkdir -p %{buildroot}/usr/share/mime/packages
cp -r usr/share/@@NAME@@/* %{buildroot}/usr/share/@@NAME@@
cp -r usr/share/applications/@@NAME@@.desktop %{buildroot}/usr/share/applications
cp -r usr/share/applications/@@NAME@@-url-handler.desktop %{buildroot}/usr/share/applications
cp -r usr/share/mime/packages/@@NAME@@-workspace.xml %{buildroot}/usr/share/mime/packages/@@NAME@@-workspace.xml
cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}/usr/share/pixmaps
cp usr/share/bash-completion/completions/@@NAME@@ %{buildroot}/usr/share/bash-completion/completions/@@NAME@@
cp usr/share/zsh/site-functions/_@@NAME@@ %{buildroot}/usr/share/zsh/site-functions/_@@NAME@@
ln -s ../share/@@NAME@@/bin/@@NAME@@ %{buildroot}/usr/bin/@@NAME@@
# Destination directories
mkdir -p %{buildroot}%{_bindir}
mkdir -p %{buildroot}%{_datadir}/%{name}
mkdir -p %{buildroot}%{_datadir}/applications
mkdir -p %{buildroot}%{_datadir}/mime/packages
mkdir -p %{buildroot}%{_datadir}/pixmaps
mkdir -p %{buildroot}%{_datadir}/bash-completion/completions
mkdir -p %{buildroot}%{_datadir}/zsh/site-functions
# Application
cp -r usr/share/%{name}/* %{buildroot}%{_datadir}/%{name}
ln -s %{_datadir}/%{name}/bin/%{name} %{buildroot}%{_bindir}/%{name}
# Support files
cp -r usr/share/applications/%{name}.desktop %{buildroot}%{_datadir}/applications
cp -r usr/share/applications/%{name}-url-handler.desktop %{buildroot}%{_datadir}/applications
cp -r usr/share/mime/packages/%{name}-workspace.xml %{buildroot}%{_datadir}/mime/packages/%{name}-workspace.xml
cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}%{_datadir}/pixmaps
# Shell completions
cp usr/share/bash-completion/completions/%{name} %{buildroot}%{_datadir}/bash-completion/completions/%{name}
cp usr/share/zsh/site-functions/_%{name} %{buildroot}%{_datadir}/zsh/site-functions/_%{name}
%post
# Remove the legacy bin command if this is the stable build
if [ "@@NAME@@" = "code" ]; then
if [ "%{name}" = "code" ]; then
rm -f /usr/local/bin/code
fi
@ -54,21 +58,21 @@ fi
#fi
# Update mimetype database to pickup workspace mimetype
update-mime-database /usr/share/mime &> /dev/null || :
update-mime-database %{_datadir}/mime &> /dev/null || :
%postun
# Update mimetype database for removed workspace mimetype
update-mime-database /usr/share/mime &> /dev/null || :
update-mime-database %{_datadir}/mime &> /dev/null || :
%files
%defattr(-,root,root)
%attr(4755, root, root) /usr/share/@@NAME@@/chrome-sandbox
%attr(4755, root, root) %{_datadir}/%{name}/chrome-sandbox
/usr/bin/@@NAME@@
/usr/share/@@NAME@@/
/usr/share/applications/@@NAME@@.desktop
/usr/share/applications/@@NAME@@-url-handler.desktop
/usr/share/mime/packages/@@NAME@@-workspace.xml
/usr/share/pixmaps/@@ICON@@.png
/usr/share/bash-completion/completions/@@NAME@@
/usr/share/zsh/site-functions/_@@NAME@@
%{_bindir}/%{name}
%{_datadir}/%{name}/
%{_datadir}/applications/%{name}.desktop
%{_datadir}/applications/%{name}-url-handler.desktop
%{_datadir}/mime/packages/%{name}-workspace.xml
%{_datadir}/pixmaps/@@ICON@@.png
%{_datadir}/bash-completion/completions/%{name}
%{_datadir}/zsh/site-functions/_%{name}

View file

@ -8,6 +8,7 @@ const path = require('path');
const moduleNames = [
'xterm',
'xterm-addon-canvas',
'xterm-addon-search',
'xterm-addon-unicode11',
'xterm-addon-webgl'
@ -30,7 +31,17 @@ function getLatestModuleVersion(moduleName) {
if (err) {
reject(err);
}
const versions = JSON.parse(stdout);
let versions = JSON.parse(stdout);
// HACK: Some bad versions were published as v5 which cannot be unpublished, ignore these
if (moduleName === 'xterm-addon-canvas') {
versions = versions.filter(e => ![
'0.12.0',
'5.0.0-beta.1',
'5.0.0-beta.2',
'5.0.0-beta.3',
'5.0.0-beta.4',
].includes(e));
}
resolve(versions[versions.length - 1]);
});
});

View file

@ -136,6 +136,7 @@
'vscode-textmate': `${baseNodeModulesPath}/vscode-textmate/release/main.js`,
'vscode-oniguruma': `${baseNodeModulesPath}/vscode-oniguruma/release/main.js`,
'xterm': `${baseNodeModulesPath}/xterm/lib/xterm.js`,
'xterm-addon-canvas': `${baseNodeModulesPath}/xterm-addon-canvas/lib/xterm-addon-canvas.js`,
'xterm-addon-search': `${baseNodeModulesPath}/xterm-addon-search/lib/xterm-addon-search.js`,
'xterm-addon-unicode11': `${baseNodeModulesPath}/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
'xterm-addon-webgl': `${baseNodeModulesPath}/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
@ -150,7 +151,7 @@
// which has a fallback to using node.js `require`
// (node.js enabled renderers only)
if (!safeProcess.sandboxed) {
loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/;
loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-canvas$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/;
}
// Signal before require.config()

View file

@ -96,10 +96,10 @@ export class HighlightedLabel {
if (pos < highlight.start) {
const substring = this.text.substring(pos, highlight.start);
children.push(dom.$('span', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]));
pos = highlight.end;
pos = highlight.start;
}
const substring = this.text.substring(highlight.start, highlight.end);
const substring = this.text.substring(pos, highlight.end);
const element = dom.$('span.highlight', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]);
if (highlight.extraClasses) {

View file

@ -829,3 +829,79 @@ export class ArrayQueue<T> {
return result;
}
}
/**
* This class is faster than an iterator and array for lazy computed data.
*/
export class CallbackIterable<T> {
public static readonly empty = new CallbackIterable<never>(_callback => { });
constructor(
/**
* Calls the callback for every item.
* Stops when the callback returns false.
*/
public readonly iterate: (callback: (item: T) => boolean) => void
) {
}
forEach(handler: (item: T) => void) {
this.iterate(item => { handler(item); return true; });
}
toArray(): T[] {
const result: T[] = [];
this.iterate(item => { result.push(item); return true; });
return result;
}
filter(predicate: (item: T) => boolean): CallbackIterable<T> {
return new CallbackIterable(cb => this.iterate(item => predicate(item) ? cb(item) : true));
}
map<TResult>(mapFn: (item: T) => TResult): CallbackIterable<TResult> {
return new CallbackIterable<TResult>(cb => this.iterate(item => cb(mapFn(item))));
}
some(predicate: (item: T) => boolean): boolean {
let result = false;
this.iterate(item => { result = predicate(item); return !result; });
return result;
}
findFirst(predicate: (item: T) => boolean): T | undefined {
let result: T | undefined;
this.iterate(item => {
if (predicate(item)) {
result = item;
return false;
}
return true;
});
return result;
}
findLast(predicate: (item: T) => boolean): T | undefined {
let result: T | undefined;
this.iterate(item => {
if (predicate(item)) {
result = item;
}
return true;
});
return result;
}
findLastMaxBy(comparator: Comparator<T>): T | undefined {
let result: T | undefined;
let first = true;
this.iterate(item => {
if (first || CompareResult.isGreaterThan(comparator(item, result!))) {
first = false;
result = item;
}
return true;
});
return result;
}
}

View file

@ -94,11 +94,12 @@ export class Codicon implements CSSIcon {
public static readonly eyeUnwatch = new Codicon('eye-unwatch', { fontCharacter: '\\ea70' });
public static readonly eyeWatch = new Codicon('eye-watch', { fontCharacter: '\\ea70' });
public static readonly circleFilled = new Codicon('circle-filled', { fontCharacter: '\\ea71' });
public static readonly primitiveDot = new Codicon('primitive-dot', { fontCharacter: '\\ea71' });
public static readonly closeDirty = new Codicon('close-dirty', { fontCharacter: '\\ea71' });
public static readonly debugBreakpoint = new Codicon('debug-breakpoint', { fontCharacter: '\\ea71' });
public static readonly debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', { fontCharacter: '\\ea71' });
public static readonly debugHint = new Codicon('debug-hint', { fontCharacter: '\\ea71' });
public static readonly primitiveDot = new Codicon('primitive-dot', Codicon.circleFilled.definition);
public static readonly closeDirty = new Codicon('close-dirty', Codicon.circleFilled.definition);
public static readonly terminalDecorationSuccess = new Codicon('terminal-decoration-success', Codicon.circleFilled.definition);
public static readonly debugBreakpoint = new Codicon('debug-breakpoint', Codicon.circleFilled.definition);
public static readonly debugBreakpointDisabled = new Codicon('debug-breakpoint-disabled', Codicon.circleFilled.definition);
public static readonly debugHint = new Codicon('debug-hint', Codicon.circleFilled.definition);
public static readonly primitiveSquare = new Codicon('primitive-square', { fontCharacter: '\\ea72' });
public static readonly edit = new Codicon('edit', { fontCharacter: '\\ea73' });
public static readonly pencil = new Codicon('pencil', { fontCharacter: '\\ea73' });
@ -218,8 +219,10 @@ export class Codicon implements CSSIcon {
public static readonly chromeMaximize = new Codicon('chrome-maximize', { fontCharacter: '\\eab9' });
public static readonly chromeMinimize = new Codicon('chrome-minimize', { fontCharacter: '\\eaba' });
public static readonly chromeRestore = new Codicon('chrome-restore', { fontCharacter: '\\eabb' });
public static readonly circleOutline = new Codicon('circle-outline', { fontCharacter: '\\eabc' });
public static readonly debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', { fontCharacter: '\\eabc' });
public static readonly circle = new Codicon('circle', { fontCharacter: '\\eabc' });
public static readonly circleOutline = new Codicon('circle-outline', Codicon.circle.definition);
public static readonly terminalDecorationIncomplete = new Codicon('terminal-decoration-incomplete', Codicon.circle.definition);
public static readonly debugBreakpointUnverified = new Codicon('debug-breakpoint-unverified', Codicon.circle.definition);
public static readonly circleSlash = new Codicon('circle-slash', { fontCharacter: '\\eabd' });
public static readonly circuitBoard = new Codicon('circuit-board', { fontCharacter: '\\eabe' });
public static readonly clearAll = new Codicon('clear-all', { fontCharacter: '\\eabf' });
@ -430,6 +433,7 @@ export class Codicon implements CSSIcon {
public static readonly debugStackframeActive = new Codicon('debug-stackframe-active', { fontCharacter: '\\eb89' });
public static readonly circleSmallFilled = new Codicon('circle-small-filled', { fontCharacter: '\\eb8a' });
public static readonly debugStackframeDot = new Codicon('debug-stackframe-dot', Codicon.circleSmallFilled.definition);
public static readonly terminalDecorationMark = new Codicon('terminal-decoration-mark', Codicon.circleSmallFilled.definition);
public static readonly debugStackframe = new Codicon('debug-stackframe', { fontCharacter: '\\eb8b' });
public static readonly debugStackframeFocused = new Codicon('debug-stackframe-focused', { fontCharacter: '\\eb8b' });
public static readonly debugBreakpointUnsupported = new Codicon('debug-breakpoint-unsupported', { fontCharacter: '\\eb8c' });
@ -473,7 +477,8 @@ export class Codicon implements CSSIcon {
public static readonly pinnedDirty = new Codicon('pinned-dirty', { fontCharacter: '\\ebb2' });
public static readonly passFilled = new Codicon('pass-filled', { fontCharacter: '\\ebb3' });
public static readonly circleLargeFilled = new Codicon('circle-large-filled', { fontCharacter: '\\ebb4' });
public static readonly circleLargeOutline = new Codicon('circle-large-outline', { fontCharacter: '\\ebb5' });
public static readonly circleLarge = new Codicon('circle-large', { fontCharacter: '\\ebb5' });
public static readonly circleLargeOutline = new Codicon('circle-large-outline', Codicon.circleLarge.definition);
public static readonly combine = new Codicon('combine', { fontCharacter: '\\ebb6' });
public static readonly gather = new Codicon('gather', { fontCharacter: '\\ebb6' });
public static readonly table = new Codicon('table', { fontCharacter: '\\ebb7' });
@ -549,6 +554,7 @@ export class Codicon implements CSSIcon {
public static readonly indent = new Codicon('indent', { fontCharacter: '\\ebf9' });
public static readonly recordSmall = new Codicon('record-small', { fontCharacter: '\\ebfa' });
public static readonly errorSmall = new Codicon('error-small', { fontCharacter: '\\ebfb' });
public static readonly terminalDecorationError = new Codicon('terminal-decoration-error', Codicon.errorSmall.definition);
public static readonly arrowCircleDown = new Codicon('arrow-circle-down', { fontCharacter: '\\ebfc' });
public static readonly arrowCircleLeft = new Codicon('arrow-circle-left', { fontCharacter: '\\ebfd' });
public static readonly arrowCircleRight = new Codicon('arrow-circle-right', { fontCharacter: '\\ebfe' });

View file

@ -136,6 +136,12 @@ export interface WebSocketCloseEvent {
export type SocketCloseEvent = NodeSocketCloseEvent | WebSocketCloseEvent | undefined;
export interface SocketTimeoutEvent {
readonly unacknowledgedMsgCount: number;
readonly timeSinceOldestUnacknowledgedMsg: number;
readonly timeSinceLastReceivedSomeData: number;
}
export interface ISocket extends IDisposable {
onData(listener: (e: VSBuffer) => void): IDisposable;
onClose(listener: (e: SocketCloseEvent) => void): IDisposable;
@ -667,6 +673,16 @@ class Queue<T> {
this._last = null;
}
public length(): number {
let result = 0;
let current = this._first;
while (current) {
current = current.next;
result++;
}
return result;
}
public peek(): T | null {
if (!this._first) {
return null;
@ -800,8 +816,8 @@ export class PersistentProtocol implements IMessagePassingProtocol {
private readonly _onSocketClose = new BufferedEmitter<SocketCloseEvent>();
readonly onSocketClose: Event<SocketCloseEvent> = this._onSocketClose.event;
private readonly _onSocketTimeout = new BufferedEmitter<void>();
readonly onSocketTimeout: Event<void> = this._onSocketTimeout.event;
private readonly _onSocketTimeout = new BufferedEmitter<SocketTimeoutEvent>();
readonly onSocketTimeout: Event<SocketTimeoutEvent> = this._onSocketTimeout.event;
public get unacknowledgedCount(): number {
return this._outgoingMsgId - this._outgoingAckId;
@ -1081,7 +1097,11 @@ export class PersistentProtocol implements IMessagePassingProtocol {
if (!this._loadEstimator.hasHighLoad()) {
// Trash the socket
this._lastSocketTimeoutTime = Date.now();
this._onSocketTimeout.fire(undefined);
this._onSocketTimeout.fire({
unacknowledgedMsgCount: this._outgoingUnackMsg.length(),
timeSinceOldestUnacknowledgedMsg,
timeSinceLastReceivedSomeData
});
return;
}
}

View file

@ -1021,7 +1021,7 @@ export class Minimap extends ViewPart implements IMinimapModel {
} else {
visibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.viewModel.getLineMaxColumn(endLineNumber));
}
const decorations = this._context.viewModel.getDecorationsInViewport(visibleRange);
const decorations = this._context.viewModel.getDecorationsInViewport(visibleRange, true);
if (this._samplingState) {
const result: ViewModelDecoration[] = [];

View file

@ -945,7 +945,7 @@ export interface ITextModel {
* @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
* @return An array with the decorations
*/
getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];
getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[];
/**
* Gets all the decorations as an array.

View file

@ -3,20 +3,20 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CallbackIterable, compareBy } from 'vs/base/common/arrays';
import { Emitter } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable } from 'vs/base/common/lifecycle';
import { LineTokens } from 'vs/editor/common/tokens/lineTokens';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { BracketPairsTree } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree';
import { BracketInfo, BracketPairInfo, BracketPairWithMinIndentationInfo, IBracketPairsTextModelPart, IFoundBracket } from 'vs/editor/common/textModelBracketPairs';
import { TextModel } from 'vs/editor/common/model/textModel';
import { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { ignoreBracketsInToken } from 'vs/editor/common/languages/supports';
import { RichEditBrackets, BracketsUtils, RichEditBracket } from 'vs/editor/common/languages/supports/richEditBrackets';
import { compareBy, findLast, findLastMaxBy } from 'vs/base/common/arrays';
import { LanguageBracketsConfiguration } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';
import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/languages/supports/richEditBrackets';
import { BracketPairsTree } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree';
import { TextModel } from 'vs/editor/common/model/textModel';
import { BracketInfo, BracketPairInfo, BracketPairWithMinIndentationInfo, IBracketPairsTextModelPart, IFoundBracket } from 'vs/editor/common/textModelBracketPairs';
import { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';
import { LineTokens } from 'vs/editor/common/tokens/lineTokens';
export class BracketPairsTextModelPart extends Disposable implements IBracketPairsTextModelPart {
private readonly bracketPairsTree = this._register(new MutableDisposable<IReference<BracketPairsTree>>());
@ -102,22 +102,22 @@ export class BracketPairsTextModelPart extends Disposable implements IBracketPai
* Returns all bracket pairs that intersect the given range.
* The result is sorted by the start position.
*/
public getBracketPairsInRange(range: Range): BracketPairInfo[] {
public getBracketPairsInRange(range: Range): CallbackIterable<BracketPairInfo> {
this.bracketsRequested = true;
this.updateBracketPairsTree();
return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, false) || [];
return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, false) || CallbackIterable.empty;
}
public getBracketPairsInRangeWithMinIndentation(range: Range): BracketPairWithMinIndentationInfo[] {
public getBracketPairsInRangeWithMinIndentation(range: Range): CallbackIterable<BracketPairWithMinIndentationInfo> {
this.bracketsRequested = true;
this.updateBracketPairsTree();
return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, true) || [];
return this.bracketPairsTree.value?.object.getBracketPairsInRange(range, true) || CallbackIterable.empty;
}
public getBracketsInRange(range: Range): BracketInfo[] {
public getBracketsInRange(range: Range): CallbackIterable<BracketInfo> {
this.bracketsRequested = true;
this.updateBracketPairsTree();
return this.bracketPairsTree.value?.object.getBracketsInRange(range) || [];
return this.bracketPairsTree.value?.object.getBracketsInRange(range) || CallbackIterable.empty;
}
public findMatchingBracketUp(_bracket: string, _position: IPosition, maxDuration?: number): Range | null {
@ -133,7 +133,7 @@ export class BracketPairsTextModelPart extends Disposable implements IBracketPai
return null;
}
const bracketPair = findLast(this.getBracketPairsInRange(Range.fromPositions(_position, _position)) || [], (b) =>
const bracketPair = this.getBracketPairsInRange(Range.fromPositions(_position, _position)).findLast((b) =>
closingBracketInfo.closes(b.openingBracketInfo)
);
@ -163,7 +163,7 @@ export class BracketPairsTextModelPart extends Disposable implements IBracketPai
public matchBracket(position: IPosition, maxDuration?: number): [Range, Range] | null {
if (this.canBuildAST) {
const bracketPair = findLastMaxBy(
const bracketPair =
this.getBracketPairsInRange(
Range.fromPositions(position, position)
).filter(
@ -171,15 +171,15 @@ export class BracketPairsTextModelPart extends Disposable implements IBracketPai
item.closingBracketRange !== undefined &&
(item.openingBracketRange.containsPosition(position) ||
item.closingBracketRange.containsPosition(position))
),
compareBy(
(item) =>
item.openingBracketRange.containsPosition(position)
? item.openingBracketRange
: item.closingBracketRange,
Range.compareRangesUsingStarts
)
);
).findLastMaxBy(
compareBy(
(item) =>
item.openingBracketRange.containsPosition(position)
? item.openingBracketRange
: item.closingBracketRange,
Range.compareRangesUsingStarts
)
);
if (bracketPair) {
return [bracketPair.openingBracketRange, bracketPair.closingBracketRange!];
}
@ -674,10 +674,10 @@ export class BracketPairsTextModelPart extends Disposable implements IBracketPai
if (this.canBuildAST) {
const range = Range.fromPositions(position);
const bracketPair = findLast(
this.getBracketPairsInRange(Range.fromPositions(position, position)),
(item) => item.closingBracketRange !== undefined && item.range.strictContainsRange(range)
);
const bracketPair =
this.getBracketPairsInRange(Range.fromPositions(position, position)).findLast(
(item) => item.closingBracketRange !== undefined && item.range.strictContainsRange(range)
);
if (bracketPair) {
return [bracketPair.openingBracketRange, bracketPair.closingBracketRange!];
}

View file

@ -20,6 +20,7 @@ import { DenseKeyProvider } from './smallImmutableSet';
import { FastTokenizer, TextBufferTokenizer } from './tokenizer';
import { BackgroundTokenizationState } from 'vs/editor/common/tokenizationTextModelPart';
import { Position } from 'vs/editor/common/core/position';
import { CallbackIterable } from 'vs/base/common/arrays';
export class BracketPairsTree extends Disposable {
private readonly didChangeEmitter = new Emitter<void>();
@ -125,26 +126,24 @@ export class BracketPairsTree extends Disposable {
return result;
}
public getBracketsInRange(range: Range): BracketInfo[] {
public getBracketsInRange(range: Range): CallbackIterable<BracketInfo> {
const startOffset = toLength(range.startLineNumber - 1, range.startColumn - 1);
const endOffset = toLength(range.endLineNumber - 1, range.endColumn - 1);
const result = new Array<BracketInfo>();
const node = this.initialAstWithoutTokens || this.astWithTokens!;
collectBrackets(node, lengthZero, node.length, startOffset, endOffset, result, 0, new Map());
return result;
return new CallbackIterable(cb => {
const node = this.initialAstWithoutTokens || this.astWithTokens!;
collectBrackets(node, lengthZero, node.length, startOffset, endOffset, cb, 0, new Map());
});
}
public getBracketPairsInRange(range: Range, includeMinIndentation: boolean): BracketPairWithMinIndentationInfo[] {
const result = new Array<BracketPairWithMinIndentationInfo>();
public getBracketPairsInRange(range: Range, includeMinIndentation: boolean): CallbackIterable<BracketPairWithMinIndentationInfo> {
const startLength = positionToLength(range.getStartPosition());
const endLength = positionToLength(range.getEndPosition());
const node = this.initialAstWithoutTokens || this.astWithTokens!;
const context = new CollectBracketPairsContext(result, includeMinIndentation, this.textModel);
collectBracketPairs(node, lengthZero, node.length, startLength, endLength, context, 0, new Map());
return result;
return new CallbackIterable(cb => {
const node = this.initialAstWithoutTokens || this.astWithTokens!;
const context = new CollectBracketPairsContext(cb, includeMinIndentation, this.textModel);
collectBracketPairs(node, lengthZero, node.length, startLength, endLength, context, 0, new Map());
});
}
public getFirstBracketAfter(position: Position): IFoundBracket | null {
@ -219,108 +218,105 @@ function collectBrackets(
nodeOffsetEnd: Length,
startOffset: Length,
endOffset: Length,
result: BracketInfo[],
push: (item: BracketInfo) => boolean,
level: number,
levelPerBracketType: Map<string, number>
): void {
): boolean {
if (level > 200) {
return;
return true;
}
if (node.kind === AstNodeKind.List) {
for (const child of node.children) {
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
collectBrackets(
child,
nodeOffsetStart,
nodeOffsetEnd,
startOffset,
endOffset,
result,
level,
levelPerBracketType
);
}
nodeOffsetStart = nodeOffsetEnd;
}
} else if (node.kind === AstNodeKind.Pair) {
let levelPerBracket = 0;
if (levelPerBracketType) {
let existing = levelPerBracketType.get(node.openingBracket.text);
if (existing === undefined) {
existing = 0;
}
levelPerBracket = existing;
existing++;
levelPerBracketType.set(node.openingBracket.text, existing);
}
whileLoop:
while (true) {
switch (node.kind) {
case AstNodeKind.List: {
const childCount = node.childrenLength;
for (let i = 0; i < childCount; i++) {
const child = node.getChild(i);
if (!child) {
continue;
}
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
const childEndsAfterEnd = lengthGreaterThanEqual(nodeOffsetEnd, endOffset);
if (childEndsAfterEnd) {
// No child after this child in the requested window, don't recurse
node = child;
continue whileLoop;
}
// Don't use node.children here to improve performance
{
const child = node.openingBracket;
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
const shouldContinue = collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, push, level, levelPerBracketType);
if (!shouldContinue) {
return false;
}
}
nodeOffsetStart = nodeOffsetEnd;
}
return true;
}
case AstNodeKind.Pair: {
let levelPerBracket = 0;
if (levelPerBracketType) {
let existing = levelPerBracketType.get(node.openingBracket.text);
if (existing === undefined) {
existing = 0;
}
levelPerBracket = existing;
existing++;
levelPerBracketType.set(node.openingBracket.text, existing);
}
const childCount = node.childrenLength;
for (let i = 0; i < childCount; i++) {
const child = node.getChild(i);
if (!child) {
continue;
}
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
const childEndsAfterEnd = lengthGreaterThanEqual(nodeOffsetEnd, endOffset);
if (childEndsAfterEnd) {
// No child after this child in the requested window, don't recurse
node = child;
level++;
continue whileLoop;
}
const shouldContinue = collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, push, level + 1, levelPerBracketType);
if (!shouldContinue) {
return false;
}
}
nodeOffsetStart = nodeOffsetEnd;
}
levelPerBracketType?.set(node.openingBracket.text, levelPerBracket);
return true;
}
case AstNodeKind.UnexpectedClosingBracket: {
const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
result.push(
new BracketInfo(range, level, levelPerBracket, !node.closingBracket)
);
return push(new BracketInfo(range, level - 1, 0, true));
}
nodeOffsetStart = nodeOffsetEnd;
}
if (node.child) {
const child = node.child;
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
collectBrackets(
child,
nodeOffsetStart,
nodeOffsetEnd,
startOffset,
endOffset,
result,
level + 1,
levelPerBracketType
);
}
nodeOffsetStart = nodeOffsetEnd;
}
if (node.closingBracket) {
const child = node.closingBracket;
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
case AstNodeKind.Bracket: {
const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
result.push(new BracketInfo(range, level, levelPerBracket, false));
return push(new BracketInfo(range, level - 1, 0, false));
}
nodeOffsetStart = nodeOffsetEnd;
case AstNodeKind.Text:
return true;
}
levelPerBracketType?.set(node.openingBracket.text, levelPerBracket);
} else if (node.kind === AstNodeKind.UnexpectedClosingBracket) {
const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
result.push(new BracketInfo(range, level - 1, 0, true));
} else if (node.kind === AstNodeKind.Bracket) {
const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
result.push(new BracketInfo(range, level - 1, 0, false));
}
}
class CollectBracketPairsContext {
constructor(
public readonly result: BracketPairWithMinIndentationInfo[],
public readonly push: (item: BracketPairWithMinIndentationInfo) => boolean,
public readonly includeMinIndentation: boolean,
public readonly textModel: ITextModel,
) {
@ -336,11 +332,13 @@ function collectBracketPairs(
context: CollectBracketPairsContext,
level: number,
levelPerBracketType: Map<string, number>
) {
): boolean {
if (level > 200) {
return;
return true;
}
let shouldContinue = true;
if (node.kind === AstNodeKind.Pair) {
let levelPerBracket = 0;
if (levelPerBracketType) {
@ -362,7 +360,7 @@ function collectBracketPairs(
);
}
context.result.push(
shouldContinue = context.push(
new BracketPairWithMinIndentationInfo(
lengthsToRange(nodeOffsetStart, nodeOffsetEnd),
lengthsToRange(nodeOffsetStart, openingBracketEnd),
@ -380,14 +378,14 @@ function collectBracketPairs(
);
nodeOffsetStart = openingBracketEnd;
if (node.child) {
if (shouldContinue && node.child) {
const child = node.child;
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
if (
lengthLessThanEqual(nodeOffsetStart, endOffset) &&
lengthGreaterThanEqual(nodeOffsetEnd, startOffset)
) {
collectBracketPairs(
shouldContinue = collectBracketPairs(
child,
nodeOffsetStart,
nodeOffsetEnd,
@ -397,6 +395,9 @@ function collectBracketPairs(
level + 1,
levelPerBracketType
);
if (!shouldContinue) {
return false;
}
}
}
@ -411,7 +412,7 @@ function collectBracketPairs(
lengthLessThanEqual(childOffset, endOffset) &&
lengthLessThanEqual(startOffset, curOffset)
) {
collectBracketPairs(
shouldContinue = collectBracketPairs(
child,
childOffset,
curOffset,
@ -421,8 +422,12 @@ function collectBracketPairs(
level,
levelPerBracketType
);
if (!shouldContinue) {
return false;
}
}
}
}
return shouldContinue;
}

View file

@ -42,7 +42,11 @@ export class ColorizedBracketPairsDecorationProvider extends Disposable implemen
//#endregion
getDecorationsInRange(range: Range, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[] {
getDecorationsInRange(range: Range, ownerId?: number, filterOutValidation?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[] {
if (onlyMinimapDecorations) {
// Bracket pair colorization decorations are not rendered in the minimap
return [];
}
if (ownerId === undefined) {
return [];
}
@ -50,22 +54,20 @@ export class ColorizedBracketPairsDecorationProvider extends Disposable implemen
return [];
}
const result = new Array<IModelDecoration>();
const bracketsInRange = this.textModel.bracketPairs.getBracketsInRange(range);
for (const bracket of bracketsInRange) {
result.push({
id: `bracket${bracket.range.toString()}-${bracket.nestingLevel}`,
options: {
description: 'BracketPairColorization',
inlineClassName: this.colorProvider.getInlineClassName(
bracket,
this.colorizationOptions.independentColorPoolPerBracketType
),
},
ownerId: 0,
range: bracket.range,
});
}
const result = this.textModel.bracketPairs.getBracketsInRange(range).map<IModelDecoration>(bracket =>
({
id: `bracket${bracket.range.toString()}-${bracket.nestingLevel}`,
options: {
description: 'BracketPairColorization',
inlineClassName: this.colorProvider.getInlineClassName(
bracket,
this.colorizationOptions.independentColorPoolPerBracketType
),
},
ownerId: 0,
range: bracket.range,
})).toArray();
return result;
}

View file

@ -23,7 +23,7 @@ export interface DecorationProvider {
* @param ownerId If set, it will ignore decorations belonging to other owners.
* @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
*/
getAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];
getAllDecorations(ownerId?: number, filterOutValidation?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[];
onDidChange: Event<void>;
}

View file

@ -292,7 +292,7 @@ export class GuidesTextModelPart extends TextModelPart implements IGuidesTextMod
endLineNumber,
this.textModel.getLineMaxColumn(endLineNumber)
)
);
).toArray();
let activeBracketPairRange: Range | undefined = undefined;
if (activePosition && bracketPairs.length > 0) {
@ -303,7 +303,7 @@ export class GuidesTextModelPart extends TextModelPart implements IGuidesTextMod
? bracketPairs
: this.textModel.bracketPairs.getBracketPairsInRange(
Range.fromPositions(activePosition)
)
).toArray()
).filter((bp) => Range.strictContainsPosition(bp.range, activePosition));
activeBracketPairRange = findLast(

View file

@ -1714,11 +1714,11 @@ export class TextModel extends Disposable implements model.ITextModel, IDecorati
return decorations;
}
public getDecorationsInRange(range: IRange, ownerId: number = 0, filterOutValidation: boolean = false): model.IModelDecoration[] {
public getDecorationsInRange(range: IRange, ownerId: number = 0, filterOutValidation: boolean = false, onlyMinimapDecorations: boolean = false): model.IModelDecoration[] {
const validatedRange = this.validateRange(range);
const decorations = this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation);
pushMany(decorations, this._decorationProvider.getDecorationsInRange(validatedRange, ownerId, filterOutValidation));
pushMany(decorations, this._decorationProvider.getDecorationsInRange(validatedRange, ownerId, filterOutValidation, onlyMinimapDecorations));
return decorations;
}

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CallbackIterable } from 'vs/base/common/arrays';
import { Event } from 'vs/base/common/event';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
@ -19,15 +20,15 @@ export interface IBracketPairsTextModelPart {
* Gets all bracket pairs that intersect the given position.
* The result is sorted by the start position.
*/
getBracketPairsInRange(range: IRange): BracketPairInfo[];
getBracketPairsInRange(range: IRange): CallbackIterable<BracketPairInfo>;
/**
* Gets all bracket pairs that intersect the given position.
* The result is sorted by the start position.
*/
getBracketPairsInRangeWithMinIndentation(range: IRange): BracketPairWithMinIndentationInfo[];
getBracketPairsInRangeWithMinIndentation(range: IRange): CallbackIterable<BracketPairWithMinIndentationInfo>;
getBracketsInRange(range: IRange): BracketInfo[];
getBracketsInRange(range: IRange): CallbackIterable<BracketInfo>;
/**
* Find the matching bracket of `request` up, counting brackets.

View file

@ -40,7 +40,7 @@ export interface IViewModel extends ICursorSimpleModel {
onCompositionStart(): void;
onCompositionEnd(): void;
getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];
getDecorationsInViewport(visibleRange: Range, onlyMinimapDecorations?: boolean): ViewModelDecoration[];
getViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;
getViewLineRenderingData(lineNumber: number): ViewLineRenderingData;
getViewLineData(lineNumber: number): ViewLineData;

View file

@ -36,6 +36,7 @@ export class ViewModelDecorations implements IDisposable {
private _cachedModelDecorationsResolver: IDecorationsViewportData | null;
private _cachedModelDecorationsResolverViewRange: Range | null;
private _cachedOnlyMinimapDecorations: boolean | null = null;
constructor(editorId: number, model: ITextModel, configuration: IEditorConfiguration, linesCollection: IViewModelLines, coordinatesConverter: ICoordinatesConverter) {
this.editorId = editorId;
@ -96,23 +97,25 @@ export class ViewModelDecorations implements IDisposable {
return r;
}
public getDecorationsViewportData(viewRange: Range): IDecorationsViewportData {
public getDecorationsViewportData(viewRange: Range, onlyMinimapDecorations: boolean = false): IDecorationsViewportData {
let cacheIsValid = (this._cachedModelDecorationsResolver !== null);
cacheIsValid = cacheIsValid && (viewRange.equalsRange(this._cachedModelDecorationsResolverViewRange));
cacheIsValid = cacheIsValid && (this._cachedOnlyMinimapDecorations === onlyMinimapDecorations);
if (!cacheIsValid) {
this._cachedModelDecorationsResolver = this._getDecorationsInRange(viewRange);
this._cachedModelDecorationsResolver = this._getDecorationsInRange(viewRange, onlyMinimapDecorations);
this._cachedModelDecorationsResolverViewRange = viewRange;
this._cachedOnlyMinimapDecorations = onlyMinimapDecorations;
}
return this._cachedModelDecorationsResolver!;
}
public getInlineDecorationsOnLine(lineNumber: number): InlineDecoration[] {
public getInlineDecorationsOnLine(lineNumber: number, onlyMinimapDecorations: boolean = false): InlineDecoration[] {
const range = new Range(lineNumber, this._linesCollection.getViewLineMinColumn(lineNumber), lineNumber, this._linesCollection.getViewLineMaxColumn(lineNumber));
return this._getDecorationsInRange(range).inlineDecorations[0];
return this._getDecorationsInRange(range, onlyMinimapDecorations).inlineDecorations[0];
}
private _getDecorationsInRange(viewRange: Range): IDecorationsViewportData {
const modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, filterValidationDecorations(this.configuration.options));
private _getDecorationsInRange(viewRange: Range, onlyMinimapDecorations: boolean): IDecorationsViewportData {
const modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, filterValidationDecorations(this.configuration.options), onlyMinimapDecorations);
const startLineNumber = viewRange.startLineNumber;
const endLineNumber = viewRange.endLineNumber;

View file

@ -675,8 +675,8 @@ export class ViewModel extends Disposable implements IViewModel {
return result + 2;
}
public getDecorationsInViewport(visibleRange: Range): ViewModelDecoration[] {
return this._decorations.getDecorationsViewportData(visibleRange).decorations;
public getDecorationsInViewport(visibleRange: Range, onlyMinimapDecorations: boolean = false): ViewModelDecoration[] {
return this._decorations.getDecorationsViewportData(visibleRange, onlyMinimapDecorations).decorations;
}
public getInjectedTextAt(viewPosition: Position): InjectedText | null {

View file

@ -45,7 +45,7 @@ export interface IViewModelLines extends IDisposable {
getViewLineData(viewLineNumber: number): ViewLineData;
getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): Array<ViewLineData | null>;
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[];
getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, onlyMinimapDecorations: boolean): IModelDecoration[];
getInjectedTextAt(viewPosition: Position): InjectedText | null;
@ -888,14 +888,14 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines {
return this.modelLineProjections[lineIndex].getViewLineNumberOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1));
}
public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[] {
public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, onlyMinimapDecorations: boolean): IModelDecoration[] {
const modelStart = this.convertViewPositionToModelPosition(range.startLineNumber, range.startColumn);
const modelEnd = this.convertViewPositionToModelPosition(range.endLineNumber, range.endColumn);
if (modelEnd.lineNumber - modelStart.lineNumber <= range.endLineNumber - range.startLineNumber) {
// most likely there are no hidden lines => fast path
// fetch decorations from column 1 to cover the case of wrapped lines that have whole line decorations at column 1
return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation);
return this.model.getDecorationsInRange(new Range(modelStart.lineNumber, 1, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation, onlyMinimapDecorations);
}
let result: IModelDecoration[] = [];
@ -914,14 +914,14 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines {
// hit invisible line => flush request
if (reqStart !== null) {
const maxLineColumn = this.model.getLineMaxColumn(modelLineIndex);
result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation));
result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelLineIndex, maxLineColumn), ownerId, filterOutValidation, onlyMinimapDecorations));
reqStart = null;
}
}
}
if (reqStart !== null) {
result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation));
result = result.concat(this.model.getDecorationsInRange(new Range(reqStart.lineNumber, reqStart.column, modelEnd.lineNumber, modelEnd.column), ownerId, filterOutValidation, onlyMinimapDecorations));
reqStart = null;
}
@ -1221,8 +1221,8 @@ export class ViewModelLinesFromModelAsIs implements IViewModelLines {
return result;
}
public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean): IModelDecoration[] {
return this.model.getDecorationsInRange(range, ownerId, filterOutValidation);
public getDecorationsInRange(range: Range, ownerId: number, filterOutValidation: boolean, onlyMinimapDecorations: boolean): IModelDecoration[] {
return this.model.getDecorationsInRange(range, ownerId, filterOutValidation, onlyMinimapDecorations);
}
normalizePosition(position: Position, affinity: PositionAffinity): Position {

View file

@ -117,7 +117,6 @@ class CodeMenuRenderer implements IListRenderer<ICodeActionMenuItem, ICodeAction
element.isEnabled = element.action.enabled;
if (element.action instanceof CodeActionAction) {
// Check documentation type
@ -239,6 +238,15 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
}
}
private _onListClick(e: IListMouseEvent<ICodeActionMenuItem>): void {
if (e.element) {
if (!e.element.isEnabled) {
this.currSelectedItem = undefined;
this.codeActionList.value?.setFocus([]);
}
}
}
private renderCodeActionMenuList(element: HTMLElement, inputArray: IAction[]): IDisposable {
const renderDisposables = new DisposableStore();
const renderMenu = document.createElement('div');
@ -275,12 +283,12 @@ export class CodeActionMenu extends Disposable implements IEditorContribution {
}, [this.listRenderer], { keyboardSupport: false }
);
renderDisposables.add(this.codeActionList.value.onMouseClick(e => this._onListClick(e)));
renderDisposables.add(this.codeActionList.value.onMouseOver(e => this._onListHover(e)));
renderDisposables.add(this.codeActionList.value.onDidChangeFocus(e => this.codeActionList.value?.domFocus()));
renderDisposables.add(this.codeActionList.value.onDidChangeSelection(e => this._onListSelection(e)));
renderDisposables.add(this._editor.onDidLayoutChange(e => this.hideCodeActionWidget()));
// Populating the list widget and tracking enabled options.
inputArray.forEach((item, index) => {

View file

@ -11,7 +11,7 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/browser/outlineModel';
import { CancellationToken, CancellationTokenSource, } from 'vs/base/common/cancellation';
import * as dom from 'vs/base/browser/dom';
import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';
import { EditorLayoutInfo, EditorOption, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { SymbolKind } from 'vs/editor/common/languages';
@ -68,6 +68,10 @@ class StickyScrollController extends Disposable implements IEditorContribution {
this._sessionStore.add(this._editor.onDidLayoutChange(() => this._onDidResize()));
this._sessionStore.add(this._editor.onDidChangeModelContent(() => this._updateSoon.schedule()));
this._sessionStore.add(this._languageFeaturesService.documentSymbolProvider.onDidChange(() => this._update(true)));
const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers);
if (lineNumberOption.renderType === RenderLineNumbersType.Relative) {
this._sessionStore.add(this._editor.onDidChangeCursorPosition(() => this._update(false)));
}
this._update(true);
}
}
@ -178,8 +182,7 @@ class StickyScrollController extends Disposable implements IEditorContribution {
});
let previous: number[] = [];
for (const [index, arr] of this._ranges.entries()) {
const [start, end, _depth] = arr;
if (previous[0] === start && previous[1] === end) {
if (previous[0] === arr[0]) {
this._ranges.splice(index, 1);
} else {
previous = arr;
@ -202,9 +205,8 @@ class StickyScrollController extends Disposable implements IEditorContribution {
const scrollTop = this._editor.getScrollTop();
this.stickyScrollWidget.emptyRootNode();
const beginningLinesConsidered: Set<number> = new Set<number>();
for (const [index, arr] of this._ranges.entries()) {
for (const arr of this._ranges) {
const [start, end, depth] = arr;
if (end - start > 0) {
const topOfElementAtDepth = (depth - 1) * lineHeight;
@ -214,18 +216,12 @@ class StickyScrollController extends Disposable implements IEditorContribution {
const topOfEndLine = this._editor.getTopForLineNumber(end) - scrollTop;
const bottomOfEndLine = this._editor.getBottomForLineNumber(end) - scrollTop;
if (!beginningLinesConsidered.has(start)) {
if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) {
beginningLinesConsidered.add(start);
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth));
break;
}
else if (bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < bottomOfEndLine - 1) {
beginningLinesConsidered.add(start);
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, 0, 0));
}
} else {
this._ranges.splice(index, 1);
if (topOfElementAtDepth >= topOfEndLine - 1 && topOfElementAtDepth < bottomOfEndLine - 2) {
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, -1, bottomOfEndLine - bottomOfElementAtDepth));
break;
}
else if (bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth < bottomOfEndLine - 1) {
this.stickyScrollWidget.pushCodeLine(new StickyScrollCodeLine(start, depth, this._editor, 0, 0));
}
}
}
@ -310,7 +306,12 @@ class StickyScrollCodeLine extends Disposable {
}
const innerLineNumberHTML = document.createElement('span');
innerLineNumberHTML.innerText = this._lineNumber.toString();
const lineNumberOption = this._editor.getOption(EditorOption.lineNumbers);
if (lineNumberOption.renderType === RenderLineNumbersType.On || lineNumberOption.renderType === RenderLineNumbersType.Interval && this._lineNumber % 10 === 0) {
innerLineNumberHTML.innerText = this._lineNumber.toString();
} else if (lineNumberOption.renderType === RenderLineNumbersType.Relative) {
innerLineNumberHTML.innerText = Math.abs(this._lineNumber - this._editor.getPosition().lineNumber).toString();
}
innerLineNumberHTML.className = 'sticky-line-number';
innerLineNumberHTML.style.lineHeight = `${lineHeight}px`;
innerLineNumberHTML.style.width = `${layoutInfo.lineNumbersWidth}px`;

View file

@ -36,7 +36,8 @@ suite('Bracket Pair Colorizer - getBracketPairsInRange', () => {
assert.deepStrictEqual(
model.bracketPairs
.getBracketPairsInRange(doc.range(1, 2))
.map(bracketPairToJSON),
.map(bracketPairToJSON)
.toArray(),
[
{
level: 0,
@ -68,7 +69,8 @@ suite('Bracket Pair Colorizer - getBracketPairsInRange', () => {
assert.deepStrictEqual(
model.bracketPairs
.getBracketPairsInRange(doc.range(1, 2))
.map(bracketPairToJSON),
.map(bracketPairToJSON)
.toArray(),
[
{
level: 0,
@ -94,7 +96,8 @@ suite('Bracket Pair Colorizer - getBracketPairsInRange', () => {
assert.deepStrictEqual(
model.bracketPairs
.getBracketPairsInRange(doc.range(1, 2))
.map(bracketPairToJSON),
.map(bracketPairToJSON)
.toArray(),
[]
);
});
@ -107,7 +110,8 @@ suite('Bracket Pair Colorizer - getBracketPairsInRange', () => {
assert.deepStrictEqual(
model.bracketPairs
.getBracketPairsInRange(doc.range(1, 2))
.map(bracketPairToJSON),
.map(bracketPairToJSON)
.toArray(),
[
{
level: 0,

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

@ -2010,7 +2010,7 @@ declare namespace monaco.editor {
* @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).
* @return An array with the decorations
*/
getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];
getDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean, onlyMinimapDecorations?: boolean): IModelDecoration[];
/**
* Gets all the decorations as an array.
* @param ownerId If set, it will ignore decorations belonging to other owners.

View file

@ -64,6 +64,7 @@ export interface IProgressNotificationOptions extends IProgressOptions {
readonly secondaryActions?: readonly IAction[];
readonly delay?: number;
readonly silent?: boolean;
readonly type?: 'syncing' | 'loading';
}
export interface IProgressDialogOptions extends IProgressOptions {

View file

@ -595,9 +595,9 @@ export abstract class PersistentConnection extends Disposable {
}
this._beginReconnecting();
}));
this._register(protocol.onSocketTimeout(() => {
this._register(protocol.onSocketTimeout((e) => {
const logPrefix = commonLogPrefix(this._connectionType, this.reconnectionToken, true);
this._options.logService.info(`${logPrefix} received socket timeout event.`);
this._options.logService.info(`${logPrefix} received socket timeout event (unacknowledgedMsgCount: ${e.unacknowledgedMsgCount}, timeSinceOldestUnacknowledgedMsg: ${e.timeSinceOldestUnacknowledgedMsg}, timeSinceLastReceivedSomeData: ${e.timeSinceLastReceivedSomeData}).`);
this._beginReconnecting();
}));

View file

@ -112,7 +112,8 @@ export const enum TerminalSettingId {
ShellIntegrationDecorationIcon = 'terminal.integrated.shellIntegration.decorationIcon',
ShellIntegrationDecorationIconError = 'terminal.integrated.shellIntegration.decorationIconError',
ShellIntegrationDecorationIconSuccess = 'terminal.integrated.shellIntegration.decorationIconSuccess',
ShellIntegrationCommandHistory = 'terminal.integrated.shellIntegration.history'
ShellIntegrationCommandHistory = 'terminal.integrated.shellIntegration.history',
SmoothScrolling = 'terminal.integrated.smoothScrolling'
}
export const enum TerminalLogConstants {
@ -167,14 +168,20 @@ export interface IPtyHostAttachTarget {
icon: TerminalIcon | undefined;
fixedDimensions: IFixedTerminalDimensions | undefined;
environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;
reconnectionOwner?: string;
task?: { label: string; id: string; lastTask: string; group?: string };
reconnectionProperties?: IReconnectionProperties;
waitOnExit?: WaitOnExitValue;
hideFromUser?: boolean;
isFeatureTerminal?: boolean;
type?: TerminalType;
}
export interface IReconnectionProperties {
ownerId: string;
data?: unknown;
}
export interface IReconnectionTaskData { label: string; id: string; lastTask: string; group?: string }
export type TerminalType = 'Task' | 'Local' | undefined;
export enum TitleEventSource {
@ -447,9 +454,9 @@ export interface IShellLaunchConfig {
ignoreConfigurationCwd?: boolean;
/**
* The owner of this terminal for reconnection.
* The reconnection properties for this terminal
*/
reconnectionOwner?: string;
reconnectionProperties?: IReconnectionProperties;
/** Whether to wait for a key press before closing the terminal. */
waitOnExit?: WaitOnExitValue;
@ -476,7 +483,7 @@ export interface IShellLaunchConfig {
* This is a terminal that attaches to an already running terminal.
*/
attachPersistentProcess?: {
id: number; findRevivedId?: boolean; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections; reconnectionOwner?: string; task?: { label: string; id: string; lastTask: string; group?: string }; type?: TerminalType; waitOnExit?: WaitOnExitValue; hideFromUser?: boolean; isFeatureTerminal?: boolean;
id: number; findRevivedId?: boolean; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections; reconnectionProperties?: IReconnectionProperties; type?: TerminalType; waitOnExit?: WaitOnExitValue; hideFromUser?: boolean; isFeatureTerminal?: boolean;
};
/**
@ -548,11 +555,6 @@ export interface IShellLaunchConfig {
* Create a terminal without shell integration even when it's enabled
*/
ignoreShellIntegration?: boolean;
/**
* The task associated with this terminal
*/
task?: { label: string; id: string; lastTask: string; group?: string };
}
export type WaitOnExitValue = boolean | string | ((exitCode: number) => string);

View file

@ -5,7 +5,7 @@
import { UriComponents } from 'vs/base/common/uri';
import { ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable';
import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, IReconnectionProperties, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
export interface ISingleTerminalConfiguration<T> {
userValue: T | undefined;
@ -60,8 +60,7 @@ export interface IProcessDetails {
color: string | undefined;
fixedDimensions: IFixedTerminalDimensions | undefined;
environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined;
reconnectionOwner?: string;
task?: { label: string; id: string; lastTask: string; group?: string };
reconnectionProperties?: IReconnectionProperties;
waitOnExit?: WaitOnExitValue;
hideFromUser?: boolean;
isFeatureTerminal?: boolean;

View file

@ -410,8 +410,7 @@ export class PtyService extends Disposable implements IPtyService {
color: persistentProcess.color,
fixedDimensions: persistentProcess.fixedDimensions,
environmentVariableCollections: persistentProcess.processLaunchOptions.options.environmentVariableCollections,
reconnectionOwner: persistentProcess.shellLaunchConfig.reconnectionOwner,
task: persistentProcess.shellLaunchConfig.task,
reconnectionProperties: persistentProcess.shellLaunchConfig.reconnectionProperties,
waitOnExit: persistentProcess.shellLaunchConfig.waitOnExit,
hideFromUser: persistentProcess.shellLaunchConfig.hideFromUser,
isFeatureTerminal: persistentProcess.shellLaunchConfig.isFeatureTerminal,
@ -789,7 +788,12 @@ class XtermSerializer implements ITerminalSerializer {
private _rawReviveBuffer: string | undefined,
logService: ILogService
) {
this._xterm = new XtermTerminal({ cols, rows, scrollback });
this._xterm = new XtermTerminal({
cols,
rows,
scrollback,
allowProposedApi: true
});
if (reviveBufferWithRestoreMessage) {
this._xterm.writeln(reviveBufferWithRestoreMessage);
}
@ -815,7 +819,7 @@ class XtermSerializer implements ITerminalSerializer {
const serialize = new (await this._getSerializeConstructor());
this._xterm.loadAddon(serialize);
const options: ISerializeOptions = {
scrollback: this._xterm.getOption('scrollback')
scrollback: this._xterm.options.scrollback
};
if (normalBufferOnly) {
options.excludeAltBuffer = true;

View file

@ -1417,12 +1417,15 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
const currentWindowConfig = window.config;
if (!configuration.extensionDevelopmentPath && currentWindowConfig && !!currentWindowConfig.extensionDevelopmentPath) {
configuration.extensionDevelopmentPath = currentWindowConfig.extensionDevelopmentPath;
configuration.extensionDevelopmentKind = currentWindowConfig.extensionDevelopmentKind;
configuration['enable-proposed-api'] = currentWindowConfig['enable-proposed-api'];
configuration.verbose = currentWindowConfig.verbose;
configuration['inspect-extensions'] = currentWindowConfig['inspect-extensions'];
configuration['inspect-brk-extensions'] = currentWindowConfig['inspect-brk-extensions'];
configuration.debugId = currentWindowConfig.debugId;
configuration.extensionEnvironment = currentWindowConfig.extensionEnvironment;
configuration['inspect-extensions'] = currentWindowConfig['inspect-extensions'];
configuration['extensions-dir'] = currentWindowConfig['extensions-dir'];
configuration['disable-extensions'] = currentWindowConfig['disable-extensions'];
}
}

View file

@ -951,8 +951,14 @@ function registerCloseEditorCommands() {
if (!editor) {
return;
}
const untypedEditor = editor.toUntyped();
const resolvedEditor = await editorResolverService.resolveEditor({ editor, options: { ...editorService.activeEditorPane?.options, override: EditorResolution.PICK } }, group);
// Resolver can only resolve untyped editors
if (!untypedEditor) {
return;
}
untypedEditor.options = { ...editorService.activeEditorPane?.options, override: EditorResolution.PICK };
const resolvedEditor = await editorResolverService.resolveEditor(untypedEditor, group);
if (!isEditorInputWithOptionsAndGroup(resolvedEditor)) {
return;
}

View file

@ -248,7 +248,7 @@ class StatusBarCodiconLabel extends SimpleIconLabel {
private progressCodicon = renderIcon(syncing);
private currentText = '';
private currentShowProgress = false;
private currentShowProgress: boolean | 'syncing' | 'loading' = false;
constructor(
private readonly container: HTMLElement
@ -258,7 +258,7 @@ class StatusBarCodiconLabel extends SimpleIconLabel {
set showProgress(showProgress: boolean | 'syncing' | 'loading') {
if (this.currentShowProgress !== showProgress) {
this.currentShowProgress = !!showProgress;
this.currentShowProgress = showProgress;
this.progressCodicon = renderIcon(showProgress === 'loading' ? spinningLoading : syncing);
this.text = this.currentText;
}

View file

@ -215,7 +215,7 @@ export class ConfigurationManager implements IConfigurationManager {
disposables.add(input.onDidTriggerItemButton(async (context) => {
resolve(undefined);
const { launch, config } = context.item;
await launch.openConfigFile({ preserveFocus: false, type: config.type });
await launch.openConfigFile({ preserveFocus: false, type: config.type, suppressInitialConfigs: true });
// Only Launch have a pin trigger button
await (launch as Launch).writeConfiguration(config);
await this.selectConfiguration(launch, config.name);
@ -564,7 +564,7 @@ class Launch extends AbstractLaunch implements ILaunch {
return this.configurationService.inspect<IGlobalConfig>('launch', { resource: this.workspace.uri }).workspaceFolderValue;
}
async openConfigFile({ preserveFocus, type, useInitialConfigs }: { preserveFocus: boolean; type?: string; useInitialConfigs?: boolean }, token?: CancellationToken): Promise<{ editor: IEditorPane | null; created: boolean }> {
async openConfigFile({ preserveFocus, type, suppressInitialConfigs }: { preserveFocus: boolean; type?: string; suppressInitialConfigs?: boolean }, token?: CancellationToken): Promise<{ editor: IEditorPane | null; created: boolean }> {
const resource = this.uri;
let created = false;
let content = '';
@ -573,7 +573,7 @@ class Launch extends AbstractLaunch implements ILaunch {
content = fileContent.value.toString();
} catch {
// launch.json not found: create one by collecting launch configs from debugConfigProviders
content = await this.getInitialConfigurationContent(this.workspace.uri, type, useInitialConfigs, token);
content = await this.getInitialConfigurationContent(this.workspace.uri, type, !suppressInitialConfigs, token);
if (!content) {
// Cancelled
return { editor: null, created: false };

View file

@ -63,7 +63,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider<IPi
tooltip: localize('customizeLaunchConfig', "Configure Launch Configuration")
}],
trigger: () => {
config.launch.openConfigFile({ preserveFocus: false, useInitialConfigs: false });
config.launch.openConfigFile({ preserveFocus: false });
return TriggerAction.CLOSE_PICKER;
},

View file

@ -840,17 +840,19 @@ export class DebugService implements IDebugService {
try {
return await dbg.substituteVariables(folder, config);
} catch (err) {
this.showError(err.message);
this.showError(err.message, undefined, !!launch?.getConfiguration(config.name));
return undefined; // bail out
}
}
return Promise.resolve(config);
}
private async showError(message: string, errorActions: ReadonlyArray<IAction> = []): Promise<void> {
private async showError(message: string, errorActions: ReadonlyArray<IAction> = [], promptLaunchJson = true): Promise<void> {
const configureAction = new Action(DEBUG_CONFIGURE_COMMAND_ID, DEBUG_CONFIGURE_LABEL, undefined, true, () => this.commandService.executeCommand(DEBUG_CONFIGURE_COMMAND_ID));
// Don't append the standard command if id of any provided action indicates it is a command
const actions = errorActions.filter((action) => action.id.endsWith('.command')).length > 0 ? errorActions : [...errorActions, configureAction];
const actions = errorActions.filter((action) => action.id.endsWith('.command')).length > 0 ?
errorActions :
[...errorActions, ...(promptLaunchJson ? [configureAction] : [])];
const { choice } = await this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length });
if (choice < actions.length) {
await actions[choice].run();

View file

@ -927,7 +927,7 @@ export interface ILaunch {
/**
* Opens the launch.json file. Creates if it does not exist.
*/
openConfigFile(options: { preserveFocus: boolean; type?: string; useInitialConfigs?: boolean }, token?: CancellationToken): Promise<{ editor: IEditorPane | null; created: boolean }>;
openConfigFile(options: { preserveFocus: boolean; type?: string; suppressInitialConfigs?: boolean }, token?: CancellationToken): Promise<{ editor: IEditorPane | null; created: boolean }>;
}
// Debug service interfaces

View file

@ -158,11 +158,11 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
title: EDIT_SESSIONS_TITLE,
ctorDescriptor: new SyncDescriptor(
ViewPaneContainer,
[EDIT_SESSIONS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true }]
[EDIT_SESSIONS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]
),
icon: EDIT_SESSIONS_VIEW_ICON,
hideIfEmpty: true
}, ViewContainerLocation.Sidebar
}, ViewContainerLocation.Sidebar, { donotRegisterOpenCommand: true }
);
this._register(this.instantiationService.createInstance(EditSessionsDataViews, container));
}
@ -596,7 +596,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
'workbench.experimental.editSessions.enabled': {
'type': 'boolean',
'tags': ['experimental', 'usesOnlineServices'],
'default': false,
'default': true,
'markdownDescription': localize('editSessionsEnabled', "Controls whether to display cloud-enabled actions to store and resume uncommitted changes when switching between web, desktop, or devices."),
},
}

View file

@ -10,16 +10,19 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { Registry } from 'vs/platform/registry/common/platform';
import { TreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { Extensions, ITreeItem, ITreeViewDataProvider, ITreeViewDescriptor, IViewsRegistry, TreeItemCollapsibleState, TreeViewItemHandleArg, ViewContainer } from 'vs/workbench/common/views';
import { EDIT_SESSIONS_DATA_VIEW_ID, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions';
import { EDIT_SESSIONS_DATA_VIEW_ID, EDIT_SESSIONS_SCHEME, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_SIGNED_IN, EDIT_SESSIONS_SIGNED_IN_KEY, EDIT_SESSIONS_TITLE, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions';
import { URI } from 'vs/base/common/uri';
import { fromNow } from 'vs/base/common/date';
import { Codicon } from 'vs/base/common/codicons';
import { API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
const EDIT_SESSIONS_COUNT_KEY = 'editSessionsCount';
const EDIT_SESSIONS_COUNT_CONTEXT_KEY = new RawContextKey<number>(EDIT_SESSIONS_COUNT_KEY, 0);
export class EditSessionsDataViews extends Disposable {
constructor(
container: ViewContainer,
@ -31,7 +34,7 @@ export class EditSessionsDataViews extends Disposable {
private registerViews(container: ViewContainer): void {
const viewId = EDIT_SESSIONS_DATA_VIEW_ID;
const name = localize('edit sessions data', 'All Sessions');
const name = EDIT_SESSIONS_TITLE;
const treeView = this.instantiationService.createInstance(TreeView, viewId, name);
treeView.showCollapseAllAction = true;
treeView.showRefreshAction = true;
@ -41,7 +44,9 @@ export class EditSessionsDataViews extends Disposable {
treeView.dataProvider = this.instantiationService.createInstance(EditSessionDataViewDataProvider);
}
});
Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).registerViews([<ITreeViewDescriptor>{
const viewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
viewsRegistry.registerViews([<ITreeViewDescriptor>{
id: viewId,
name,
ctorDescriptor: new SyncDescriptor(TreeViewPane),
@ -54,12 +59,26 @@ export class EditSessionsDataViews extends Disposable {
hideByDefault: true,
}], container);
viewsRegistry.registerViewWelcomeContent(viewId, {
content: localize(
'noEditSessions',
'You have no stored edit sessions to display.\n{0}',
localize(
{ key: 'storeEditSessionCommand', comment: ['Please do not translate the word "command", it is part of our internal syntax which must not change'] },
'[{0}](command:workbench.editSessions.actions.store)',
localize('storeEditSessionTitle', 'Store Edit Session')
)
),
when: ContextKeyExpr.and(ContextKeyExpr.equals(EDIT_SESSIONS_SIGNED_IN_KEY, true), ContextKeyExpr.equals(EDIT_SESSIONS_COUNT_KEY, 0)),
order: 1
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.editSessions.actions.resume',
title: localize('workbench.editSessions.actions.resume', "Resume Edit Session"),
icon: Codicon.repoPull,
icon: Codicon.desktopDownload,
menu: {
id: MenuId.ViewItemContext,
when: ContextKeyExpr.and(ContextKeyExpr.equals('view', viewId), ContextKeyExpr.regex('viewItem', /edit-session/i)),
@ -76,6 +95,22 @@ export class EditSessionsDataViews extends Disposable {
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.editSessions.actions.store',
title: localize('workbench.editSessions.actions.store', "Store Edit Session"),
icon: Codicon.cloudUpload,
});
}
async run(accessor: ServicesAccessor, handle: TreeViewItemHandleArg): Promise<void> {
const commandService = accessor.get(ICommandService);
await commandService.executeCommand('workbench.experimental.editSessions.actions.storeCurrent');
await treeView.refresh();
}
});
registerAction2(class extends Action2 {
constructor() {
super({
@ -105,13 +140,47 @@ export class EditSessionsDataViews extends Disposable {
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.editSessions.actions.deleteAll',
title: localize('workbench.editSessions.actions.deleteAll', "Delete All Edit Sessions"),
icon: Codicon.trash,
menu: {
id: MenuId.ViewTitle,
when: ContextKeyExpr.and(ContextKeyExpr.equals('view', viewId), ContextKeyExpr.greater(EDIT_SESSIONS_COUNT_KEY, 0)),
}
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const dialogService = accessor.get(IDialogService);
const editSessionWorkbenchService = accessor.get(IEditSessionsWorkbenchService);
const result = await dialogService.confirm({
message: localize('confirm delete all', 'Are you sure you want to permanently delete all edit sessions? You cannot undo this action.'),
type: 'warning',
title: EDIT_SESSIONS_TITLE
});
if (result.confirmed) {
await editSessionWorkbenchService.delete(null);
await treeView.refresh();
}
}
});
}
}
class EditSessionDataViewDataProvider implements ITreeViewDataProvider {
private editSessionsCount;
constructor(
@IEditSessionsWorkbenchService private readonly editSessionsWorkbenchService: IEditSessionsWorkbenchService
) { }
@IEditSessionsWorkbenchService private readonly editSessionsWorkbenchService: IEditSessionsWorkbenchService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
) {
this.editSessionsCount = EDIT_SESSIONS_COUNT_CONTEXT_KEY.bindTo(this.contextKeyService);
}
async getChildren(element?: ITreeItem): Promise<ITreeItem[]> {
if (!element) {
@ -131,13 +200,14 @@ class EditSessionDataViewDataProvider implements ITreeViewDataProvider {
private async getAllEditSessions(): Promise<ITreeItem[]> {
const allEditSessions = await this.editSessionsWorkbenchService.list();
this.editSessionsCount.set(allEditSessions.length);
return allEditSessions.map((session) => {
const resource = URI.from({ scheme: EDIT_SESSIONS_SCHEME, authority: 'remote-session-content', path: `/${session.ref}` });
return {
handle: resource.toString(),
collapsibleState: TreeItemCollapsibleState.Collapsed,
label: { label: session.ref },
description: fromNow(session.created, true),
label: { label: fromNow(session.created, true) },
description: session.ref,
themeIcon: Codicon.repo,
contextValue: `edit-session`
};

View file

@ -59,6 +59,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
// If another window changes the preferred session storage, reset our cached auth state in memory
this._register(this.storageService.onDidChangeValue(e => this.onDidChangeStorage(e)));
this.registerSignInAction();
this.registerResetAuthenticationAction();
this.signedInContext = EDIT_SESSIONS_SIGNED_IN.bindTo(this.contextKeyService);
@ -109,7 +110,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
return (content !== undefined && content !== null && ref !== undefined) ? { ref: ref, editSession: JSON.parse(content) } : undefined;
}
async delete(ref: string) {
async delete(ref: string | null) {
await this.initialize();
if (!this.initialized) {
throw new Error(`Unable to delete edit session with ref ${ref}.`);
@ -349,6 +350,27 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
}
}
private registerSignInAction() {
const that = this;
this._register(registerAction2(class ResetEditSessionAuthenticationAction extends Action2 {
constructor() {
super({
id: 'workbench.editSessions.actions.signIn',
title: localize('sign in', 'Sign In'),
category: EDIT_SESSION_SYNC_CATEGORY,
precondition: ContextKeyExpr.equals(EDIT_SESSIONS_SIGNED_IN_KEY, false),
menu: [{
id: MenuId.CommandPalette,
}]
});
}
async run() {
await that.initialize();
}
}));
}
private registerResetAuthenticationAction() {
const that = this;
this._register(registerAction2(class ResetEditSessionAuthenticationAction extends Action2 {

View file

@ -23,7 +23,7 @@ export interface IEditSessionsWorkbenchService {
read(ref: string | undefined): Promise<{ ref: string; editSession: EditSession } | undefined>;
write(editSession: EditSession): Promise<string>;
delete(ref: string): Promise<void>;
delete(ref: string | null): Promise<void>;
list(): Promise<IResourceRefHandle[]>;
}

View file

@ -8,6 +8,7 @@ import { grammarsExtPoint, ITMSyntaxExtensionPoint } from 'vs/workbench/services
import { IExtensionService, ExtensionPointContribution } from 'vs/workbench/services/extensions/common/extensions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
interface ModeScopeMap {
[key: string]: string;
@ -70,13 +71,18 @@ export abstract class EmmetEditorAction extends EditorAction {
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
const extensionService = accessor.get(IExtensionService);
const commandService = accessor.get(ICommandService);
const configurationService = accessor.get(IConfigurationService);
const extensionService = accessor.get(IExtensionService);
return this._withGrammarContributions(extensionService).then((grammarContributions) => {
if (this.id === 'editor.emmet.action.expandAbbreviation' && grammarContributions) {
return commandService.executeCommand<void>('emmet.expandAbbreviation', EmmetEditorAction.getLanguage(editor, grammarContributions));
const languageInfo = EmmetEditorAction.getLanguage(editor, grammarContributions);
const languageId = languageInfo?.language;
if (configurationService.getValue('emmet.triggerExpansionOnTab', { overrideIdentifier: languageId }) === true) {
return commandService.executeCommand<void>('emmet.expandAbbreviation', languageInfo);
}
}
return undefined;

View file

@ -95,7 +95,6 @@ export class CellDragAndDropController extends Disposable {
return;
}
event.browserEvent.preventDefault();
event.browserEvent.stopImmediatePropagation();
this.onCellDragover(event);
}, true);
addCellDragListener(DOM.EventType.DROP, event => {

View file

@ -1025,31 +1025,33 @@ var requirejs = (function() {
});
}
async showMarkupPreview(initialization: IMarkupCellInitialization) {
async showMarkupPreview(newContent: IMarkupCellInitialization) {
if (this._disposed) {
return;
}
const entry = this.markupPreviewMapping.get(initialization.cellId);
const entry = this.markupPreviewMapping.get(newContent.cellId);
if (!entry) {
return this.createMarkupPreview(initialization);
return this.createMarkupPreview(newContent);
}
const sameContent = initialization.content === entry.content;
if (!sameContent || !entry.visible) {
const sameContent = newContent.content === entry.content;
const sameMetadata = newContent.metadata === entry.metadata;
if (!sameContent || !sameMetadata || !entry.visible) {
this._sendMessageToWebview({
type: 'showMarkupCell',
id: initialization.cellId,
handle: initialization.cellHandle,
id: newContent.cellId,
handle: newContent.cellHandle,
// If the content has not changed, we still want to make sure the
// preview is visible but don't need to send anything over
content: sameContent ? undefined : initialization.content,
top: initialization.offset
content: sameContent ? undefined : newContent.content,
top: newContent.offset,
metadata: sameMetadata ? undefined : newContent.metadata
});
}
entry.content = initialization.content;
entry.offset = initialization.offset;
entry.metadata = newContent.metadata;
entry.content = newContent.content;
entry.offset = newContent.offset;
entry.visible = true;
}

View file

@ -316,6 +316,7 @@ export interface IShowMarkupCellMessage {
readonly handle: number;
readonly content: string | undefined;
readonly top: number;
readonly metadata: NotebookCellMetadata | undefined;
}
export interface IUpdateSelectedMarkupCellsMessage {

View file

@ -1035,7 +1035,7 @@ async function webviewPreloads(ctx: PreloadContext) {
break;
case 'showMarkupCell':
viewModel.showMarkupCell(event.data.id, event.data.top, event.data.content);
viewModel.showMarkupCell(event.data.id, event.data.top, event.data.content, event.data.metadata);
break;
case 'hideMarkupCells':
@ -1448,7 +1448,7 @@ async function webviewPreloads(ctx: PreloadContext) {
let cell = this._markupCells.get(info.cellId);
if (cell) {
cell.element.style.visibility = info.visible ? 'visible' : 'hidden';
await cell.updateContentAndRender(info.content);
await cell.updateContentAndRender(info.content, info.metadata);
} else {
cell = await this.createMarkupCell(info, info.offset, info.visible);
}
@ -1462,14 +1462,14 @@ async function webviewPreloads(ctx: PreloadContext) {
}
}
public async updateMarkupContent(id: string, newContent: string): Promise<void> {
public async updateMarkupContent(id: string, newContent: string, metadata: NotebookCellMetadata): Promise<void> {
const cell = this.getExpectedMarkupCell(id);
await cell?.updateContentAndRender(newContent);
await cell?.updateContentAndRender(newContent, metadata);
}
public showMarkupCell(id: string, top: number, newContent: string | undefined): void {
public showMarkupCell(id: string, top: number, newContent: string | undefined, metadata: NotebookCellMetadata | undefined): void {
const cell = this.getExpectedMarkupCell(id);
cell?.show(top, newContent);
cell?.show(top, newContent, metadata);
}
public hideMarkupCell(id: string): void {
@ -1633,11 +1633,11 @@ async function webviewPreloads(ctx: PreloadContext) {
private readonly outputItem: rendererApi.OutputItem;
/// Internal field that holds text content
private _content: { readonly value: string; readonly version: number };
private _content: { readonly value: string; readonly version: number; readonly metadata: NotebookCellMetadata };
constructor(id: string, mime: string, content: string, top: number, metadata: NotebookCellMetadata) {
this.id = id;
this._content = { value: content, version: 0 };
this._content = { value: content, version: 0, metadata: metadata };
let resolveReady: () => void;
this.ready = new Promise<void>(r => resolveReady = r);
@ -1646,7 +1646,10 @@ async function webviewPreloads(ctx: PreloadContext) {
this.outputItem = Object.freeze(<rendererApi.OutputItem>{
id,
mime,
metadata,
metadata: (): NotebookCellMetadata => {
return this._content.metadata;
},
text: (): string => {
return this._content.value;
@ -1688,7 +1691,7 @@ async function webviewPreloads(ctx: PreloadContext) {
this.addEventListeners();
this.updateContentAndRender(this._content.value).then(() => {
this.updateContentAndRender(this._content.value, this._content.metadata).then(() => {
resizeObserver.observe(this.element, this.id, false, this.id);
resolveReady();
});
@ -1738,8 +1741,8 @@ async function webviewPreloads(ctx: PreloadContext) {
});
}
public async updateContentAndRender(newContent: string): Promise<void> {
this._content = { value: newContent, version: this._content.version + 1 };
public async updateContentAndRender(newContent: string, metadata: NotebookCellMetadata): Promise<void> {
this._content = { value: newContent, version: this._content.version + 1, metadata };
await renderers.render(this.outputItem, this.element);
@ -1772,11 +1775,11 @@ async function webviewPreloads(ctx: PreloadContext) {
});
}
public show(top: number, newContent: string | undefined): void {
public show(top: number, newContent: string | undefined, metadata: NotebookCellMetadata | undefined): void {
this.element.style.visibility = 'visible';
this.element.style.top = `${top}px`;
if (typeof newContent === 'string') {
this.updateContentAndRender(newContent);
if (typeof newContent === 'string' || metadata) {
this.updateContentAndRender(newContent ?? this._content.value, metadata ?? this._content.metadata);
} else {
this.updateMarkupDimensions();
}
@ -1792,7 +1795,7 @@ async function webviewPreloads(ctx: PreloadContext) {
}
public rerender() {
this.updateContentAndRender(this._content.value);
this.updateContentAndRender(this._content.value, this._content.metadata);
}
public remove() {

View file

@ -29,8 +29,10 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
public get renderedHtml(): string | undefined { return this._renderedHtml; }
public set renderedHtml(value: string | undefined) {
this._renderedHtml = value;
this._onDidChangeState.fire({ contentChanged: true });
if (this._renderedHtml !== value) {
this._renderedHtml = value;
this._onDidChangeState.fire({ contentChanged: true });
}
}
get layoutInfo() {

View file

@ -642,6 +642,7 @@ export class SettingsEditor2 extends EditorPane {
private onDidClickSetting(evt: ISettingLinkClickEvent, recursed?: boolean): void {
const targetElement = this.currentSettingsModel.getElementsByName(evt.targetKey)?.[0];
let revealFailed = false;
if (targetElement) {
let sourceTop = 0.5;
try {
@ -661,23 +662,34 @@ export class SettingsEditor2 extends EditorPane {
if (this.viewState.filterToCategory && evt.source.displayCategory !== targetElement.displayCategory) {
this.tocTree.setFocus([]);
}
this.settingsTree.reveal(targetElement, sourceTop);
try {
this.settingsTree.reveal(targetElement, sourceTop);
} catch (_) {
// The listwidget couldn't find the setting to reveal,
// even though it's in the model, meaning there might be a filter
// preventing it from showing up.
revealFailed = true;
}
// We need to shift focus from the setting that contains the link to the setting that's
// linked. Clicking on the link sets focus on the setting that contains the link,
// which is why we need the setTimeout.
setTimeout(() => {
this.settingsTree.setFocus([targetElement]);
}, 50);
if (!revealFailed) {
// We need to shift focus from the setting that contains the link to the setting that's
// linked. Clicking on the link sets focus on the setting that contains the link,
// which is why we need the setTimeout.
setTimeout(() => {
this.settingsTree.setFocus([targetElement]);
}, 50);
const domElements = this.settingRenderers.getDOMElementsForSettingKey(this.settingsTree.getHTMLElement(), evt.targetKey);
if (domElements && domElements[0]) {
const control = domElements[0].querySelector(AbstractSettingRenderer.CONTROL_SELECTOR);
if (control) {
(<HTMLElement>control).focus();
const domElements = this.settingRenderers.getDOMElementsForSettingKey(this.settingsTree.getHTMLElement(), evt.targetKey);
if (domElements && domElements[0]) {
const control = domElements[0].querySelector(AbstractSettingRenderer.CONTROL_SELECTOR);
if (control) {
(<HTMLElement>control).focus();
}
}
}
} else if (!recursed) {
}
if (!recursed && revealFailed) {
// We'll call this event handler again after clearing the search query,
// so that more settings show up in the list.
const p = this.triggerSearch('');

View file

@ -510,7 +510,7 @@ configurationRegistry.registerConfiguration({
},
[TaskSettingId.ShowDecorations]: {
type: 'boolean',
description: nls.localize('task.showDecorations', "Shows decorations at points of interest in the terminal buffer such as the first problem found via a watch task. Note that this will only take effect for future tasks."),
markdownDescription: nls.localize('task.showDecorations', "Shows decorations at points of interest in the terminal buffer such as the first problem found via a watch task. Note that this will only take effect for future tasks. {0} will take precedence over this setting", '`#terminal.integrated.shellIntegration.decorationsEnabled#`'),
default: true
},
[TaskSettingId.Reconnection]: {

View file

@ -209,7 +209,8 @@ export class TaskQuickPick extends Disposable {
const changeSettingResult = await this._dialogService.show(Severity.Warning,
nls.localize('TaskQuickPick.changeSettingDetails',
"Task detection for {0} tasks causes files in any workspace you open to be run as code. Enabling {0} task detection is a user setting and will apply to any workspace you open. \n\n Do you want to enable {0} task detection for all workspaces?", selectedType),
[noButton, yesButton]
[noButton, yesButton],
{ cancelId: 1 }
);
if (changeSettingResult.choice === 1) {
await this._configurationService.updateValue(`${selectedType}.autoDetect`, 'on');

View file

@ -30,7 +30,7 @@ import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IShellLaunchConfig, TerminalLocation, TerminalSettingId, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { IReconnectionTaskData, IShellLaunchConfig, TerminalLocation, TerminalSettingId, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
@ -1271,7 +1271,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
private async _reconnectToTerminal(task: Task): Promise<ITerminalInstance | undefined> {
for (let i = 0; i < this._reconnectTerminals.length; i++) {
const terminal = this._reconnectTerminals[i];
const taskForTerminal = terminal.shellLaunchConfig.attachPersistentProcess?.task;
const taskForTerminal = terminal.shellLaunchConfig.attachPersistentProcess?.reconnectionProperties?.data as IReconnectionTaskData;
if (taskForTerminal?.id && task.getRecentlyUsedKey() === taskForTerminal.lastTask) {
this._reconnectTerminals.splice(i, 1);
return terminal;
@ -1318,7 +1318,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
return;
}
for (const terminal of terminals) {
const task = terminal.shellLaunchConfig.attachPersistentProcess?.task;
const task = terminal.shellLaunchConfig.attachPersistentProcess?.reconnectionProperties?.data as IReconnectionTaskData;
if (!task) {
continue;
}
@ -1428,8 +1428,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
this._terminalCreationQueue = this._terminalCreationQueue.then(() => this._doCreateTerminal(task, group, launchConfigs!));
const terminal: ITerminalInstance = (await this._terminalCreationQueue)!;
terminal.shellLaunchConfig.task = { lastTask: task.getRecentlyUsedKey()!, group, label: task._label, id: task._id };
terminal.shellLaunchConfig.reconnectionOwner = ReconnectionType;
terminal.shellLaunchConfig.reconnectionProperties = { ownerId: ReconnectionType, data: { lastTask: taskKey, group, label: task._label, id: task._id } };
const terminalKey = terminal.instanceId.toString();
const terminalData = { terminal: terminal, lastTask: taskKey, group };
terminal.onDisposed(() => this._deleteTaskAndTerminal(terminal, terminalData));

View file

@ -11,7 +11,7 @@ import { FindReplaceState } from 'vs/editor/contrib/find/browser/findState';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { ITerminalCapabilityStore, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IExtensionTerminalProfile, IProcessPropertyMap, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, ProcessPropertyType, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { IExtensionTerminalProfile, IProcessPropertyMap, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, ProcessPropertyType, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal';
import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProcess';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
@ -257,11 +257,10 @@ interface ITerminalEditorInputObject {
readonly icon: TerminalIcon | undefined;
readonly color: string | undefined;
readonly hasChildProcesses?: boolean;
readonly task?: { label: string; id: string; lastTask: string; group?: string; waitOnExit?: WaitOnExitValue };
readonly type?: TerminalType;
readonly isFeatureTerminal?: boolean;
readonly hideFromUser?: boolean;
readonly reconnectionOwner?: string;
readonly reconnectionProperties?: IReconnectionProperties;
}
export interface ISerializedTerminalEditorInput extends ITerminalEditorInputObject {
@ -450,7 +449,7 @@ export interface ITerminalInstance {
readonly fixedRows?: number;
readonly icon?: TerminalIcon;
readonly color?: string;
readonly reconnectionOwner?: string;
readonly reconnectionProperties?: IReconnectionProperties;
readonly processName: string;
readonly sequence?: string;
readonly staticTitle?: string;

View file

@ -44,10 +44,9 @@ export class TerminalInputSerializer implements IEditorSerializer {
color: instance.color,
resource: instance.resource.toString(),
hasChildProcesses: instance.hasChildProcesses,
task: instance.shellLaunchConfig.task,
type: instance.shellLaunchConfig.type,
isFeatureTerminal: instance.shellLaunchConfig.isFeatureTerminal,
hideFromUser: instance.shellLaunchConfig.hideFromUser,
reconnectionProperties: instance.shellLaunchConfig.reconnectionProperties
};
}
}

View file

@ -46,7 +46,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStoreMultiplexer } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { IProcessDataEvent, IProcessPropertyMap, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, PosixShellType, ProcessPropertyType, ShellIntegrationStatus, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId, TerminalShellType, TitleEventSource, WindowsShellType } from 'vs/platform/terminal/common/terminal';
import { IProcessDataEvent, IProcessPropertyMap, IReconnectionProperties, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, PosixShellType, ProcessPropertyType, ShellIntegrationStatus, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalSettingId, TerminalShellType, TitleEventSource, WindowsShellType } from 'vs/platform/terminal/common/terminal';
import { escapeNonWindowsPath, collapseTildePath } from 'vs/platform/terminal/common/terminalEnvironment';
import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry';
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
@ -282,7 +282,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// TODO: Should this be an event as it can fire twice?
get processReady(): Promise<void> { return this._processManager.ptyProcessReady; }
get hasChildProcesses(): boolean { return this.shellLaunchConfig.attachPersistentProcess?.hasChildProcesses || this._processManager.hasChildProcesses; }
get reconnectionOwner(): string | undefined { return this.shellLaunchConfig.attachPersistentProcess?.reconnectionOwner || this.shellLaunchConfig.reconnectionOwner; }
get reconnectionProperties(): IReconnectionProperties | undefined { return this.shellLaunchConfig.attachPersistentProcess?.reconnectionProperties || this.shellLaunchConfig.reconnectionProperties; }
get areLinksReady(): boolean { return this._areLinksReady; }
get initialDataEvents(): string[] | undefined { return this._initialDataEvents; }
get exitCode(): number | undefined { return this._exitCode; }
@ -696,7 +696,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._shutdownPersistentProcessId = shutdownPersistentProcessId;
}
get persistentProcessId(): number | undefined { return this._processManager.persistentProcessId ?? this._shutdownPersistentProcessId; }
get shouldPersist(): boolean { return (this._processManager.shouldPersist || this._shutdownPersistentProcessId !== undefined) && !this.shellLaunchConfig.isTransient && (!this.reconnectionOwner || this._configurationService.getValue(TaskSettingId.Reconnection) === true); }
get shouldPersist(): boolean { return (this._processManager.shouldPersist || this._shutdownPersistentProcessId !== undefined) && !this.shellLaunchConfig.isTransient && (!this.reconnectionProperties || this._configurationService.getValue(TaskSettingId.Reconnection) === true); }
/**
* Create xterm.js instance and attach data listeners.
@ -1249,7 +1249,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// If IShellLaunchConfig.waitOnExit was true and the process finished before the terminal
// panel was initialized.
if (xterm.raw.getOption('disableStdin')) {
if (xterm.raw.options.disableStdin) {
this._attachPressAnyKeyToCloseListener(xterm.raw);
}
}
@ -2392,7 +2392,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
info.requiresAction &&
this._configHelper.config.environmentChangesRelaunch &&
!this._processManager.hasWrittenData &&
(!this._shellLaunchConfig.isFeatureTerminal || (this.reconnectionOwner && this._configurationService.getValue(TaskSettingId.Reconnection) === true)) &&
(!this._shellLaunchConfig.isFeatureTerminal || (this.reconnectionProperties && this._configurationService.getValue(TaskSettingId.Reconnection) === true)) &&
!this._shellLaunchConfig.customPtyImplementation
&& !this._shellLaunchConfig.isExtensionOwnedTerminal &&
!this._shellLaunchConfig.attachPersistentProcess

View file

@ -20,7 +20,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { NaiveCwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/naiveCwdDetectionCapability';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { FlowControlConstants, IProcessDataEvent, IProcessProperty, IProcessPropertyMap, IProcessReadyEvent, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProcessOptions, ProcessPropertyType, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { FlowControlConstants, IProcessDataEvent, IProcessProperty, IProcessPropertyMap, IProcessReadyEvent, IReconnectionProperties, IShellLaunchConfig, ITerminalChildProcess, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProcessOptions, ProcessPropertyType, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { ISerializedCommandDetectionCapability } from 'vs/platform/terminal/common/terminalProcess';
import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
@ -114,10 +114,10 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
readonly onRestoreCommands = this._onRestoreCommands.event;
get persistentProcessId(): number | undefined { return this._process?.id; }
get shouldPersist(): boolean { return !!this.reconnectionOwner || (this._process ? this._process.shouldPersist : false); }
get shouldPersist(): boolean { return !!this.reconnectionProperties || (this._process ? this._process.shouldPersist : false); }
get hasWrittenData(): boolean { return this._hasWrittenData; }
get hasChildProcesses(): boolean { return this._hasChildProcesses; }
get reconnectionOwner(): string | undefined { return this._shellLaunchConfig?.attachPersistentProcess?.reconnectionOwner || this._shellLaunchConfig?.reconnectionOwner || undefined; }
get reconnectionProperties(): IReconnectionProperties | undefined { return this._shellLaunchConfig?.attachPersistentProcess?.reconnectionProperties || this._shellLaunchConfig?.reconnectionProperties || undefined; }
constructor(
private readonly _instanceId: number,
@ -246,7 +246,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
// this is a copy of what the merged environment collection is on the remote side
const env = await this._resolveEnvironment(backend, variableResolver, shellLaunchConfig);
const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionOwner) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient;
const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionProperties) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient;
if (shellLaunchConfig.attachPersistentProcess) {
const result = await backend.attachToProcess(shellLaunchConfig.attachPersistentProcess.id);
if (result) {
@ -460,7 +460,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
windowsEnableConpty: this._configHelper.config.windowsEnableConpty && !isScreenReaderModeEnabled,
environmentVariableCollections: this._extEnvironmentVariableCollection ? serializeEnvironmentVariableCollections(this._extEnvironmentVariableCollection.collections) : undefined
};
const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionOwner) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient;
const shouldPersist = ((this._configurationService.getValue(TaskSettingId.Reconnection) && shellLaunchConfig.reconnectionProperties) || !shellLaunchConfig.isFeatureTerminal) && this._configHelper.config.enablePersistentSessions && !shellLaunchConfig.isTransient;
return await backend.createProcess(shellLaunchConfig, initialCwd, cols, rows, this._configHelper.config.unicodeVersion, env, options, shouldPersist);
}
@ -493,7 +493,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
this._ptyResponsiveListener?.dispose();
this._ptyResponsiveListener = undefined;
if (this._shellLaunchConfig) {
if (this._shellLaunchConfig.isFeatureTerminal && !this.reconnectionOwner) {
if (this._shellLaunchConfig.isFeatureTerminal && !this.reconnectionProperties) {
// Indicate the process is exited (and gone forever) only for feature terminals
// so they can react to the exit, this is particularly important for tasks so
// that it knows that the process is not still active. Note that this is not

View file

@ -1049,12 +1049,12 @@ export class TerminalService implements ITerminalService {
}
private _addToReconnected(instance: ITerminalInstance): void {
if (instance.reconnectionOwner) {
const reconnectedTerminals = this._reconnectedTerminals.get(instance.reconnectionOwner);
if (instance.reconnectionProperties) {
const reconnectedTerminals = this._reconnectedTerminals.get(instance.reconnectionProperties.ownerId);
if (reconnectedTerminals) {
reconnectedTerminals.push(instance);
} else {
this._reconnectedTerminals.set(instance.reconnectionOwner, [instance]);
this._reconnectedTerminals.set(instance.reconnectionProperties.ownerId, [instance]);
}
}
}

View file

@ -3,11 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { IBuffer, IMarker, ITheme, RendererType, Terminal as RawXtermTerminal } from 'xterm';
import type { IBuffer, IMarker, ITheme, Terminal as RawXtermTerminal } from 'xterm';
import type { CanvasAddon as CanvasAddonType } from 'xterm-addon-canvas';
import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search';
import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11';
import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl';
import { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize';
import type { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize';
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
@ -27,7 +28,7 @@ import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeServic
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { TERMINAL_FOREGROUND_COLOR, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, ansiColorIdentifiers, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_FIND_MATCH_FOREGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_CURSOR_FOREGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { TERMINAL_FOREGROUND_COLOR, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, ansiColorIdentifiers, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_FIND_MATCH_FOREGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_CURSOR_FOREGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR, TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { Color } from 'vs/base/common/color';
import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@ -41,11 +42,13 @@ import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProc
// which suggests the fallback DOM-based renderer
const SLOW_CANVAS_RENDER_THRESHOLD = 50;
const NUMBER_OF_FRAMES_TO_MEASURE = 20;
const SMOOTH_SCROLL_DURATION = 125;
let CanvasAddon: typeof CanvasAddonType;
let SearchAddon: typeof SearchAddonType;
let SerializeAddon: typeof SerializeAddonType;
let Unicode11Addon: typeof Unicode11AddonType;
let WebglAddon: typeof WebglAddonType;
let SerializeAddon: typeof SerializeAddonType;
/**
* Wraps the xterm object with additional functionality. Interaction with the backing process is out
@ -78,6 +81,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
private _decorationAddon: DecorationAddon;
// Optional addons
private _canvasAddon?: CanvasAddonType;
private _searchAddon?: SearchAddonType;
private _unicode11Addon?: Unicode11AddonType;
private _webglAddon?: WebglAddonType;
@ -130,6 +134,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
const editorOptions = this._configurationService.getValue<IEditorOptions>('editor');
this.raw = this.add(new xtermCtor({
allowProposedApi: true,
cols,
rows,
altClickMovesCursor: config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt',
@ -146,16 +151,15 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
cursorBlink: config.cursorBlinking,
cursorStyle: config.cursorStyle === 'line' ? 'bar' : config.cursorStyle,
cursorWidth: config.cursorWidth,
bellStyle: 'none',
macOptionIsMeta: config.macOptionIsMeta,
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
rightClickSelectsWord: config.rightClickBehavior === 'selectWord',
fastScrollModifier: 'alt',
fastScrollSensitivity: config.fastScrollSensitivity,
scrollSensitivity: config.mouseWheelScrollSensitivity,
rendererType: this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType),
wordSeparator: config.wordSeparators,
overviewRulerWidth: 10
overviewRulerWidth: 10,
smoothScrollDuration: config.smoothScrolling ? SMOOTH_SCROLL_DURATION : 0
}));
this._core = (this.raw as any)._core as IXtermCore;
@ -227,6 +231,8 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
this._container = container;
if (this._shouldLoadWebgl()) {
this._enableWebglRenderer();
} else if (this._shouldLoadCanvas()) {
this._enableCanvasRenderer();
}
// Screen must be created at this point as xterm.open is called
return this._container.querySelector('.xterm-screen')!;
@ -250,11 +256,16 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
this.raw.options.rightClickSelectsWord = config.rightClickBehavior === 'selectWord';
this.raw.options.wordSeparator = config.wordSeparators;
this.raw.options.customGlyphs = config.customGlyphs;
this.raw.options.smoothScrollDuration = config.smoothScrolling ? SMOOTH_SCROLL_DURATION : 0;
if (this._shouldLoadWebgl()) {
this._enableWebglRenderer();
} else {
this._disposeOfWebglRenderer();
this.raw.options.rendererType = this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType);
if (this._shouldLoadCanvas()) {
this._enableCanvasRenderer();
} else {
this._disposeOfCanvasRenderer();
}
}
}
@ -262,6 +273,10 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
return !isSafari && (this._configHelper.config.gpuAcceleration === 'auto' && XtermTerminal._suggestedRendererType === undefined) || this._configHelper.config.gpuAcceleration === 'on';
}
private _shouldLoadCanvas(): boolean {
return (this._configHelper.config.gpuAcceleration === 'auto' && (XtermTerminal._suggestedRendererType === undefined || XtermTerminal._suggestedRendererType === 'canvas')) || this._configHelper.config.gpuAcceleration === 'canvas';
}
forceRedraw() {
this._webglAddon?.clearTextureAtlas();
this.raw.clearTextureAtlas();
@ -280,7 +295,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
// This is to fix an issue where dragging the windpow to the top of the screen to
// maximize on Windows/Linux would fire an event saying that the terminal was not
// visible.
if (this.raw.getOption('rendererType') === 'canvas') {
if (!!this._canvasAddon) {
this._core._renderService?._onIntersectionChange({ intersectionRatio: 1 });
// HACK: Force a refresh of the screen to ensure links are refresh corrected.
// This can probably be removed when the above hack is fixed in Chromium.
@ -432,27 +447,19 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
}
}
private _getBuiltInXtermRenderer(gpuAcceleration: string, suggestedRendererType?: string): RendererType {
let rendererType: RendererType = 'canvas';
if (gpuAcceleration === 'off' || (gpuAcceleration === 'auto' && suggestedRendererType === 'dom')) {
rendererType = 'dom';
}
return rendererType;
}
private async _enableWebglRenderer(): Promise<void> {
if (!this.raw.element || this._webglAddon) {
return;
}
const Addon = await this._getWebglAddonConstructor();
this._webglAddon = new Addon();
this._disposeOfCanvasRenderer();
try {
this.raw.loadAddon(this._webglAddon);
this._logService.trace('Webgl was loaded');
this._webglAddon.onContextLoss(() => {
this._logService.info(`Webgl lost context, disposing of webgl renderer`);
this._disposeOfWebglRenderer();
this.raw.options.rendererType = 'dom';
});
// Uncomment to add the texture atlas to the DOM
// setTimeout(() => {
@ -467,12 +474,41 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') {
this._measureRenderTime();
}
this.raw.options.rendererType = 'canvas';
XtermTerminal._suggestedRendererType = 'canvas';
this._disposeOfWebglRenderer();
this._enableCanvasRenderer();
}
}
private async _enableCanvasRenderer(): Promise<void> {
if (!this.raw.element || this._canvasAddon) {
return;
}
const Addon = await this._getCanvasAddonConstructor();
this._canvasAddon = new Addon();
this._disposeOfWebglRenderer();
try {
this.raw.loadAddon(this._canvasAddon);
this._logService.trace('Canvas was loaded');
} catch (e) {
this._logService.warn(`Canvas could not be loaded. Falling back to the dom renderer type.`, e);
const neverMeasureRenderTime = this._storageService.getBoolean(TerminalStorageKeys.NeverMeasureRenderTime, StorageScope.APPLICATION, false);
// if it's already set to dom, no need to measure render time
if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') {
this._measureRenderTime();
}
XtermTerminal._suggestedRendererType = 'dom';
this._disposeOfCanvasRenderer();
}
}
protected async _getCanvasAddonConstructor(): Promise<typeof CanvasAddonType> {
if (!CanvasAddon) {
CanvasAddon = (await import('xterm-addon-canvas')).CanvasAddon;
}
return CanvasAddon;
}
protected async _getSearchAddonConstructor(): Promise<typeof SearchAddonType> {
if (!SearchAddon) {
SearchAddon = (await import('xterm-addon-search')).SearchAddon;
@ -501,6 +537,15 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
return SerializeAddon;
}
private _disposeOfCanvasRenderer(): void {
try {
this._canvasAddon?.dispose();
} catch {
// ignore
}
this._canvasAddon = undefined;
}
private _disposeOfWebglRenderer(): void {
try {
this._webglAddon?.dispose();
@ -579,6 +624,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
const cursorColor = theme.getColor(TERMINAL_CURSOR_FOREGROUND_COLOR) || foregroundColor;
const cursorAccentColor = theme.getColor(TERMINAL_CURSOR_BACKGROUND_COLOR) || backgroundColor;
const selectionBackgroundColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR);
const selectionInactiveBackgroundColor = theme.getColor(TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR);
const selectionForegroundColor = theme.getColor(TERMINAL_SELECTION_FOREGROUND_COLOR) || undefined;
return {
@ -586,7 +632,8 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
foreground: foregroundColor?.toString(),
cursor: cursorColor?.toString(),
cursorAccent: cursorAccentColor?.toString(),
selection: selectionBackgroundColor?.toString(),
selectionBackground: selectionBackgroundColor?.toString(),
selectionInactiveBackground: selectionInactiveBackgroundColor?.toString(),
selectionForeground: selectionForegroundColor?.toString(),
black: theme.getColor(ansiColorIdentifiers[0])?.toString(),
red: theme.getColor(ansiColorIdentifiers[1])?.toString(),
@ -608,7 +655,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II
}
private _updateTheme(theme?: IColorTheme): void {
this.raw.setOption('theme', this._getXtermTheme(theme));
this.raw.options.theme = this._getXtermTheme(theme);
}
private async _updateUnicodeVersion(): Promise<void> {

View file

@ -302,6 +302,7 @@ export interface ITerminalConfiguration {
enabled: boolean;
decorationsEnabled: boolean;
};
smoothScrolling: boolean;
}
export const DEFAULT_LOCAL_ECHO_EXCLUDE: ReadonlyArray<string> = ['vim', 'vi', 'nano', 'tmux'];

View file

@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import { registerColor, ColorIdentifier, ColorDefaults, editorFindMatch, editorFindMatchHighlight, overviewRulerFindMatchForeground, editorSelectionBackground } from 'vs/platform/theme/common/colorRegistry';
import { registerColor, ColorIdentifier, ColorDefaults, editorFindMatch, editorFindMatchHighlight, overviewRulerFindMatchForeground, editorSelectionBackground, transparent } from 'vs/platform/theme/common/colorRegistry';
import { EDITOR_DRAG_AND_DROP_BACKGROUND, PANEL_BORDER, TAB_ACTIVE_BORDER } from 'vs/workbench/common/theme';
/**
@ -29,6 +29,12 @@ export const TERMINAL_SELECTION_BACKGROUND_COLOR = registerColor('terminal.selec
hcDark: editorSelectionBackground,
hcLight: editorSelectionBackground
}, nls.localize('terminal.selectionBackground', 'The selection background color of the terminal.'));
export const TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR = registerColor('terminal.inactiveSelectionBackground', {
light: transparent(TERMINAL_SELECTION_BACKGROUND_COLOR, 0.5),
dark: transparent(TERMINAL_SELECTION_BACKGROUND_COLOR, 0.5),
hcDark: transparent(TERMINAL_SELECTION_BACKGROUND_COLOR, 0.7),
hcLight: transparent(TERMINAL_SELECTION_BACKGROUND_COLOR, 0.5)
}, nls.localize('terminal.inactiveSelectionBackground', 'The selection background color of the terminal when it does not have focus.'));
export const TERMINAL_SELECTION_FOREGROUND_COLOR = registerColor('terminal.selectionForeground', {
light: null,
dark: null,

View file

@ -571,6 +571,11 @@ const terminalConfiguration: IConfigurationNode = {
type: 'number',
default: 100
},
[TerminalSettingId.SmoothScrolling]: {
markdownDescription: localize('terminal.integrated.smoothScrolling', "Controls whether the terminal will scroll using an animation."),
type: 'boolean',
default: false
},
}
};

View file

@ -63,7 +63,7 @@ suite('CommandDetectionCapability', () => {
}
setup(() => {
xterm = new Terminal({ cols: 80 });
xterm = new Terminal({ allowProposedApi: true, cols: 80 });
capability = new TestCommandDetectionCapability(xterm, new NullLogService());
addEvents = [];
capability.onCommandFinished(e => addEvents.push(e));

View file

@ -35,7 +35,7 @@ suite('PartialCommandDetectionCapability', () => {
}
setup(() => {
xterm = new Terminal({ cols: 80 }) as TestTerminal;
xterm = new Terminal({ allowProposedApi: true, cols: 80 }) as TestTerminal;
capability = new PartialCommandDetectionCapability(xterm);
addEvents = [];
capability.onCommandFinished(e => addEvents.push(e));

View file

@ -80,7 +80,7 @@ suite('TerminalLinkManager', () => {
instantiationService.stub(IThemeService, themeService);
instantiationService.stub(IViewDescriptorService, viewDescriptorService);
xterm = new Terminal({ cols: 80, rows: 30 });
xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 });
linkManager = instantiationService.createInstance(TestLinkManager, xterm, upcastPartial<ITerminalProcessManager>({
async getInitialCwd() {
return '';

View file

@ -87,7 +87,7 @@ suite('Workbench - TerminalLinkOpeners', () => {
}
} as Partial<IEditorService>);
// /*editorServiceSpy = */instantiationService.spy(IEditorService, 'openEditor');
xterm = new Terminal();
xterm = new Terminal({ allowProposedApi: true });
});
suite('TerminalSearchLinkOpener', () => {

View file

@ -98,7 +98,7 @@ suite('Workbench - TerminalLocalLinkDetector', () => {
configurationService = new TestConfigurationService();
instantiationService.stub(IConfigurationService, configurationService);
xterm = new Terminal({ cols: 80, rows: 30 });
xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 });
});
suite('platform independent', () => {

View file

@ -22,7 +22,7 @@ suite('Workbench - TerminalUriLinkDetector', () => {
instantiationService.stub(IConfigurationService, configurationService);
xterm = new Terminal({ cols: 80, rows: 30 });
xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 });
detector = instantiationService.createInstance(TerminalUriLinkDetector, xterm, resolveLinkForTest);
});

View file

@ -22,7 +22,7 @@ suite('Workbench - TerminalWordLinkDetector', () => {
instantiationService.stub(IConfigurationService, configurationService);
xterm = new Terminal({ cols: 80, rows: 30 });
xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 });
detector = instantiationService.createInstance(TerminalWordLinkDetector, xterm);
});

View file

@ -51,6 +51,7 @@ suite('DecorationAddon', () => {
});
instantiationService.stub(IThemeService, new TestThemeService());
xterm = new TestTerminal({
allowProposedApi: true,
cols: 80,
rows: 30
});

View file

@ -28,9 +28,7 @@ suite('LineDataEventAddon', () => {
let events: string[];
setup(() => {
xterm = new Terminal({
cols: 4
});
xterm = new Terminal({ allowProposedApi: true, cols: 4 });
lineDataEventAddon = new LineDataEventAddon();
xterm.loadAddon(lineDataEventAddon);

View file

@ -42,10 +42,7 @@ suite('ShellIntegrationAddon', () => {
let capabilities: ITerminalCapabilityStore;
setup(() => {
xterm = new Terminal({
cols: 80,
rows: 30
});
xterm = new Terminal({ allowProposedApi: true, cols: 80, rows: 30 });
const instantiationService = new TestInstantiationService();
instantiationService.stub(ILogService, NullLogService);
shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon, undefined, undefined);

View file

@ -16,7 +16,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IViewDescriptor, IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { Emitter } from 'vs/base/common/event';
import { TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR, TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { WebglAddon } from 'xterm-addon-webgl';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
@ -33,6 +33,7 @@ import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecy
class TestWebglAddon {
static shouldThrow = false;
static isEnabled = false;
readonly onChangeTextureAtlas = new Emitter().event as IEvent<HTMLCanvasElement>;
readonly onContextLoss = new Emitter().event as IEvent<void>;
activate() {
TestWebglAddon.isEnabled = !TestWebglAddon.shouldThrow;
@ -48,8 +49,8 @@ class TestWebglAddon {
class TestXtermTerminal extends XtermTerminal {
webglAddonPromise: Promise<typeof WebglAddon> = Promise.resolve(TestWebglAddon);
// Force synchronous to avoid async when activating the addon
protected override _getWebglAddonConstructor() {
// Force synchronous to avoid async when activating the addon
return this.webglAddonPromise;
}
}
@ -123,8 +124,8 @@ suite('XtermTerminal', () => {
});
test('should use fallback dimensions of 80x30', () => {
strictEqual(xterm.raw.options.cols, 80);
strictEqual(xterm.raw.options.rows, 30);
strictEqual(xterm.raw.cols, 80);
strictEqual(xterm.raw.rows, 30);
});
suite('theme', () => {
@ -149,6 +150,7 @@ suite('XtermTerminal', () => {
[TERMINAL_CURSOR_FOREGROUND_COLOR]: '#000300',
[TERMINAL_CURSOR_BACKGROUND_COLOR]: '#000400',
[TERMINAL_SELECTION_BACKGROUND_COLOR]: '#000500',
[TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR]: '#000600',
[TERMINAL_SELECTION_FOREGROUND_COLOR]: undefined,
'terminal.ansiBlack': '#010000',
'terminal.ansiRed': '#020000',
@ -173,7 +175,8 @@ suite('XtermTerminal', () => {
foreground: '#000200',
cursor: '#000300',
cursorAccent: '#000400',
selection: '#000500',
selectionBackground: '#000500',
selectionInactiveBackground: '#000600',
selectionForeground: undefined,
black: '#010000',
green: '#030000',
@ -198,7 +201,8 @@ suite('XtermTerminal', () => {
[TERMINAL_CURSOR_FOREGROUND_COLOR]: '#00030f',
[TERMINAL_CURSOR_BACKGROUND_COLOR]: '#00040f',
[TERMINAL_SELECTION_BACKGROUND_COLOR]: '#00050f',
[TERMINAL_SELECTION_FOREGROUND_COLOR]: '#00060f',
[TERMINAL_INACTIVE_SELECTION_BACKGROUND_COLOR]: '#00060f',
[TERMINAL_SELECTION_FOREGROUND_COLOR]: '#00070f',
'terminal.ansiBlack': '#01000f',
'terminal.ansiRed': '#02000f',
'terminal.ansiGreen': '#03000f',
@ -221,8 +225,9 @@ suite('XtermTerminal', () => {
foreground: '#00020f',
cursor: '#00030f',
cursorAccent: '#00040f',
selection: '#00050f',
selectionForeground: '#00060f',
selectionBackground: '#00050f',
selectionInactiveBackground: '#00060f',
selectionForeground: '#00070f',
black: '#01000f',
green: '#03000f',
red: '#02000f',
@ -246,7 +251,6 @@ suite('XtermTerminal', () => {
suite('renderers', () => {
test('should re-evaluate gpu acceleration auto when the setting is changed', async () => {
// Check initial state
strictEqual(xterm.raw.options.rendererType, 'dom');
strictEqual(TestWebglAddon.isEnabled, false);
// Open xterm as otherwise the webgl addon won't activate
@ -267,7 +271,6 @@ suite('XtermTerminal', () => {
await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'off' } });
configurationService.onDidChangeConfigurationEmitter.fire({ affectsConfiguration: () => true } as any);
await xterm.webglAddonPromise; // await addon activate
strictEqual(xterm.raw.options.rendererType, 'dom');
strictEqual(TestWebglAddon.isEnabled, false);
// Set to auto again but throw when activating the webgl addon
@ -275,7 +278,6 @@ suite('XtermTerminal', () => {
await configurationService.setUserConfiguration('terminal', { integrated: { ...defaultTerminalConfig, gpuAcceleration: 'auto' } });
configurationService.onDidChangeConfigurationEmitter.fire({ affectsConfiguration: () => true } as any);
await xterm.webglAddonPromise; // await addon activate
strictEqual(xterm.raw.options.rendererType, 'canvas');
strictEqual(TestWebglAddon.isEnabled, false);
});
});

View file

@ -83,37 +83,16 @@ export class EditorResolverService extends Disposable implements IEditorResolver
});
}
private resolveUntypedInputAndGroup(editor: EditorInputWithOptions | IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): [IUntypedEditorInput, IEditorGroup, EditorActivation | undefined] | undefined {
let untypedEditor: IUntypedEditorInput | undefined = undefined;
private resolveUntypedInputAndGroup(editor: IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): [IUntypedEditorInput, IEditorGroup, EditorActivation | undefined] | undefined {
const untypedEditor = editor;
// Typed: convert to untyped to be able to resolve the editor as the service only uses untyped
if (isEditorInputWithOptions(editor)) {
untypedEditor = editor.editor.toUntyped();
if (untypedEditor) {
// Preserve original options: specifically it is
// possible that a `override` was defined from
// the outside and we do not want to lose it.
untypedEditor.options = { ...untypedEditor.options, ...editor.options };
}
}
// Untyped: take as is
else {
untypedEditor = editor;
}
// Typed editors that cannot convert to untyped will be returned as undefined
if (!untypedEditor) {
return undefined;
}
// Use the untyped editor to find a group
const [group, activation] = this.instantiationService.invokeFunction(findGroup, untypedEditor, preferredGroup);
return [untypedEditor, group, activation];
}
async resolveEditor(editor: EditorInputWithOptions | IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): Promise<ResolvedEditor> {
async resolveEditor(editor: IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): Promise<ResolvedEditor> {
// Update the flattened editors
this._flattenedEditors = this._flattenEditorsMap();

View file

@ -501,8 +501,8 @@ export class EditorService extends Disposable implements EditorServiceImpl {
}
// Resolve override unless disabled
if (options?.override !== EditorResolution.DISABLED) {
const resolvedEditor = await this.editorResolverService.resolveEditor(isEditorInput(editor) ? { editor, options } : editor, preferredGroup);
if (options?.override !== EditorResolution.DISABLED && !isEditorInput(editor)) {
const resolvedEditor = await this.editorResolverService.resolveEditor(editor, preferredGroup);
if (resolvedEditor === ResolvedStatus.ABORT) {
return; // skip editor if override is aborted
@ -561,7 +561,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
let group: IEditorGroup | undefined = undefined;
// Resolve override unless disabled
if (editor.options?.override !== EditorResolution.DISABLED) {
if (editor.options?.override !== EditorResolution.DISABLED && !isEditorInputWithOptions(editor)) {
const resolvedEditor = await this.editorResolverService.resolveEditor(editor, preferredGroup);
if (resolvedEditor === ResolvedStatus.ABORT) {
@ -860,9 +860,9 @@ export class EditorService extends Disposable implements EditorServiceImpl {
}
// Resolve override unless disabled
if (override !== EditorResolution.DISABLED) {
if (override !== EditorResolution.DISABLED && !isEditorInput(replacement.replacement)) {
const resolvedEditor = await this.editorResolverService.resolveEditor(
isEditorReplacement(replacement) ? { editor: replacement.replacement, options: replacement.options } : replacement.replacement,
replacement.replacement,
targetGroup
);

View file

@ -156,12 +156,12 @@ export interface IEditorResolverService {
): IDisposable;
/**
* Given an editor resolves it to the suitable EditorInputWithOptionsAndGroup based on user extensions, settings, and built-in editors
* Given an editor resolves it to the suitable ResolvedEitor based on user extensions, settings, and built-in editors
* @param editor The editor to resolve
* @param preferredGroup The group you want to open the editor in
* @returns An EditorInputWithOptionsAndGroup if there is an available editor or a status of how to proceed
*/
resolveEditor(editor: EditorInputWithOptions | IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): Promise<ResolvedEditor>;
resolveEditor(editor: IUntypedEditorInput, preferredGroup: PreferredGroup | undefined): Promise<ResolvedEditor>;
/**
* Given a resource returns all the editor ids that match that resource. If there is exclusive editor we return an empty array

View file

@ -851,11 +851,12 @@ suite('EditorService', () => {
assert.ok(typedInput instanceof TestFileEditorInput);
assert.strictEqual(typedInput.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(editorFactoryCalled, 1);
// It's a typed editor input so the resolver should not have been called
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedEditor.resource.toString());
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -876,11 +877,11 @@ suite('EditorService', () => {
assert.ok(typedInput instanceof TestFileEditorInput);
assert.strictEqual(typedInput.resource.toString(), typedEditorReplacement.resource.toString());
assert.strictEqual(editorFactoryCalled, 2);
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedInput.resource.toString());
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -941,7 +942,8 @@ suite('EditorService', () => {
const pane = await openEditor({ editor: typedEditor, options: { override: DEFAULT_EDITOR_ASSOCIATION.id } });
assert.strictEqual(pane?.group, rootGroup);
assert.ok(pane.input instanceof FileEditorInput);
// We shouldn't have resolved because it is a typed editor, even though we have an override specified
assert.ok(pane.input instanceof TestFileEditorInput);
assert.strictEqual(pane.input.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(editorFactoryCalled, 0);
@ -964,11 +966,11 @@ suite('EditorService', () => {
assert.ok(pane.input instanceof TestFileEditorInput);
assert.strictEqual(pane.input.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(editorFactoryCalled, 1);
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedEditor.resource.toString());
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -985,12 +987,11 @@ suite('EditorService', () => {
assert.strictEqual(pane.input.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(pane.group.isSticky(pane.input), true);
assert.strictEqual(editorFactoryCalled, 1);
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedEditor.resource.toString());
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).options?.preserveFocus, true);
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -1008,12 +1009,11 @@ suite('EditorService', () => {
assert.strictEqual(pane.input.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(pane.group.isSticky(pane.input), true);
assert.strictEqual(editorFactoryCalled, 1);
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedEditor.resource.toString());
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).options?.preserveFocus, true);
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -1031,11 +1031,11 @@ suite('EditorService', () => {
assert.ok(pane?.input instanceof TestFileEditorInput);
assert.strictEqual(pane?.input.resource.toString(), typedEditor.resource.toString());
assert.strictEqual(editorFactoryCalled, 1);
assert.strictEqual(editorFactoryCalled, 0);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
assert.strictEqual((lastEditorFactoryEditor as IResourceEditorInput).resource.toString(), typedEditor.resource.toString());
assert.ok(!lastEditorFactoryEditor);
assert.ok(!lastUntitledEditorFactoryEditor);
assert.ok(!lastDiffEditorFactoryEditor);
@ -1342,7 +1342,8 @@ suite('EditorService', () => {
assert.strictEqual(pane?.group, rootGroup);
assert.strictEqual(pane?.group.count, 5);
assert.strictEqual(editorFactoryCalled, 3);
// Only the untyped editors should have had factories called (and 1 is disabled so 3 untyped - 1 disabled = 2)
assert.strictEqual(editorFactoryCalled, 2);
assert.strictEqual(untitledEditorFactoryCalled, 0);
assert.strictEqual(diffEditorFactoryCalled, 0);
@ -2334,13 +2335,19 @@ suite('EditorService', () => {
);
assert.strictEqual(editorCount, 0);
const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource1.txt'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('file://test/path/resource2.txt'), TEST_EDITOR_INPUT_ID);
const input3 = new TestFileEditorInput(URI.parse('file://test/path/resource3.md'), TEST_EDITOR_INPUT_ID);
const input4 = new TestFileEditorInput(URI.parse('file://test/path/resource4.md'), TEST_EDITOR_INPUT_ID);
const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource1.txt'), TEST_EDITOR_INPUT_ID).toUntyped();
const input2 = new TestFileEditorInput(URI.parse('file://test/path/resource2.txt'), TEST_EDITOR_INPUT_ID).toUntyped();
const input3 = new TestFileEditorInput(URI.parse('file://test/path/resource3.md'), TEST_EDITOR_INPUT_ID).toUntyped();
const input4 = new TestFileEditorInput(URI.parse('file://test/path/resource4.md'), TEST_EDITOR_INPUT_ID).toUntyped();
// Open editor input 1 and it shouln't trigger override as the glob doesn't match
await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: input3 }, { editor: input4 }]);
assert.ok(input1);
assert.ok(input2);
assert.ok(input3);
assert.ok(input4);
// Open editor inputs
await service.openEditors([input1, input2, input3, input4]);
// Only two matched the factory glob
assert.strictEqual(editorCount, 2);
registrationDisposable.dispose();
@ -2374,6 +2381,8 @@ suite('EditorService', () => {
assert.strictEqual(editorCount, 0);
const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource2.md'), TEST_EDITOR_INPUT_ID);
const untypedInput1 = input1.toUntyped();
assert.ok(untypedInput1);
// Open editor input 1 and it shouldn't trigger because I've disabled the override logic
await service.openEditor(input1, { override: EditorResolution.DISABLED });
@ -2381,7 +2390,7 @@ suite('EditorService', () => {
await service.replaceEditors([{
editor: input1,
replacement: input1,
replacement: untypedInput1,
}], part.activeGroup);
assert.strictEqual(editorCount, 1);

View file

@ -71,15 +71,17 @@ export class ProgressService extends Disposable implements IProgressService {
switch (location) {
case ProgressLocation.Notification:
return this.withNotificationProgress({ ...options, location, silent: this.notificationService.doNotDisturbMode }, task, onDidCancel);
case ProgressLocation.Window:
case ProgressLocation.Window: {
const type = (options as IProgressWindowOptions).type;
if ((options as IProgressWindowOptions).command) {
// Window progress with command get's shown in the status bar
return this.withWindowProgress({ ...options, location }, task);
return this.withWindowProgress({ ...options, location, type }, task);
}
// Window progress without command can be shown as silent notification
// which will first appear in the status bar and can then be brought to
// the front when clicking.
return this.withNotificationProgress({ delay: 150 /* default for ProgressLocation.Window */, ...options, silent: true, location: ProgressLocation.Notification }, task, onDidCancel);
return this.withNotificationProgress({ delay: 150 /* default for ProgressLocation.Window */, ...options, silent: true, location: ProgressLocation.Notification, type }, task, onDidCancel);
}
case ProgressLocation.Explorer:
return this.withPaneCompositeProgress('workbench.view.explorer', ViewContainerLocation.Sidebar, task, { ...options, location });
case ProgressLocation.Scm:
@ -235,7 +237,8 @@ export class ProgressService extends Disposable implements IProgressService {
this.withWindowProgress({
location: ProgressLocation.Window,
title: options.title ? parseLinkedText(options.title).toString() : undefined, // convert markdown links => string
command: 'notifications.showList'
command: 'notifications.showList',
type: options.type
}, progress => {
function reportProgress(step: IProgressStep) {

View file

@ -87,23 +87,23 @@ export class TextEditorService extends Disposable implements ITextEditorService
createTextEditor(input: IUntypedFileEditorInput): IFileEditorInput;
createTextEditor(input: IUntypedEditorInput | IUntypedFileEditorInput): EditorInput | IFileEditorInput {
// Merge Editor is Unsupported from here
// Merge Editor Not Supported (we fallback to showing the result only)
if (isResourceMergeEditorInput(input)) {
throw new Error('Unsupported input');
return this.createTextEditor(input.result);
}
// Diff Editor Support
if (isResourceDiffEditorInput(input)) {
const original = this.createTextEditor({ ...input.original });
const modified = this.createTextEditor({ ...input.modified });
const original = this.createTextEditor(input.original);
const modified = this.createTextEditor(input.modified);
return this.instantiationService.createInstance(DiffEditorInput, input.label, input.description, original, modified, undefined);
}
// Side by Side Editor Support
if (isResourceSideBySideEditorInput(input)) {
const primary = this.createTextEditor({ ...input.primary });
const secondary = this.createTextEditor({ ...input.secondary });
const primary = this.createTextEditor(input.primary);
const secondary = this.createTextEditor(input.secondary);
return this.instantiationService.createInstance(SideBySideEditorInput, input.label, input.description, secondary, primary);
}

View file

@ -575,13 +575,13 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
"@ts-morph/common@~0.12.3":
version "0.12.3"
resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.12.3.tgz#a96e250217cd30e480ab22ec6a0ebbe65fd784ff"
integrity sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w==
"@ts-morph/common@~0.16.0":
version "0.16.0"
resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.16.0.tgz#57e27d4b3fd65a4cd72cb36679ed08acb40fa3ba"
integrity sha512-SgJpzkTgZKLKqQniCjLaE3c2L2sdL7UShvmTmPBejAKd2OKV/yfMpQ2IWpAuA+VY5wy7PkSUaEObIqEK6afFuw==
dependencies:
fast-glob "^3.2.7"
minimatch "^3.0.4"
fast-glob "^3.2.11"
minimatch "^5.1.0"
mkdirp "^1.0.4"
path-browserify "^1.0.1"
@ -1005,14 +1005,14 @@
resolved "https://registry.yarnpkg.com/@vscode/sudo-prompt/-/sudo-prompt-9.3.1.tgz#c562334bc6647733649fd42afc96c0eea8de3b65"
integrity sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA==
"@vscode/telemetry-extractor@^1.9.6":
version "1.9.6"
resolved "https://registry.yarnpkg.com/@vscode/telemetry-extractor/-/telemetry-extractor-1.9.6.tgz#1b8d31c2ea841b33e5aa4e9c69a01f011cfc3add"
integrity sha512-G5m3NRNXW5ePsm4dft64EiOOopYin/3vQ6mBwWKkgnRkD8LivVvtDBjDMwZGsN5lF0w4t+ugb+IE4bXfMhZMcg==
"@vscode/telemetry-extractor@^1.9.8":
version "1.9.8"
resolved "https://registry.yarnpkg.com/@vscode/telemetry-extractor/-/telemetry-extractor-1.9.8.tgz#ffc000720ea2b9cd3421ba8a7bd172972c398b06"
integrity sha512-L27/fgC/gM7AY6AXriFGrznnX1M4Nc7VmHabYinDPoJDQYLjbSEDDVjjlSS6BiVkzc3OrFQStqXpHBhImis2eQ==
dependencies:
"@vscode/ripgrep" "^1.14.2"
command-line-args "^5.2.1"
ts-morph "^13.0.3"
ts-morph "^15.1.0"
"@vscode/test-web@^0.0.29":
version "0.0.29"
@ -1963,6 +1963,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^2.3.1, braces@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
@ -4232,18 +4239,7 @@ fast-glob@^3.1.1, fast-glob@^3.2.4:
micromatch "^4.0.2"
picomatch "^2.2.1"
fast-glob@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-glob@^3.2.9:
fast-glob@^3.2.11, fast-glob@^3.2.9:
version "3.2.11"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
@ -7002,6 +6998,13 @@ minimatch@4.2.1:
dependencies:
brace-expansion "^1.1.7"
minimatch@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7"
integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
@ -10297,12 +10300,12 @@ ts-loader@^9.2.7:
micromatch "^4.0.0"
semver "^7.3.4"
ts-morph@^13.0.3:
version "13.0.3"
resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-13.0.3.tgz#c0c51d1273ae2edb46d76f65161eb9d763444c1d"
integrity sha512-pSOfUMx8Ld/WUreoSzvMFQG5i9uEiWIsBYjpU9+TTASOeUa89j5HykomeqVULm1oqWtBdleI3KEFRLrlA3zGIw==
ts-morph@^15.1.0:
version "15.1.0"
resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-15.1.0.tgz#53deea5296d967ff6eba8f15f99d378aa7074a4e"
integrity sha512-RBsGE2sDzUXFTnv8Ba22QfeuKbgvAGJFuTN7HfmIRUkgT/NaVLfDM/8OFm2NlFkGlWEXdpW5OaFIp1jvqdDuOg==
dependencies:
"@ts-morph/common" "~0.12.3"
"@ts-morph/common" "~0.16.0"
code-block-writer "^11.0.0"
tsec@0.1.4:
@ -11225,6 +11228,11 @@ xtend@~2.1.1:
dependencies:
object-keys "~0.4.0"
xterm-addon-canvas@0.2.0-beta.15:
version "0.2.0-beta.15"
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4"
integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw==
xterm-addon-search@0.10.0-beta.3:
version "0.10.0-beta.3"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a"
@ -11240,20 +11248,20 @@ xterm-addon-unicode11@0.4.0-beta.3:
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa"
integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q==
xterm-addon-webgl@0.13.0-beta.9:
version "0.13.0-beta.9"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.9.tgz#66a9ac142ae347d0548abbf4e66bb2f35f415adb"
integrity sha512-x1o1tpCqIsICvhcRsZs+BLcwUIdizYS2G4TIH0KBnUDiSN+oSqpVBQNG8qKg56xbK8WtpdbQ9dLB7JR2W5cX0g==
xterm-addon-webgl@0.13.0-beta.32:
version "0.13.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.32.tgz#ae7335f788ae611733e03f6ca38280ab7b86d212"
integrity sha512-xOudNzYXaRh9QZ+IigXM5EB3bM8l3/F8F35EpJRYvvsylVxiB6Km8X8l7+nxlWt+uYdnHZs0ka2rvtL8kOP/uw==
xterm-headless@4.20.0-beta.20:
version "4.20.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.20.0-beta.20.tgz#da2d8131b02d6f1e37f47cc17e578f2c2980fbb6"
integrity sha512-JK4jUIiUH7TdzvMrpfDnbGxTuC4s7byjqnMHR8+gIpY8qCFjz0xcMFSbp+ZshxGwVyziI4jtJqTHZjFToT2/kw==
xterm-headless@5.0.0-beta.5:
version "5.0.0-beta.5"
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.0.0-beta.5.tgz#e29b6c5081f31f887122b7263ba996b0c46b3c22"
integrity sha512-CMQ1+prBNF92oBMeZzc2rfTcmOaCGfwwSaoPYNTjyziZT6mZsEg7amajYkb0YAnqJ29MFm4kPGZbU78/dX4k2A==
xterm@4.20.0-beta.20:
version "4.20.0-beta.20"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.20.tgz#2979a31839f7b8ee3ffe4f063b40c02facdb0fed"
integrity sha512-ltDtTquH+33tXQPFSDqenbgz6LkvIob6l6Rac85L4aX5Ve7P3ubVLrq+lTFJGQn3iiwGqNmnE1t1EUuGhxsXcQ==
xterm@5.0.0-beta.32:
version "5.0.0-beta.32"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.0.0-beta.32.tgz#62bb9902429c0055fd2fd85c9eecfbf1756ed31c"
integrity sha512-OAM1GaBs/chK63Cr86XbVhfVCLLXLpNxxFrv3RK9xoyb9dwiY3gaMxK9jeGzTnrbGLWJb+k5nxaC0rx2YsHvUA==
y18n@^3.2.1:
version "3.2.2"