提交 650eaa26 编写于 作者: S Sandeep Somavarapu

Merge branch 'master' into sandy081/sync-auth-flow

......@@ -3,7 +3,7 @@
"tasks": [
{
"type": "npm",
"script": "watch",
"script": "watchd",
"label": "Build VS Code",
"group": {
"kind": "build",
......@@ -31,6 +31,16 @@
}
}
},
{
"type": "npm",
"script": "kill-watchd",
"label": "Kill Build VS Code",
"group": "build",
"presentation": {
"reveal": "never"
},
"problemMatcher": "$tsc"
},
{
"label": "Run tests",
"type": "shell",
......
......@@ -435,14 +435,13 @@ export class Git {
const [, letter] = match;
try {
let networkPath = await new Promise<string>(resolve =>
const networkPath = await new Promise<string>(resolve =>
realpath.native(`${letter}:`, { encoding: 'utf8' }, (err, resolvedPath) =>
// eslint-disable-next-line eqeqeq
resolve(err != null ? undefined : resolvedPath),
),
);
if (networkPath !== undefined) {
networkPath = `${networkPath}\\`;
return path.normalize(
repoUri.fsPath.replace(
networkPath,
......
......@@ -13,7 +13,6 @@ import { nulToken } from '../utils/cancellation';
import { applyCodeAction } from '../utils/codeAction';
import { Command, CommandManager } from '../utils/commandManager';
import { ConfigurationDependentRegistration } from '../utils/dependentRegistration';
import { memoize } from '../utils/memoize';
import * as Previewer from '../utils/previewer';
import { snippetForFunctionCall } from '../utils/snippetForFunctionCall';
import { TelemetryReporter } from '../utils/telemetry';
......@@ -68,7 +67,9 @@ class MyCompletionItem extends vscode.CompletionItem {
this.preselect = tsEntry.isRecommended;
this.position = position;
this.useCodeSnippet = completionContext.useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method);
this.range = this.getRangeFromReplacementSpan(tsEntry, completionContext, position);
this.commitCharacters = MyCompletionItem.getCommitCharacters(completionContext, tsEntry);
this.insertText = tsEntry.insertText;
this.filterText = this.getFilterText(completionContext.line, tsEntry.insertText);
......@@ -268,14 +269,13 @@ class MyCompletionItem extends vscode.CompletionItem {
}
}
@memoize
public get commitCharacters(): string[] | undefined {
if (this.completionContext.isNewIdentifierLocation || !this.completionContext.isInValidCommitCharacterContext) {
private static getCommitCharacters(context: CompletionContext, entry: Proto.CompletionEntry): string[] | undefined {
if (context.isNewIdentifierLocation || !context.isInValidCommitCharacterContext) {
return undefined;
}
const commitCharacters: string[] = [];
switch (this.tsEntry.kind) {
switch (entry.kind) {
case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor:
case PConst.Kind.constructSignature:
......@@ -299,7 +299,7 @@ class MyCompletionItem extends vscode.CompletionItem {
case PConst.Kind.keyword:
case PConst.Kind.parameter:
commitCharacters.push('.', ',', ';');
if (this.completionContext.enableCallCompletions) {
if (context.enableCallCompletions) {
commitCharacters.push('(');
}
break;
......
......@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import type * as Proto from '../protocol';
import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService';
import API from '../utils/api';
import * as typeConverters from '../utils/typeConverters';
import FileConfigurationManager from './fileConfigurationManager';
......@@ -24,6 +25,10 @@ class TypeScriptRenameProvider implements vscode.RenameProvider {
position: vscode.Position,
token: vscode.CancellationToken
): Promise<vscode.Range | null> {
if (this.client.apiVersion.lt(API.v310)) {
return null;
}
const response = await this.execRename(document, position, token);
if (response?.type !== 'response' || !response.body) {
return null;
......@@ -34,12 +39,7 @@ class TypeScriptRenameProvider implements vscode.RenameProvider {
return Promise.reject<vscode.Range>(renameInfo.localizedErrorMessage);
}
const triggerSpan = renameInfo.triggerSpan; // added in TS 3.1
if (triggerSpan) {
return typeConverters.Range.fromTextSpan(triggerSpan);
}
return null;
return typeConverters.Range.fromTextSpan(renameInfo.triggerSpan);
}
public async provideRenameEdits(
......
......@@ -14,7 +14,7 @@
"native-watchdog": "1.3.0",
"node-pty": "0.10.0-beta8",
"onigasm-umd": "2.2.5",
"semver-umd": "^5.5.5",
"semver-umd": "^5.5.6",
"spdlog": "^0.11.1",
"vscode-nsfw": "1.2.8",
"vscode-proxy-agent": "^0.5.2",
......
......@@ -3,7 +3,7 @@
"version": "0.0.0",
"dependencies": {
"onigasm-umd": "2.2.5",
"semver-umd": "^5.5.5",
"semver-umd": "^5.5.6",
"vscode-textmate": "4.4.0",
"xterm": "4.6.0-beta.4",
"xterm-addon-search": "0.6.0",
......
......@@ -19,10 +19,10 @@ oniguruma@^7.2.0:
dependencies:
nan "^2.14.0"
semver-umd@^5.5.5:
version "5.5.5"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.5.tgz#a2e4280d0e92a2b27695c18811f0e939e144d86f"
integrity sha512-8rUq0nnTzlexpAdYmm8UDYsLkBn0MnBkfrGWPmyDBDDzv71dPOH07szOOaLj/5hO3BYmumYwS+wp3C60zLzh5g==
semver-umd@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
vscode-textmate@4.4.0:
version "4.4.0"
......
......@@ -317,10 +317,10 @@ readdirp@~3.2.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
semver-umd@^5.5.5:
version "5.5.5"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.5.tgz#a2e4280d0e92a2b27695c18811f0e939e144d86f"
integrity sha512-8rUq0nnTzlexpAdYmm8UDYsLkBn0MnBkfrGWPmyDBDDzv71dPOH07szOOaLj/5hO3BYmumYwS+wp3C60zLzh5g==
semver-umd@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
semver@^5.3.0:
version "5.6.0"
......
......@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?c49b146a6d13d30d08fbc195f20565aa") format("truetype");
src: url("./codicon.ttf?5d4d76ab2ce5108968ad644d591a16a6") format("truetype");
}
.codicon[class*='codicon-'] {
......
......@@ -153,6 +153,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget {
}
private hide(): void {
this.renderDisposeables.clear();
if (!this.visible) {
return;
}
......
......@@ -9803,6 +9803,11 @@ declare module 'vscode' {
* A string to show as placeholder in the input box to guide the user.
*/
placeholder: string;
/**
* Controls whether the input box is visible (default is `true`).
*/
visible: boolean;
}
interface QuickDiffProvider {
......
......@@ -828,21 +828,6 @@ declare module 'vscode' {
//#endregion
//#region Joao: SCM Input Box
/**
* Represents the input box in the Source Control viewlet.
*/
export interface SourceControlInputBox {
/**
* Controls whether the input box is visible (default is `true`).
*/
visible: boolean;
}
//#endregion
//#region Terminal data write event https://github.com/microsoft/vscode/issues/78502
export interface TerminalDataWriteEvent {
......
......@@ -406,7 +406,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return {
label: data[ISuggestDataDtoField.label2] || data[ISuggestDataDtoField.label],
kind: data[ISuggestDataDtoField.kind],
kind: data[ISuggestDataDtoField.kind] || modes.CompletionItemKind.Property,
tags: data[ISuggestDataDtoField.kindModifier],
detail: data[ISuggestDataDtoField.detail],
documentation: data[ISuggestDataDtoField.documentation],
......
......@@ -1104,7 +1104,7 @@ export const enum ISuggestDataDtoField {
export interface ISuggestDataDto {
[ISuggestDataDtoField.label]: string;
[ISuggestDataDtoField.label2]?: string | modes.CompletionItemLabel;
[ISuggestDataDtoField.kind]: modes.CompletionItemKind;
[ISuggestDataDtoField.kind]?: modes.CompletionItemKind;
[ISuggestDataDtoField.detail]?: string;
[ISuggestDataDtoField.documentation]?: string | IMarkdownString;
[ISuggestDataDtoField.sortText]?: string;
......
......@@ -956,7 +956,7 @@ class SuggestAdapter {
//
[extHostProtocol.ISuggestDataDtoField.label]: item.label,
[extHostProtocol.ISuggestDataDtoField.label2]: item.label2,
[extHostProtocol.ISuggestDataDtoField.kind]: typeConvert.CompletionItemKind.from(item.kind),
[extHostProtocol.ISuggestDataDtoField.kind]: item.kind ? typeConvert.CompletionItemKind.from(item.kind) : undefined,
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
[extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
......
......@@ -194,6 +194,11 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
set visible(visible: boolean) {
visible = !!visible;
if (this._visible === visible) {
return;
}
this._visible = visible;
this._proxy.$setInputBoxVisibility(this._sourceControlHandle, visible);
}
......
......@@ -808,70 +808,72 @@ export namespace CompletionItemTag {
export namespace CompletionItemKind {
export function from(kind: types.CompletionItemKind | undefined): modes.CompletionItemKind {
switch (kind) {
case types.CompletionItemKind.Method: return modes.CompletionItemKind.Method;
case types.CompletionItemKind.Function: return modes.CompletionItemKind.Function;
case types.CompletionItemKind.Constructor: return modes.CompletionItemKind.Constructor;
case types.CompletionItemKind.Field: return modes.CompletionItemKind.Field;
case types.CompletionItemKind.Variable: return modes.CompletionItemKind.Variable;
case types.CompletionItemKind.Class: return modes.CompletionItemKind.Class;
case types.CompletionItemKind.Interface: return modes.CompletionItemKind.Interface;
case types.CompletionItemKind.Struct: return modes.CompletionItemKind.Struct;
case types.CompletionItemKind.Module: return modes.CompletionItemKind.Module;
case types.CompletionItemKind.Property: return modes.CompletionItemKind.Property;
case types.CompletionItemKind.Unit: return modes.CompletionItemKind.Unit;
case types.CompletionItemKind.Value: return modes.CompletionItemKind.Value;
case types.CompletionItemKind.Constant: return modes.CompletionItemKind.Constant;
case types.CompletionItemKind.Enum: return modes.CompletionItemKind.Enum;
case types.CompletionItemKind.EnumMember: return modes.CompletionItemKind.EnumMember;
case types.CompletionItemKind.Keyword: return modes.CompletionItemKind.Keyword;
case types.CompletionItemKind.Snippet: return modes.CompletionItemKind.Snippet;
case types.CompletionItemKind.Text: return modes.CompletionItemKind.Text;
case types.CompletionItemKind.Color: return modes.CompletionItemKind.Color;
case types.CompletionItemKind.File: return modes.CompletionItemKind.File;
case types.CompletionItemKind.Reference: return modes.CompletionItemKind.Reference;
case types.CompletionItemKind.Folder: return modes.CompletionItemKind.Folder;
case types.CompletionItemKind.Event: return modes.CompletionItemKind.Event;
case types.CompletionItemKind.Operator: return modes.CompletionItemKind.Operator;
case types.CompletionItemKind.TypeParameter: return modes.CompletionItemKind.TypeParameter;
case types.CompletionItemKind.Issue: return modes.CompletionItemKind.Issue;
case types.CompletionItemKind.User: return modes.CompletionItemKind.User;
}
return modes.CompletionItemKind.Property;
}
const _from = new Map<types.CompletionItemKind, modes.CompletionItemKind>([
[types.CompletionItemKind.Method, modes.CompletionItemKind.Method],
[types.CompletionItemKind.Function, modes.CompletionItemKind.Function],
[types.CompletionItemKind.Constructor, modes.CompletionItemKind.Constructor],
[types.CompletionItemKind.Field, modes.CompletionItemKind.Field],
[types.CompletionItemKind.Variable, modes.CompletionItemKind.Variable],
[types.CompletionItemKind.Class, modes.CompletionItemKind.Class],
[types.CompletionItemKind.Interface, modes.CompletionItemKind.Interface],
[types.CompletionItemKind.Struct, modes.CompletionItemKind.Struct],
[types.CompletionItemKind.Module, modes.CompletionItemKind.Module],
[types.CompletionItemKind.Property, modes.CompletionItemKind.Property],
[types.CompletionItemKind.Unit, modes.CompletionItemKind.Unit],
[types.CompletionItemKind.Value, modes.CompletionItemKind.Value],
[types.CompletionItemKind.Constant, modes.CompletionItemKind.Constant],
[types.CompletionItemKind.Enum, modes.CompletionItemKind.Enum],
[types.CompletionItemKind.EnumMember, modes.CompletionItemKind.EnumMember],
[types.CompletionItemKind.Keyword, modes.CompletionItemKind.Keyword],
[types.CompletionItemKind.Snippet, modes.CompletionItemKind.Snippet],
[types.CompletionItemKind.Text, modes.CompletionItemKind.Text],
[types.CompletionItemKind.Color, modes.CompletionItemKind.Color],
[types.CompletionItemKind.File, modes.CompletionItemKind.File],
[types.CompletionItemKind.Reference, modes.CompletionItemKind.Reference],
[types.CompletionItemKind.Folder, modes.CompletionItemKind.Folder],
[types.CompletionItemKind.Event, modes.CompletionItemKind.Event],
[types.CompletionItemKind.Operator, modes.CompletionItemKind.Operator],
[types.CompletionItemKind.TypeParameter, modes.CompletionItemKind.TypeParameter],
[types.CompletionItemKind.Issue, modes.CompletionItemKind.Issue],
[types.CompletionItemKind.User, modes.CompletionItemKind.User],
]);
export function from(kind: types.CompletionItemKind): modes.CompletionItemKind {
return _from.get(kind) ?? modes.CompletionItemKind.Property;
}
const _to = new Map<modes.CompletionItemKind, types.CompletionItemKind>([
[modes.CompletionItemKind.Method, types.CompletionItemKind.Method],
[modes.CompletionItemKind.Function, types.CompletionItemKind.Function],
[modes.CompletionItemKind.Constructor, types.CompletionItemKind.Constructor],
[modes.CompletionItemKind.Field, types.CompletionItemKind.Field],
[modes.CompletionItemKind.Variable, types.CompletionItemKind.Variable],
[modes.CompletionItemKind.Class, types.CompletionItemKind.Class],
[modes.CompletionItemKind.Interface, types.CompletionItemKind.Interface],
[modes.CompletionItemKind.Struct, types.CompletionItemKind.Struct],
[modes.CompletionItemKind.Module, types.CompletionItemKind.Module],
[modes.CompletionItemKind.Property, types.CompletionItemKind.Property],
[modes.CompletionItemKind.Unit, types.CompletionItemKind.Unit],
[modes.CompletionItemKind.Value, types.CompletionItemKind.Value],
[modes.CompletionItemKind.Constant, types.CompletionItemKind.Constant],
[modes.CompletionItemKind.Enum, types.CompletionItemKind.Enum],
[modes.CompletionItemKind.EnumMember, types.CompletionItemKind.EnumMember],
[modes.CompletionItemKind.Keyword, types.CompletionItemKind.Keyword],
[modes.CompletionItemKind.Snippet, types.CompletionItemKind.Snippet],
[modes.CompletionItemKind.Text, types.CompletionItemKind.Text],
[modes.CompletionItemKind.Color, types.CompletionItemKind.Color],
[modes.CompletionItemKind.File, types.CompletionItemKind.File],
[modes.CompletionItemKind.Reference, types.CompletionItemKind.Reference],
[modes.CompletionItemKind.Folder, types.CompletionItemKind.Folder],
[modes.CompletionItemKind.Event, types.CompletionItemKind.Event],
[modes.CompletionItemKind.Operator, types.CompletionItemKind.Operator],
[modes.CompletionItemKind.TypeParameter, types.CompletionItemKind.TypeParameter],
[modes.CompletionItemKind.User, types.CompletionItemKind.User],
[modes.CompletionItemKind.Issue, types.CompletionItemKind.Issue],
]);
export function to(kind: modes.CompletionItemKind): types.CompletionItemKind {
switch (kind) {
case modes.CompletionItemKind.Method: return types.CompletionItemKind.Method;
case modes.CompletionItemKind.Function: return types.CompletionItemKind.Function;
case modes.CompletionItemKind.Constructor: return types.CompletionItemKind.Constructor;
case modes.CompletionItemKind.Field: return types.CompletionItemKind.Field;
case modes.CompletionItemKind.Variable: return types.CompletionItemKind.Variable;
case modes.CompletionItemKind.Class: return types.CompletionItemKind.Class;
case modes.CompletionItemKind.Interface: return types.CompletionItemKind.Interface;
case modes.CompletionItemKind.Struct: return types.CompletionItemKind.Struct;
case modes.CompletionItemKind.Module: return types.CompletionItemKind.Module;
case modes.CompletionItemKind.Property: return types.CompletionItemKind.Property;
case modes.CompletionItemKind.Unit: return types.CompletionItemKind.Unit;
case modes.CompletionItemKind.Value: return types.CompletionItemKind.Value;
case modes.CompletionItemKind.Constant: return types.CompletionItemKind.Constant;
case modes.CompletionItemKind.Enum: return types.CompletionItemKind.Enum;
case modes.CompletionItemKind.EnumMember: return types.CompletionItemKind.EnumMember;
case modes.CompletionItemKind.Keyword: return types.CompletionItemKind.Keyword;
case modes.CompletionItemKind.Snippet: return types.CompletionItemKind.Snippet;
case modes.CompletionItemKind.Text: return types.CompletionItemKind.Text;
case modes.CompletionItemKind.Color: return types.CompletionItemKind.Color;
case modes.CompletionItemKind.File: return types.CompletionItemKind.File;
case modes.CompletionItemKind.Reference: return types.CompletionItemKind.Reference;
case modes.CompletionItemKind.Folder: return types.CompletionItemKind.Folder;
case modes.CompletionItemKind.Event: return types.CompletionItemKind.Event;
case modes.CompletionItemKind.Operator: return types.CompletionItemKind.Operator;
case modes.CompletionItemKind.TypeParameter: return types.CompletionItemKind.TypeParameter;
case modes.CompletionItemKind.User: return types.CompletionItemKind.User;
case modes.CompletionItemKind.Issue: return types.CompletionItemKind.Issue;
}
return types.CompletionItemKind.Property;
return _to.get(kind) ?? types.CompletionItemKind.Property;
}
}
......
......@@ -695,7 +695,7 @@ class StatusbarEntryItem extends Disposable {
}
if (!this.entry || entry.ariaLabel !== this.entry.ariaLabel) {
this.container.setAttribute('aria-label', entry.ariaLabel);
this.labelContainer.setAttribute('aria-label', entry.ariaLabel);
}
// Update: Tooltip (on the container, because label can be disabled)
......
......@@ -171,7 +171,7 @@ registerAction2(class extends Action2 {
return;
}
const idx = editor.viewModel?.getViewCellIndex(activeCell);
const idx = editor.viewModel?.getCellIndex(activeCell);
if (typeof idx !== 'number') {
return;
}
......@@ -453,7 +453,7 @@ async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor
const text = activeCell.getText();
await editor.insertNotebookCell(activeCell, kind, 'below', text);
const idx = editor.viewModel?.getViewCellIndex(activeCell);
const idx = editor.viewModel?.getCellIndex(activeCell);
if (typeof idx !== 'number') {
return;
}
......@@ -522,7 +522,8 @@ registerAction2(class extends InsertCellCommand {
super(
{
id: INSERT_CODE_CELL_ABOVE_COMMAND_ID,
title: localize('notebookActions.insertCodeCellAbove', "Insert Code Cell Above")
title: localize('notebookActions.insertCodeCellAbove', "Insert Code Cell Above"),
f1: true
},
CellKind.Code,
'above');
......@@ -578,6 +579,7 @@ registerAction2(class extends InsertCellCommand {
{
id: INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID,
title: localize('notebookActions.insertMarkdownCellAbove', "Insert Markdown Cell Above"),
f1: true
},
CellKind.Markdown,
'above');
......@@ -860,7 +862,7 @@ registerAction2(class extends Action2 {
return;
}
viewModel.deleteCell(viewModel.getViewCellIndex(context.cell), true);
viewModel.deleteCell(viewModel.getCellIndex(context.cell), true);
notebookService.setToCopy([context.cell.model]);
}
});
......@@ -898,7 +900,7 @@ registerAction2(class extends Action2 {
return;
}
const currCellIndex = viewModel.getViewCellIndex(context!.cell);
const currCellIndex = viewModel.getCellIndex(context!.cell);
pasteCells.reverse().forEach(pasteCell => {
viewModel.insertCell(currCellIndex, pasteCell, true);
......@@ -939,7 +941,7 @@ registerAction2(class extends Action2 {
return;
}
const currCellIndex = viewModel.getViewCellIndex(context!.cell);
const currCellIndex = viewModel.getCellIndex(context!.cell);
pasteCells.reverse().forEach(pasteCell => {
viewModel.insertCell(currCellIndex + 1, pasteCell, true);
......@@ -1018,7 +1020,7 @@ registerAction2(class extends Action2 {
const editor = context.notebookEditor;
const activeCell = context.cell;
const idx = editor.viewModel?.getViewCellIndex(activeCell);
const idx = editor.viewModel?.getCellIndex(activeCell);
if (typeof idx !== 'number') {
return;
}
......@@ -1057,7 +1059,7 @@ registerAction2(class extends Action2 {
const editor = context.notebookEditor;
const activeCell = context.cell;
const idx = editor.viewModel?.getViewCellIndex(activeCell);
const idx = editor.viewModel?.getCellIndex(activeCell);
if (typeof idx !== 'number') {
return;
}
......@@ -1174,3 +1176,96 @@ registerAction2(class extends Action2 {
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.notebook.testSetHiddenRanges1',
title: 'Notebook Cells set hidden ranges: 2,3,4',
category: NOTEBOOK_ACTIONS_CATEGORY,
keybinding: {
when: IsDevelopmentContext,
primary: undefined,
weight: KeybindingWeight.WorkbenchContrib
},
f1: true
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const resource = editorService.activeEditor?.resource;
if (!resource) {
return;
}
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}
editor.setHiddenAreas([{ start: 1, length: 3 }]);
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.notebook.testSetHiddenRanges2',
title: 'Notebook Cells set hidden ranges: 4,5',
category: NOTEBOOK_ACTIONS_CATEGORY,
keybinding: {
when: IsDevelopmentContext,
primary: undefined,
weight: KeybindingWeight.WorkbenchContrib
},
f1: true
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const resource = editorService.activeEditor?.resource;
if (!resource) {
return;
}
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}
editor.setHiddenAreas([{ start: 3, length: 2 }]);
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.notebook.resetHiddenAreas',
title: 'Notebook Cells reset hidden ranges',
category: NOTEBOOK_ACTIONS_CATEGORY,
keybinding: {
when: IsDevelopmentContext,
primary: undefined,
weight: KeybindingWeight.WorkbenchContrib
},
f1: true
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const resource = editorService.activeEditor?.resource;
if (!resource) {
return;
}
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}
editor.setHiddenAreas([]);
}
});
......@@ -135,11 +135,11 @@
cursor: pointer;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows .monaco-list-row {
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row {
width: 100%;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows .monaco-list-row > .monaco-toolbar {
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .monaco-toolbar {
visibility: hidden;
display: inline-block;
......@@ -151,7 +151,7 @@
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2);
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows .monaco-list-row > .monaco-toolbar .action-item {
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .monaco-toolbar .action-item {
width: 24px;
height: 24px;
display: flex;
......@@ -159,7 +159,7 @@
margin: 1px 2px;
}
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows .monaco-list-row > .monaco-toolbar .action-item .action-label {
.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .monaco-toolbar .action-item .action-label {
display: flex;
align-items: center;
margin: auto;
......
......@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
......@@ -20,6 +21,9 @@ import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } fro
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { ScrollEvent } from 'vs/base/common/scrollable';
import { IListStyles, IListOptions } from 'vs/base/browser/ui/list/listWidget';
import { IListEvent } from 'vs/base/browser/ui/list/list';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
......@@ -249,6 +253,11 @@ export interface INotebookEditor {
*/
revealRangeInCenterIfOutsideViewport(cell: ICellViewModel, range: Range): void;
/**
* Set hidden areas on cell text models.
*/
setHiddenAreas(_ranges: ICellRange[]): boolean;
setCellSelection(cell: ICellViewModel, selection: Range): void;
/**
......@@ -270,6 +279,45 @@ export interface INotebookEditor {
hideFind(): void;
}
export interface INotebookCellList {
onWillScroll: Event<ScrollEvent>;
onDidChangeFocus: Event<IListEvent<ICellViewModel>>;
onDidChangeContentHeight: Event<number>;
scrollTop: number;
scrollHeight: number;
scrollLeft: number;
length: number;
rowsContainer: HTMLElement;
readonly onDidRemoveOutput: Event<IOutput>;
detachViewModel(): void;
attachViewModel(viewModel: NotebookViewModel): void;
clear(): void;
focusElement(element: ICellViewModel): void;
selectElement(element: ICellViewModel): void;
getFocusedElements(): ICellViewModel[];
revealElementInView(element: ICellViewModel): void;
revealElementInCenterIfOutsideViewport(element: ICellViewModel): void;
revealElementInCenter(element: ICellViewModel): void;
revealElementLineInView(element: ICellViewModel, line: number): void;
revealElementLineInCenter(element: ICellViewModel, line: number): void;
revealElementLineInCenterIfOutsideViewport(element: ICellViewModel, line: number): void;
revealElementRangeInView(element: ICellViewModel, range: Range): void;
revealElementRangeInCenter(element: ICellViewModel, range: Range): void;
revealElementRangeInCenterIfOutsideViewport(element: ICellViewModel, range: Range): void;
setHiddenAreas(_ranges: ICellRange[]): boolean;
domElementOfElement(element: ICellViewModel): HTMLElement | null;
focusView(): void;
getAbsoluteTopOfElement(element: ICellViewModel): number;
triggerScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent): void;
updateElementHeight2(element: ICellViewModel, size: number): void;
domFocus(): void;
setCellSelection(element: ICellViewModel, range: Range): void;
style(styles: IListStyles): void;
updateOptions(options: IListOptions<ICellViewModel>): void;
layout(height?: number, width?: number): void;
dispose(): void;
}
export interface BaseCellRenderTemplate {
container: HTMLElement;
cellContainer: HTMLElement;
......@@ -352,3 +400,66 @@ export enum CursorAtBoundary {
Bottom,
Both
}
/**
* [start, start + length]
*/
export interface ICellRange {
start: number;
length: number;
}
/**
* @param _ranges
*/
export function reduceCellRanges(_ranges: ICellRange[]): ICellRange[] {
if (!_ranges.length) {
return [];
}
let ranges = _ranges.sort((a, b) => a.start - b.start);
let result: ICellRange[] = [];
let currentRangeStart = ranges[0].start;
let currentRangeEnd = ranges[0].start + ranges[0].length;
for (let i = 0, len = ranges.length; i < len; i++) {
let range = ranges[i];
if (range.start > currentRangeEnd) {
result.push({ start: currentRangeStart, length: currentRangeEnd - currentRangeStart });
currentRangeStart = range.start;
currentRangeEnd = range.start + range.length;
} else if (range.start + range.length > currentRangeEnd) {
currentRangeEnd = range.start + range.length;
}
}
result.push({ start: currentRangeStart, length: currentRangeEnd - currentRangeStart });
return result;
}
export function getVisibleCells(cells: CellViewModel[], hiddenRanges: ICellRange[]) {
if (!hiddenRanges.length) {
return cells;
}
let start = 0;
let hiddenRangeIndex = 0;
let result: any[] = [];
while (start < cells.length && hiddenRangeIndex < hiddenRanges.length) {
if (start < hiddenRanges[hiddenRangeIndex].start) {
result.push(...cells.slice(start, hiddenRanges[hiddenRangeIndex].start));
}
start = hiddenRanges[hiddenRangeIndex].start + hiddenRanges[hiddenRangeIndex].length;
hiddenRangeIndex++;
}
if (start < cells.length) {
result.push(...cells.slice(start));
}
return result;
}
......@@ -30,7 +30,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { EditorOptions, IEditorCloseEvent, IEditorMemento } from 'vs/workbench/common/editor';
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_TOP_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
import { NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget';
import { CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, INotebookCellList, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
......@@ -70,7 +70,7 @@ export class NotebookCodeEditors implements ICompositeCodeEditor {
readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;
constructor(
private _list: NotebookCellList,
private _list: INotebookCellList,
private _renderedEditors: Map<ICellViewModel, ICodeEditor | undefined>
) {
_list.onDidChangeFocus(_e => this._onDidChangeActiveEditor.fire(this), undefined, this._disposables);
......@@ -93,7 +93,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
private body!: HTMLElement;
private webview: BackLayerWebView | null = null;
private webviewTransparentCover: HTMLElement | null = null;
private list: NotebookCellList | undefined;
private list: INotebookCellList | undefined;
private control: ICompositeCodeEditor | undefined;
private renderedEditors: Map<ICellViewModel, ICodeEditor | undefined> = new Map();
private eventDispatcher: NotebookEventDispatcher | undefined;
......@@ -275,7 +275,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.webview = null;
}
this.list?.splice(0, this.list?.length);
this.list?.clear();
super.onHide();
}
......@@ -348,12 +348,13 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
private detachModel() {
this.localStore.clear();
this.list?.detachViewModel();
this.notebookViewModel?.dispose();
this.notebookViewModel = undefined;
this.webview?.clearInsets();
this.webview?.clearPreloadsCache();
this.findWidget.clear();
this.list?.splice(0, this.list?.length || 0);
this.list?.clear();
}
private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
......@@ -373,36 +374,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.editorEditable?.set(e.source.editable);
}));
this.localStore.add(this.notebookViewModel.onDidChangeViewCells((e) => {
if (e.synchronous) {
e.splices.reverse().forEach((diff) => {
// remove output in the webview
for (let i = diff[0]; i < diff[0] + diff[1]; i++) {
const cell = this.list?.element(i);
cell?.model.outputs.forEach(output => {
this.removeInset(output);
});
}
this.list?.splice(diff[0], diff[1], diff[2]);
});
} else {
DOM.scheduleAtNextAnimationFrame(() => {
e.splices.reverse().forEach((diff) => {
// remove output in the webview
for (let i = diff[0]; i < diff[0] + diff[1]; i++) {
const cell = this.list?.element(i);
cell?.model.outputs.forEach(output => {
this.removeInset(output);
});
}
this.list?.splice(diff[0], diff[1], diff[2]);
});
});
}
}));
this.webview?.updateRendererPreloads(this.notebookViewModel.renderers);
this.localStore.add(this.list!.onWillScroll(e => {
......@@ -418,9 +389,8 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
if (this.webview?.insetMapping) {
this.webview?.insetMapping.forEach((value, key) => {
let cell = value.cell;
let index = this.notebookViewModel!.getViewCellIndex(cell);
let cellTop = this.list?.getAbsoluteTop(index) || 0;
const cell = value.cell;
const cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
updateItems.push({
cell: cell,
......@@ -436,8 +406,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}));
this.list?.splice(0, 0, this.notebookViewModel!.viewCells as CellViewModel[]);
this.list?.layout();
this.list!.attachViewModel(this.notebookViewModel);
this.localStore.add(this.list!.onDidRemoveOutput(output => {
this.removeInset(output);
}));
this.list!.layout();
if (viewState?.scrollPosition !== undefined) {
this.list!.scrollTop = viewState!.scrollPosition.top;
......@@ -454,8 +428,8 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
if (this.list) {
state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
let cellHeights: { [key: number]: number } = {};
for (let i = 0; i < this.list.length; i++) {
const elm = this.list.element(i)!;
for (let i = 0; i < this.viewModel!.viewCells.length; i++) {
const elm = this.viewModel!.viewCells[i] as CellViewModel;
if (elm.cellKind === CellKind.Code) {
cellHeights[i] = elm.layoutInfo.totalHeight;
} else {
......@@ -507,98 +481,57 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
//#region Editor Features
selectElement(cell: ICellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.setSelection([index]);
this.list?.setFocus([index]);
}
this.list?.selectElement(cell);
}
revealInView(cell: ICellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealInView(index);
}
this.list?.revealElementInView(cell);
}
revealInCenterIfOutsideViewport(cell: ICellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealInCenterIfOutsideViewport(index);
}
this.list?.revealElementInCenterIfOutsideViewport(cell);
}
revealInCenter(cell: ICellViewModel) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealInCenter(index);
}
this.list?.revealElementInCenter(cell);
}
revealLineInView(cell: ICellViewModel, line: number): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealLineInView(index, line);
}
this.list?.revealElementLineInView(cell, line);
}
revealLineInCenter(cell: ICellViewModel, line: number) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealLineInCenter(index, line);
}
this.list?.revealElementLineInCenter(cell, line);
}
revealLineInCenterIfOutsideViewport(cell: ICellViewModel, line: number) {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealLineInCenterIfOutsideViewport(index, line);
}
this.list?.revealElementLineInCenterIfOutsideViewport(cell, line);
}
revealRangeInView(cell: ICellViewModel, range: Range): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealRangeInView(index, range);
}
this.list?.revealElementRangeInView(cell, range);
}
revealRangeInCenter(cell: ICellViewModel, range: Range): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealRangeInCenter(index, range);
}
this.list?.revealElementRangeInCenter(cell, range);
}
revealRangeInCenterIfOutsideViewport(cell: ICellViewModel, range: Range): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.revealRangeInCenterIfOutsideViewport(index, range);
}
this.list?.revealElementRangeInCenterIfOutsideViewport(cell, range);
}
setCellSelection(cell: ICellViewModel, range: Range): void {
const index = this.notebookViewModel?.getViewCellIndex(cell);
if (index !== undefined) {
this.list?.setCellSelection(index, range);
}
this.list?.setCellSelection(cell, range);
}
changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
return this.notebookViewModel?.changeDecorations(callback);
}
setHiddenAreas(_ranges: ICellRange[]): boolean {
return this.list!.setHiddenAreas(_ranges);
}
//#endregion
//#region Find Delegate
......@@ -617,10 +550,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
//#region Cell operations
async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
let relayout = (cell: ICellViewModel, height: number) => {
let index = this.notebookViewModel!.getViewCellIndex(cell);
if (index >= 0) {
this.list?.updateElementHeight(index, height);
}
this.list?.updateElementHeight2(cell, height);
};
let r: () => void;
......@@ -635,10 +565,10 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
async insertNotebookCell(cell: ICellViewModel, type: CellKind, direction: 'above' | 'below', initialText: string = ''): Promise<void> {
const newLanguages = this.notebookViewModel!.languages;
const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
const index = this.notebookViewModel!.getViewCellIndex(cell);
const index = this.notebookViewModel!.getCellIndex(cell);
const insertIndex = direction === 'above' ? index : index + 1;
const newCell = this.notebookViewModel!.createCell(insertIndex, initialText.split(/\r?\n/g), language, type, true);
this.list?.setFocus([insertIndex]);
this.list?.focusElement(newCell);
if (type === CellKind.Markdown) {
newCell.editState = CellEditState.Editing;
......@@ -646,7 +576,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
let r: () => void;
DOM.scheduleAtNextAnimationFrame(() => {
this.list?.revealInCenterIfOutsideViewport(insertIndex);
this.list?.revealElementInCenterIfOutsideViewport(cell);
r();
});
......@@ -655,12 +585,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
async deleteNotebookCell(cell: ICellViewModel): Promise<void> {
(cell as CellViewModel).save();
const index = this.notebookViewModel!.getViewCellIndex(cell);
const index = this.notebookViewModel!.getCellIndex(cell);
this.notebookViewModel!.deleteCell(index, true);
}
async moveCellDown(cell: ICellViewModel): Promise<void> {
const index = this.notebookViewModel!.getViewCellIndex(cell);
const index = this.notebookViewModel!.getCellIndex(cell);
if (index === this.notebookViewModel!.viewCells.length - 1) {
return;
}
......@@ -670,7 +600,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
async moveCellUp(cell: ICellViewModel): Promise<void> {
const index = this.notebookViewModel!.getViewCellIndex(cell);
const index = this.notebookViewModel!.getCellIndex(cell);
if (index === 0) {
return;
}
......@@ -686,7 +616,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
let r: () => void;
DOM.scheduleAtNextAnimationFrame(() => {
this.list?.revealInCenterIfOutsideViewport(index + 1);
this.list?.revealElementInCenterIfOutsideViewport(this.notebookViewModel!.viewCells[index + 1]);
r();
});
......@@ -785,18 +715,15 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
const index = this.notebookViewModel!.getViewCellIndex(cell);
if (focusEditor) {
this.list?.setFocus([index]);
this.list?.setSelection([index]);
this.selectElement(cell);
this.list?.focusView();
cell.editState = CellEditState.Editing;
cell.focusMode = CellFocusMode.Editor;
this.revealInCenterIfOutsideViewport(cell);
} else {
let itemDOM = this.list?.domElementAtIndex(index);
let itemDOM = this.list?.domElementOfElement(cell);
if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
(document.activeElement as HTMLElement).blur();
}
......@@ -804,8 +731,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
cell.editState = CellEditState.Preview;
cell.focusMode = CellFocusMode.Editor;
this.list?.setFocus([index]);
this.list?.setSelection([index]);
this.selectElement(cell);
this.revealInCenterIfOutsideViewport(cell);
this.list?.focusView();
}
......@@ -839,13 +765,10 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
let preloads = this.notebookViewModel!.renderers;
if (!this.webview!.insetMapping.has(output)) {
let index = this.notebookViewModel!.getViewCellIndex(cell);
let cellTop = this.list?.getAbsoluteTop(index) || 0;
let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
} else {
let index = this.notebookViewModel!.getViewCellIndex(cell);
let cellTop = this.list?.getAbsoluteTop(index) || 0;
let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
let scrollTop = this.list?.scrollTop || 0;
this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
......@@ -959,13 +882,13 @@ registerThemingParticipant((theme, collector) => {
}
// Cell Margin
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row { padding-top: ${EDITOR_TOP_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { padding-top: ${EDITOR_TOP_MARGIN}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container { width: calc(100% - ${CELL_MARGIN * 2 + CELL_RUN_GUTTER}px); margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { width: calc(100% - ${CELL_RUN_GUTTER}px); }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .markdown-editor-container { margin-left: ${CELL_RUN_GUTTER}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`);
collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
});
......@@ -343,7 +343,11 @@ export class BackLayerWebView extends Disposable {
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
} else if (data.type === 'did-scroll-wheel') {
this.notebookEditor.triggerScroll(data.payload);
this.notebookEditor.triggerScroll({
...data.payload,
preventDefault: () => { },
stopPropagation: () => { }
});
}
return;
}
......
......@@ -110,7 +110,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
const outputTotalHeight = this._outputsTop!.getTotalValue();
const totalHeight = EDITOR_TOOLBAR_HEIGHT + this.editorHeight + EDITOR_TOP_MARGIN + outputTotalHeight + BOTTOM_CELL_TOOLBAR_HEIGHT + CELL_STATUSBAR_HEIGHT;
const indicatorHeight = this.editorHeight + CELL_STATUSBAR_HEIGHT + outputTotalHeight;
const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.editorHeight;
const outputContainerOffset = EDITOR_TOOLBAR_HEIGHT + EDITOR_TOP_MARGIN + this.editorHeight + CELL_STATUSBAR_HEIGHT;
const bottomToolbarOffset = totalHeight - BOTTOM_CELL_TOOLBAR_HEIGHT;
const editorWidth = state.outerWidth !== undefined ? state.outerWidth - CELL_MARGIN * 2 - CELL_RUN_GUTTER : this._layoutInfo?.editorWidth;
this._layoutInfo = {
......
......@@ -10,11 +10,11 @@ import { URI } from 'vs/base/common/uri';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { IModelDeltaDecoration, TrackedRangeStickiness, IModelDecorationOptions } from 'vs/editor/common/model';
import { WorkspaceTextEdit } from 'vs/editor/common/modes';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { CellFindMatch, CellEditState, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellFindMatch, CellEditState, ICellViewModel, NotebookLayoutInfo, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { DeleteCellEdit, InsertCellEdit, MoveCellEdit } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEdit';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
......@@ -23,6 +23,7 @@ import { CellKind, ICell } from 'vs/workbench/contrib/notebook/common/notebookCo
import { NotebookEventDispatcher, NotebookMetadataChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import * as strings from 'vs/base/common/strings';
export interface INotebookEditorViewState {
editingCells: { [key: number]: boolean };
......@@ -59,6 +60,70 @@ export interface INotebookViewCellsUpdateEvent {
splices: NotebookViewCellsSplice[];
}
import { IntervalTree, IntervalNode } from 'vs/editor/common/model/intervalTree';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
class DecorationsTree {
private readonly _decorationsTree: IntervalTree;
constructor() {
this._decorationsTree = new IntervalTree();
}
public intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number): IntervalNode[] {
const r1 = this._decorationsTree.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
return r1;
}
public search(filterOwnerId: number, filterOutValidation: boolean, overviewRulerOnly: boolean, cachedVersionId: number): IntervalNode[] {
return this._decorationsTree.search(filterOwnerId, filterOutValidation, cachedVersionId);
}
public collectNodesFromOwner(ownerId: number): IntervalNode[] {
const r1 = this._decorationsTree.collectNodesFromOwner(ownerId);
return r1;
}
public collectNodesPostOrder(): IntervalNode[] {
const r1 = this._decorationsTree.collectNodesPostOrder();
return r1;
}
public insert(node: IntervalNode): void {
this._decorationsTree.insert(node);
}
public delete(node: IntervalNode): void {
this._decorationsTree.delete(node);
}
public resolveNode(node: IntervalNode, cachedVersionId: number): void {
this._decorationsTree.resolveNode(node, cachedVersionId);
}
public acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {
this._decorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
}
}
const TRACKED_RANGE_OPTIONS = [
ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }),
ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }),
ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }),
ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }),
];
function _normalizeOptions(options: IModelDecorationOptions): ModelDecorationOptions {
if (options instanceof ModelDecorationOptions) {
return options;
}
return ModelDecorationOptions.createDynamic(options);
}
let MODEL_ID = 0;
export class NotebookViewModel extends Disposable {
private _localStore: DisposableStore = this._register(new DisposableStore());
private _viewCells: CellViewModel[] = [];
......@@ -117,6 +182,12 @@ export class NotebookViewModel extends Disposable {
return this._layoutInfo;
}
private _decorationsTree = new DecorationsTree();
private _decorations: { [decorationId: string]: IntervalNode; } = Object.create(null);
private _lastDecorationId: number = 0;
private readonly _instanceId: string;
public readonly id: string;
constructor(
public viewType: string,
private _model: NotebookEditorModel,
......@@ -128,6 +199,10 @@ export class NotebookViewModel extends Disposable {
) {
super();
MODEL_ID++;
this.id = '$notebookViewModel' + MODEL_ID;
this._instanceId = strings.singleLetterHash(MODEL_ID);
// this._register(this._model.onDidChangeCells(e => {
// this._onDidChangeViewCells.fire({
// synchronous: true,
......@@ -164,10 +239,123 @@ export class NotebookViewModel extends Disposable {
});
}
getViewCellIndex(cell: ICellViewModel) {
getCellIndex(cell: ICellViewModel) {
return this._viewCells.indexOf(cell as CellViewModel);
}
getVersionId() {
return this._model.notebook.versionId;
}
getTrackedRange(id: string): ICellRange | null {
return this.getDecorationRange(id);
}
getDecorationRange(decorationId: string): ICellRange | null {
const node = this._decorations[decorationId];
if (!node) {
return null;
}
const versionId = this.getVersionId();
if (node.cachedVersionId !== versionId) {
this._decorationsTree.resolveNode(node, versionId);
}
if (node.range === null) {
return { start: node.cachedAbsoluteStart - 1, length: node.cachedAbsoluteEnd - node.cachedAbsoluteStart + 1 };
}
return { start: node.range.startLineNumber - 1, length: node.range.endLineNumber - node.range.startLineNumber + 1 };
}
setTrackedRange(id: string | null, newRange: ICellRange | null, newStickiness: TrackedRangeStickiness): string | null {
const node = (id ? this._decorations[id] : null);
if (!node) {
if (!newRange) {
return null;
}
return this._deltaCellDecorationsImpl(0, [], [{ range: new Range(newRange.start + 1, 1, newRange.start + newRange.length, 1), options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0];
}
if (!newRange) {
// node exists, the request is to delete => delete node
this._decorationsTree.delete(node);
delete this._decorations[node.id];
return null;
}
this._decorationsTree.delete(node);
node.reset(this.getVersionId(), newRange.start, newRange.start + newRange.length, new Range(newRange.start + 1, 1, newRange.start + newRange.length, 1));
node.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]);
this._decorationsTree.insert(node);
return node.id;
}
private _deltaCellDecorationsImpl(ownerId: number, oldDecorationsIds: string[], newDecorations: IModelDeltaDecoration[]): string[] {
const versionId = this.getVersionId();
const oldDecorationsLen = oldDecorationsIds.length;
let oldDecorationIndex = 0;
const newDecorationsLen = newDecorations.length;
let newDecorationIndex = 0;
let result = new Array<string>(newDecorationsLen);
while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {
let node: IntervalNode | null = null;
if (oldDecorationIndex < oldDecorationsLen) {
// (1) get ourselves an old node
do {
node = this._decorations[oldDecorationsIds[oldDecorationIndex++]];
} while (!node && oldDecorationIndex < oldDecorationsLen);
// (2) remove the node from the tree (if it exists)
if (node) {
this._decorationsTree.delete(node);
// this._onDidChangeDecorations.checkAffectedAndFire(node.options);
}
}
if (newDecorationIndex < newDecorationsLen) {
// (3) create a new node if necessary
if (!node) {
const internalDecorationId = (++this._lastDecorationId);
const decorationId = `${this._instanceId};${internalDecorationId}`;
node = new IntervalNode(decorationId, 0, 0);
this._decorations[decorationId] = node;
}
// (4) initialize node
const newDecoration = newDecorations[newDecorationIndex];
// const range = this._validateRangeRelaxedNoAllocations(newDecoration.range);
const range = newDecoration.range;
const options = _normalizeOptions(newDecoration.options);
// const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
// const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
node.ownerId = ownerId;
node.reset(versionId, range.startLineNumber, range.endLineNumber, Range.lift(range));
node.setOptions(options);
// this._onDidChangeDecorations.checkAffectedAndFire(options);
this._decorationsTree.insert(node);
result[newDecorationIndex] = node.id;
newDecorationIndex++;
} else {
if (node) {
delete this._decorations[node.id];
}
}
}
return result;
}
private _insertCellDelegate(insertIndex: number, insertCell: CellViewModel) {
this._viewCells!.splice(insertIndex, 0, insertCell);
this._model.insertCell(insertCell.model, insertIndex);
......@@ -192,6 +380,7 @@ export class NotebookViewModel extends Disposable {
deleteCell: this._deleteCellDelegate.bind(this)
}));
this._decorationsTree.acceptReplace(index, 0, 1, true);
this._onDidChangeViewCells.fire({ synchronous: synchronous, splices: [[index, 0, [newCell]]] });
return newCell;
}
......@@ -206,6 +395,7 @@ export class NotebookViewModel extends Disposable {
deleteCell: this._deleteCellDelegate.bind(this)
}));
this._decorationsTree.acceptReplace(index, 0, 1, true);
this._onDidChangeViewCells.fire({ synchronous: synchronous, splices: [[index, 0, [newCell]]] });
return newCell;
}
......@@ -223,6 +413,9 @@ export class NotebookViewModel extends Disposable {
}
}));
this._decorationsTree.acceptReplace(index, 1, 0, true);
this._onDidChangeViewCells.fire({ synchronous: synchronous, splices: [[index, 1, []]] });
viewCell.dispose();
}
......
......@@ -31,6 +31,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
private _isUntitled: boolean | undefined = undefined;
private _versionId = 0;
get versionId() {
return this._versionId;
}
constructor(
public handle: number,
public viewType: string,
......
......@@ -173,6 +173,7 @@ export interface INotebookTextModel {
viewType: string;
// metadata: IMetadata;
readonly uri: URI;
readonly versionId: number;
languages: string[];
cells: ICell[];
renderers: Set<number>;
......
......@@ -8,12 +8,14 @@ import { URI } from 'vs/base/common/uri';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, NotebookCellMetadata, diff } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { withTestNotebook, TestCell } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { TrackedRangeStickiness } from 'vs/editor/common/model';
import { reduceCellRanges, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
suite('NotebookViewModel', () => {
const instantiationService = new TestInstantiationService();
......@@ -45,12 +47,12 @@ suite('NotebookViewModel', () => {
const cell = viewModel.insertCell(1, new TestCell(viewModel.viewType, 0, ['var c = 3;'], 'javascript', CellKind.Code, []), true);
assert.equal(viewModel.viewCells.length, 3);
assert.equal(viewModel.notebookDocument.cells.length, 3);
assert.equal(viewModel.getViewCellIndex(cell), 1);
assert.equal(viewModel.getCellIndex(cell), 1);
viewModel.deleteCell(1, true);
assert.equal(viewModel.viewCells.length, 2);
assert.equal(viewModel.notebookDocument.cells.length, 2);
assert.equal(viewModel.getViewCellIndex(cell), -1);
assert.equal(viewModel.getCellIndex(cell), -1);
}
);
});
......@@ -68,18 +70,18 @@ suite('NotebookViewModel', () => {
const firstViewCell = viewModel.viewCells[0];
const lastViewCell = viewModel.viewCells[viewModel.viewCells.length - 1];
const insertIndex = viewModel.getViewCellIndex(firstViewCell) + 1;
const insertIndex = viewModel.getCellIndex(firstViewCell) + 1;
const cell = viewModel.insertCell(insertIndex, new TestCell(viewModel.viewType, 3, ['var c = 3;'], 'javascript', CellKind.Code, []), true);
const addedCellIndex = viewModel.getViewCellIndex(cell);
const addedCellIndex = viewModel.getCellIndex(cell);
viewModel.deleteCell(addedCellIndex, true);
const secondInsertIndex = viewModel.getViewCellIndex(lastViewCell) + 1;
const secondInsertIndex = viewModel.getCellIndex(lastViewCell) + 1;
const cell2 = viewModel.insertCell(secondInsertIndex, new TestCell(viewModel.viewType, 4, ['var d = 4;'], 'javascript', CellKind.Code, []), true);
assert.equal(viewModel.viewCells.length, 3);
assert.equal(viewModel.notebookDocument.cells.length, 3);
assert.equal(viewModel.getViewCellIndex(cell2), 2);
assert.equal(viewModel.getCellIndex(cell2), 2);
}
);
});
......@@ -178,3 +180,184 @@ suite('NotebookViewModel', () => {
);
});
});
function getVisibleCells(cells: any[], hiddenRanges: ICellRange[]) {
if (!hiddenRanges.length) {
return cells;
}
let start = 0;
let hiddenRangeIndex = 0;
let result: any[] = [];
while (start < cells.length && hiddenRangeIndex < hiddenRanges.length) {
if (start < hiddenRanges[hiddenRangeIndex].start) {
result.push(...cells.slice(start, hiddenRanges[hiddenRangeIndex].start));
}
start = hiddenRanges[hiddenRangeIndex].start + hiddenRanges[hiddenRangeIndex].length;
hiddenRangeIndex++;
}
if (start < cells.length) {
result.push(...cells.slice(start));
}
return result;
}
suite('NotebookViewModel Decorations', () => {
const instantiationService = new TestInstantiationService();
const blukEditService = instantiationService.get(IBulkEditService);
const undoRedoService = instantiationService.stub(IUndoRedoService, () => { });
instantiationService.spy(IUndoRedoService, 'pushElement');
test('tracking range', function () {
withTestNotebook(
instantiationService,
blukEditService,
undoRedoService,
[
[['var a = 1;'], 'javascript', CellKind.Code, [], {}],
[['var b = 2;'], 'javascript', CellKind.Code, [], { editable: true, runnable: true }],
[['var c = 3;'], 'javascript', CellKind.Code, [], { editable: true, runnable: false }],
[['var d = 4;'], 'javascript', CellKind.Code, [], { editable: false, runnable: true }],
[['var e = 5;'], 'javascript', CellKind.Code, [], { editable: false, runnable: false }],
],
(editor, viewModel) => {
const trackedId = viewModel.setTrackedRange('test', { start: 1, length: 2 }, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 2
});
viewModel.insertCell(0, new TestCell(viewModel.viewType, 5, ['var d = 6;'], 'javascript', CellKind.Code, []), true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 2,
length: 2
});
viewModel.deleteCell(0, true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 2
});
viewModel.insertCell(3, new TestCell(viewModel.viewType, 6, ['var d = 7;'], 'javascript', CellKind.Code, []), true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 3
});
viewModel.deleteCell(3, true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 2
});
viewModel.deleteCell(1, true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 0,
length: 2
});
}
);
});
test('tracking range 2', function () {
withTestNotebook(
instantiationService,
blukEditService,
undoRedoService,
[
[['var a = 1;'], 'javascript', CellKind.Code, [], {}],
[['var b = 2;'], 'javascript', CellKind.Code, [], { editable: true, runnable: true }],
[['var c = 3;'], 'javascript', CellKind.Code, [], { editable: true, runnable: false }],
[['var d = 4;'], 'javascript', CellKind.Code, [], { editable: false, runnable: true }],
[['var e = 5;'], 'javascript', CellKind.Code, [], { editable: false, runnable: false }],
[['var e = 6;'], 'javascript', CellKind.Code, [], { editable: false, runnable: false }],
[['var e = 7;'], 'javascript', CellKind.Code, [], { editable: false, runnable: false }],
],
(editor, viewModel) => {
const trackedId = viewModel.setTrackedRange('test', { start: 1, length: 3 }, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 3
});
viewModel.insertCell(5, new TestCell(viewModel.viewType, 8, ['var d = 9;'], 'javascript', CellKind.Code, []), true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 3
});
viewModel.insertCell(4, new TestCell(viewModel.viewType, 9, ['var d = 10;'], 'javascript', CellKind.Code, []), true);
assert.deepEqual(viewModel.getTrackedRange(trackedId!), {
start: 1,
length: 4
});
}
);
});
test('reduce range', function () {
assert.deepEqual(reduceCellRanges([
{ start: 0, length: 2 },
{ start: 1, length: 2 },
{ start: 4, length: 2 }
]), [
{ start: 0, length: 3 },
{ start: 4, length: 2 }
]);
assert.deepEqual(reduceCellRanges([
{ start: 0, length: 2 },
{ start: 1, length: 2 },
{ start: 3, length: 2 }
]), [
{ start: 0, length: 5 }
]);
});
test('diff hidden ranges', function () {
assert.deepEqual(getVisibleCells([1, 2, 3, 4, 5], []), [1, 2, 3, 4, 5]);
assert.deepEqual(
getVisibleCells(
[1, 2, 3, 4, 5],
[{ start: 1, length: 2 }]
),
[1, 4, 5]
);
assert.deepEqual(
getVisibleCells(
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[
{ start: 1, length: 2 },
{ start: 4, length: 2 }
]
),
[1, 4, 7, 8, 9]
);
const original = getVisibleCells(
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[
{ start: 1, length: 2 },
{ start: 4, length: 2 }
]
);
const modified = getVisibleCells(
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[
{ start: 2, length: 3 }
]
);
assert.deepEqual(diff<number>(original, modified, (a) => {
return original.indexOf(a) >= 0;
}), [{ start: 1, deleteCount: 1, toInsert: [2, 6] }]);
});
});
......@@ -9,7 +9,7 @@ import { CellKind, IOutput, CellUri, NotebookCellMetadata } from 'vs/workbench/c
import { NotebookViewModel, IModelDecorationsChangeAccessor, CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookEditor, NotebookLayoutInfo, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, NotebookLayoutInfo, ICellViewModel, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
......@@ -49,6 +49,11 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
setHiddenAreas(_ranges: ICellRange[]): boolean {
throw new Error('Method not implemented.');
}
getInnerWebview(): Webview | undefined {
throw new Error('Method not implemented.');
}
......
......@@ -544,6 +544,10 @@ export class TerminalLinkManager extends DisposableStore {
return null;
}
link = this.osPath.join(this._processCwd, link);
} else {
// Remove \\?\ from paths so that they share the same underlying
// uri and don't open multiple tabs for the same file
link = link.replace(/^\\\\\?\\/, '');
}
} else {
if (!this._processCwd) {
......
......@@ -254,6 +254,7 @@ suite('Workbench - TerminalLinkHandler', () => {
assert.equal(linkHandler.preprocessPath('~/src/file3'), 'C:\\Users\\Me\\src\\file3');
assert.equal(linkHandler.preprocessPath('~\\src\\file4'), 'C:\\Users\\Me\\src\\file4');
assert.equal(linkHandler.preprocessPath('C:\\absolute\\path\\file5'), 'C:\\absolute\\path\\file5');
assert.equal(linkHandler.preprocessPath('\\\\?\\C:\\absolute\\path\\extended\\file6'), 'C:\\absolute\\path\\extended\\file6');
});
test('Windows - spaces', () => {
const linkHandler = new TestTerminalLinkManager(new TestXterm() as any, {
......
......@@ -28,7 +28,7 @@ import { readFileSync, statSync } from 'fs';
import { detectEncodingByBOM } from 'vs/base/test/node/encoding/encoding.test';
import { workbenchInstantiationService, TestNativeTextFileServiceWithEncodingOverrides } from 'vs/workbench/test/electron-browser/workbenchTestServices';
suite('Files - TextFileService i/o', () => {
suite('Files - TextFileService i/o', function () {
const parentDir = getRandomTestPath(tmpdir(), 'vsctests', 'textfileservice');
const disposables = new DisposableStore();
......@@ -36,6 +36,14 @@ suite('Files - TextFileService i/o', () => {
let service: ITextFileService;
let testDir: string;
// Given issues such as https://github.com/microsoft/vscode/issues/78602
// and https://github.com/microsoft/vscode/issues/92334 we see random test
// failures when accessing the native file system. To diagnose further, we
// retry node.js file access tests up to 3 times to rule out any random disk
// issue and increase the timeout.
this.retries(3);
this.timeout(1000 * 10);
setup(async () => {
const instantiationService = workbenchInstantiationService();
......
......@@ -8224,10 +8224,10 @@ semver-greatest-satisfied-range@^1.1.0:
dependencies:
sver-compat "^1.5.0"
semver-umd@^5.5.5:
version "5.5.5"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.5.tgz#a2e4280d0e92a2b27695c18811f0e939e144d86f"
integrity sha512-8rUq0nnTzlexpAdYmm8UDYsLkBn0MnBkfrGWPmyDBDDzv71dPOH07szOOaLj/5hO3BYmumYwS+wp3C60zLzh5g==
semver-umd@^5.5.6:
version "5.5.6"
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
version "5.4.1"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册