From 07f4e584267183a9ed1d4fc23a4e3f306a2b6286 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Jun 2018 11:40:21 +0200 Subject: [PATCH 1/4] fix #51001 --- .../src/singlefolder-tests/window.test.ts | 50 ++++++++++++++++++ src/vs/vscode.d.ts | 51 +++++++++++++++---- .../api/node/extHostTypeConverters.ts | 30 +++++------ src/vs/workbench/api/node/extHostTypes.ts | 9 +++- src/vs/workbench/api/shared/editor.ts | 18 +++---- 5 files changed, 118 insertions(+), 40 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index 1d73c5056e5d6..3e727449d2cc1 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -156,6 +156,56 @@ suite('window namespace tests', () => { assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); }); + test('showTextDocument ViewColumn.BESIDE', async () => { + const [docA, docB, docC] = await Promise.all([ + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()) + ]); + + await window.showTextDocument(docA, ViewColumn.One); + await window.showTextDocument(docB, ViewColumn.Beside); + + assert.ok(window.activeTextEditor); + assert.ok(window.activeTextEditor!.document === docB); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + + await window.showTextDocument(docC, ViewColumn.Beside); + + assert.ok(window.activeTextEditor!.document === docC); + assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Three); + }); + + test('showTextDocument ViewColumn is always defined (even when opening > ViewColumn.Nine)', async () => { + const [doc1, doc2, doc3, doc4, doc5, doc6, doc7, doc8, doc9, doc10] = await Promise.all([ + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()), + workspace.openTextDocument(await createRandomFile()) + ]); + + await window.showTextDocument(doc1, ViewColumn.One); + await window.showTextDocument(doc2, ViewColumn.Two); + await window.showTextDocument(doc3, ViewColumn.Three); + await window.showTextDocument(doc4, ViewColumn.Four); + await window.showTextDocument(doc5, ViewColumn.Five); + await window.showTextDocument(doc6, ViewColumn.Six); + await window.showTextDocument(doc7, ViewColumn.Seven); + await window.showTextDocument(doc8, ViewColumn.Eight); + await window.showTextDocument(doc9, ViewColumn.Nine); + await window.showTextDocument(doc10, ViewColumn.Beside); + + assert.ok(window.activeTextEditor); + assert.ok(window.activeTextEditor!.document === doc10); + assert.equal(window.activeTextEditor!.viewColumn, 10); + }); + test('issue #27408 - showTextDocument & vscode.diff always default to ViewColumn.One', async () => { const [docA, docB, docC] = await Promise.all([ workspace.openTextDocument(await createRandomFile()), diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index a21705d911f87..ad9303e090e9c 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -754,7 +754,8 @@ declare module 'vscode' { * An optional view column in which the [editor](#TextEditor) should be shown. * The default is the [active](#ViewColumn.Active), other values are adjusted to * be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is - * not adjusted. + * not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) to open the + * editor to the side of the currently active one. */ viewColumn?: ViewColumn; @@ -4016,17 +4017,23 @@ declare module 'vscode' { } /** - * Denotes a column in the editor window. Columns are - * used to show editors side by side. + * Denotes a location of an editor in the window. Editors can be arranged in a grid + * and each column represents one editor location in that grid by counting the editors + * in order of their appearance. */ export enum ViewColumn { /** - * A *symbolic* editor column representing the currently - * active column. This value can be used when opening editors, but the - * *resolved* [viewColumn](#TextEditor.viewColumn)-value of editors will always - * be `One`, `Two`, `Three`, or `undefined` but never `Active`. + * A *symbolic* editor column representing the currently active column. This value + * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Active`. */ Active = -1, + /** + * A *symbolic* editor column representing the column to the side of the active one. This value + * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Beside`. + */ + Beside = -2, /** * The first editor column. */ @@ -4038,7 +4045,31 @@ declare module 'vscode' { /** * The third editor column. */ - Three = 3 + Three = 3, + /** + * The fourth editor column. + */ + Four = 4, + /** + * The fifth editor column. + */ + Five = 5, + /** + * The sixth editor column. + */ + Six = 6, + /** + * The seventh editor column. + */ + Seven = 7, + /** + * The eighth editor column. + */ + Eight = 8, + /** + * The ninth editor column. + */ + Nine = 9 } /** @@ -5646,8 +5677,8 @@ declare module 'vscode' { * * @param document A text document to be shown. * @param column A view column in which the [editor](#TextEditor) should be shown. The default is the [active](#ViewColumn.Active), other values - * are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is - * not adjusted. + * are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) + * to open the editor to the side of the currently active one. * @param preserveFocus When `true` the editor will not take focus. * @return A promise that resolves to an [editor](#TextEditor). */ diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 3ee9ba84150c5..c5a8fa1d3bfd9 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -23,6 +23,7 @@ import { IRelativePattern } from 'vs/base/common/glob'; import * as languageSelector from 'vs/editor/common/modes/languageSelector'; import { WorkspaceEditDto, ResourceTextEditDto } from 'vs/workbench/api/node/extHost.protocol'; import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers'; +import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; export interface PositionLike { line: number; @@ -159,29 +160,22 @@ export namespace DiagnosticSeverity { export namespace ViewColumn { export function from(column?: vscode.ViewColumn): EditorViewColumn { - let editorColumn: EditorViewColumn; - if (column === types.ViewColumn.One) { - editorColumn = 0; - } else if (column === types.ViewColumn.Two) { - editorColumn = 1; - } else if (column === types.ViewColumn.Three) { - editorColumn = 2; - } else { - // in any other case (no column or ViewColumn.Active), leave the - // editorColumn as undefined which signals to use the active column - editorColumn = undefined; + if (typeof column === 'number' && column >= types.ViewColumn.One) { + return column - 1; // adjust zero index (ViewColumn.ONE => 0) + } + + if (column === types.ViewColumn.Beside) { + return SIDE_GROUP; } - return editorColumn; + + return ACTIVE_GROUP; // default is always the active group } export function to(position?: EditorViewColumn): vscode.ViewColumn { - if (position === 0) { - return types.ViewColumn.One; - } else if (position === 1) { - return types.ViewColumn.Two; - } else if (position === 2) { - return types.ViewColumn.Three; + if (typeof position === 'number' && position >= 0) { + return position + 1; // adjust to index (ViewColumn.ONE => 1) } + return undefined; } } diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 45d1aae95b7c8..d706eac34450f 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1120,9 +1120,16 @@ export class CompletionList { export enum ViewColumn { Active = -1, + Beside = -2, One = 1, Two = 2, - Three = 3 + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9 } export enum StatusBarAlignment { diff --git a/src/vs/workbench/api/shared/editor.ts b/src/vs/workbench/api/shared/editor.ts index 7c537a8edd0bb..6faf61d10634e 100644 --- a/src/vs/workbench/api/shared/editor.ts +++ b/src/vs/workbench/api/shared/editor.ts @@ -9,18 +9,14 @@ import { IEditorGroupsService, IEditorGroup, GroupsOrder } from 'vs/workbench/se import { GroupIdentifier } from 'vs/workbench/common/editor'; import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -// TODO@api this was previously a hardcoded list of editor positions (ONE, TWO, THREE) -// that with the introduction of grid editor feature is now unbounded. This should be -// revisited when the grid functionality is exposed to extensions, - export type EditorViewColumn = number; export function viewColumnToEditorGroup(editorGroupService: IEditorGroupsService, position?: EditorViewColumn): GroupIdentifier { - if (typeof position !== 'number') { - return ACTIVE_GROUP; // prefer active group when position is undefined + if (typeof position !== 'number' || position === ACTIVE_GROUP) { + return ACTIVE_GROUP; // prefer active group when position is undefined or passed in as such } - const groups = editorGroupService.getGroups(GroupsOrder.CREATION_TIME); + const groups = editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE); let candidate = groups[position]; if (candidate) { @@ -29,14 +25,14 @@ export function viewColumnToEditorGroup(editorGroupService: IEditorGroupsService let firstGroup = groups[0]; if (groups.length === 1 && firstGroup.count === 0) { - return firstGroup.id; // first editor should always open in first group + return firstGroup.id; // first editor should always open in first group independent from position provided } - return SIDE_GROUP; // open to the side if group not found + return SIDE_GROUP; // open to the side if group not found or we are instructed to } export function editorGroupToViewColumn(editorGroupService: IEditorGroupsService, editorGroup: IEditorGroup | GroupIdentifier): EditorViewColumn { - const group = typeof editorGroup === 'number' ? editorGroupService.getGroup(editorGroup) : editorGroup; + const group = (typeof editorGroup === 'number') ? editorGroupService.getGroup(editorGroup) : editorGroup; - return editorGroupService.getGroups(GroupsOrder.CREATION_TIME).indexOf(group); + return editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE).indexOf(group); } \ No newline at end of file From c7f9a7a97011bdca4d10a6a96249796e14585b0c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Jun 2018 12:10:38 +0200 Subject: [PATCH 2/4] add onDidChangeTextEditorViewColumn test that validates moving editor group --- .../src/singlefolder-tests/window.test.ts | 47 ++++++++++++++++++- .../api/electron-browser/mainThreadEditors.ts | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index 3e727449d2cc1..d57851e58af20 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -81,7 +81,7 @@ suite('window namespace tests', () => { }); }); - test('editor, onDidChangeTextEditorViewColumn', () => { + test('editor, onDidChangeTextEditorViewColumn (close editor)', () => { let actualEvent: TextEditorViewColumnChangeEvent; @@ -119,6 +119,51 @@ suite('window namespace tests', () => { }); }); + test('editor, onDidChangeTextEditorViewColumn (move editor group)', () => { + + let actualEvents: TextEditorViewColumnChangeEvent[] = []; + + let registration1 = workspace.registerTextDocumentContentProvider('bikes', { + provideTextDocumentContent() { + return 'mountainbiking,roadcycling'; + } + }); + + return Promise.all([ + workspace.openTextDocument(Uri.parse('bikes://testing/one')).then(doc => window.showTextDocument(doc, ViewColumn.One)), + workspace.openTextDocument(Uri.parse('bikes://testing/two')).then(doc => window.showTextDocument(doc, ViewColumn.Two)) + ]).then(editors => { + + let [, two] = editors; + two.show(); + + return new Promise(resolve => { + + let registration2 = window.onDidChangeTextEditorViewColumn(event => { + actualEvents.push(event); + + if (actualEvents.length === 2) { + registration2.dispose(); + resolve(); + } + }); + + // move active editor group left + return commands.executeCommand('workbench.action.moveActiveEditorGroupLeft'); + + }).then(() => { + assert.equal(actualEvents.length, 2); + + for (let i = 0; i < actualEvents.length; i++) { + const event = actualEvents[i]; + assert.equal(event.viewColumn, event.textEditor.viewColumn); + } + + registration1.dispose(); + }); + }); + }); + test('active editor not always correct... #49125', async function () { const [docA, docB] = await Promise.all([ workspace.openTextDocument(await createRandomFile()), diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts index 2e3c3bbf63081..737c5de4d2507 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts @@ -56,6 +56,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { this._toDispose.push(this._editorService.onDidVisibleEditorsChange(() => this._updateActiveAndVisibleTextEditors())); this._toDispose.push(this._editorGroupService.onDidRemoveGroup(() => this._updateActiveAndVisibleTextEditors())); + this._toDispose.push(this._editorGroupService.onDidMoveGroup(() => this._updateActiveAndVisibleTextEditors())); this._registeredDecorationTypes = Object.create(null); } From 5399d6308883664eb2833458d150445f3d19ffb6 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Jun 2018 15:34:28 +0200 Subject: [PATCH 3/4] adopt vscode.ViewColumn.Beside --- .../src/commands/showPreview.ts | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/extensions/markdown-language-features/src/commands/showPreview.ts b/extensions/markdown-language-features/src/commands/showPreview.ts index c522c2b5ddc35..3c4873ba42495 100644 --- a/extensions/markdown-language-features/src/commands/showPreview.ts +++ b/extensions/markdown-language-features/src/commands/showPreview.ts @@ -10,27 +10,6 @@ import { MarkdownPreviewManager } from '../features/previewManager'; import { TelemetryReporter } from '../telemetryReporter'; import { PreviewSettings } from '../features/preview'; - -function getViewColumn(sideBySide: boolean): vscode.ViewColumn | undefined { - const active = vscode.window.activeTextEditor; - if (!active) { - return vscode.ViewColumn.One; - } - - if (!sideBySide) { - return active.viewColumn; - } - - switch (active.viewColumn) { - case vscode.ViewColumn.One: - return vscode.ViewColumn.Two; - case vscode.ViewColumn.Two: - return vscode.ViewColumn.Three; - } - - return active.viewColumn; -} - interface ShowPreviewSettings { readonly sideBySide?: boolean; readonly locked?: boolean; @@ -61,7 +40,7 @@ async function showPreview( webviewManager.preview(resource, { resourceColumn: (vscode.window.activeTextEditor && vscode.window.activeTextEditor.viewColumn) || vscode.ViewColumn.One, - previewColumn: getViewColumn(!!previewSettings.sideBySide) || vscode.ViewColumn.Active, + previewColumn: previewSettings.sideBySide ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active, locked: !!previewSettings.locked }); From 6acff660c932708dc5b65f63e50e816525effb34 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 14 Jun 2018 16:56:34 +0200 Subject: [PATCH 4/4] add vscode.setEditorLayout command --- src/vs/workbench/api/node/apiCommands.ts | 9 +++++++++ src/vs/workbench/api/node/extHostApiCommands.ts | 10 +++++++++- .../services/group/common/editorGroupsService.ts | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/node/apiCommands.ts b/src/vs/workbench/api/node/apiCommands.ts index 5be2fe4cba70f..049f955bb8b98 100644 --- a/src/vs/workbench/api/node/apiCommands.ts +++ b/src/vs/workbench/api/node/apiCommands.ts @@ -10,6 +10,7 @@ import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters'; import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { EditorViewColumn } from 'vs/workbench/api/shared/editor'; +import { EditorGroupLayout } from 'vs/workbench/services/group/common/editorGroupsService'; // ----------------------------------------------------------------- // The following commands are registered on both sides separately. @@ -98,3 +99,11 @@ export class RemoveFromRecentlyOpenedAPICommand { } } CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute)); + +export class SetEditorLayoutAPICommand { + public static ID = 'vscode.setEditorLayout'; + public static execute(executor: ICommandsExecutor, layout: EditorGroupLayout): Thenable { + return executor.executeCommand('layoutEditorGroups', layout); + } +} +CommandsRegistry.registerCommand(SetEditorLayoutAPICommand.ID, adjustHandler(SetEditorLayoutAPICommand.execute)); \ No newline at end of file diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index 0a62b6f803125..3ff0a6186c004 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -17,7 +17,8 @@ import * as search from 'vs/workbench/parts/search/common/search'; import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures'; -import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand } from './apiCommands'; +import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands'; +import { EditorGroupLayout } from 'vs/workbench/services/group/common/editorGroupsService'; export class ExtHostApiCommands { @@ -249,6 +250,13 @@ export class ExtHostApiCommands { { name: 'path', description: 'Path to remove from recently opened.', constraint: (value: any) => typeof value === 'string' } ] }); + + this._register(SetEditorLayoutAPICommand.ID, adjustHandler(SetEditorLayoutAPICommand.execute), { + description: 'Sets the editor layout. The layout is described as object with an initial (optional) orientation (0 = horizontal, 1 = vertical) and an array of editor groups within. Each editor group can have a size and another array of editor groups that will be layed out orthogonal to the orientation. If editor group sizes are provided, their sum must be 1 to be applied per row or column. Example for a 2x2 grid: `{ orientation: 0, groups: [{ groups: [{}, {}], size: 0.5 }, { groups: [{}, {}], size: 0.5 }] }`', + args: [ + { name: 'layout', description: 'The editor layout to set.', constraint: (value: EditorGroupLayout) => typeof value === 'object' && Array.isArray(value.groups) } + ] + }); } // --- command impl diff --git a/src/vs/workbench/services/group/common/editorGroupsService.ts b/src/vs/workbench/services/group/common/editorGroupsService.ts index 138849ffa8e3a..dc1595f47d16d 100644 --- a/src/vs/workbench/services/group/common/editorGroupsService.ts +++ b/src/vs/workbench/services/group/common/editorGroupsService.ts @@ -64,7 +64,7 @@ export enum GroupsArrangement { export interface GroupLayoutArgument { size?: number; - groups?: Array; + groups?: GroupLayoutArgument[]; } export interface EditorGroupLayout {