Skip to content

Commit

Permalink
Pin tabs similar to Visual Studio
Browse files Browse the repository at this point in the history
  • Loading branch information
teintinu committed May 24, 2017
1 parent 921107c commit ac017d6
Show file tree
Hide file tree
Showing 56 changed files with 521 additions and 325 deletions.
8 changes: 7 additions & 1 deletion src/vs/platform/editor/common/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ export enum Verbosity {
LONG
}

export enum Pinned {
NO,
SOFT,
HARD
}

export interface IEditorInput extends IDisposable {

onDispose: Event<void>;
Expand Down Expand Up @@ -257,7 +263,7 @@ export interface IEditorOptions {
* An editor that is pinned remains in the editor stack even when another editor is being opened.
* An editor that is not pinned will always get replaced by another editor that is not pinned.
*/
pinned?: boolean;
pinned?: Pinned;

/**
* The index in the document stack where to insert the editor into when opening.
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';

import { IMarkerData } from 'vs/platform/markers/common/markers';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { Position as EditorPosition, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
Expand Down Expand Up @@ -176,7 +176,7 @@ export interface IApplyEditsOptions extends IUndoStopOptions {
export interface ITextDocumentShowOptions {
position?: EditorPosition;
preserveFocus?: boolean;
pinned?: boolean;
pinned?: EditorPinned;
}

export abstract class MainThreadEditorsShape {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/node/extHostApiCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { IOutline } from 'vs/editor/contrib/quickOpen/common/quickOpen';
import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import { ICodeLensData } from 'vs/editor/contrib/codelens/common/codelens';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorOptions, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';

export class ExtHostApiCommands {

Expand Down Expand Up @@ -209,7 +209,7 @@ export class ExtHostApiCommands {
let editorOptions: IEditorOptions;
if (options) {
editorOptions = {
pinned: !options.preview,
pinned: options.preview ? EditorPinned.SOFT : EditorPinned.NO,
preserveFocus: options.preserveFocus
};
}
Expand Down
8 changes: 4 additions & 4 deletions src/vs/workbench/api/node/extHostTextEditors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { TextEditorSelectionChangeKind } from './extHostTypes';
import * as TypeConverters from './extHostTypeConverters';
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { Position as EditorPosition, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './extHost.protocol';
import * as vscode from 'vscode';

Expand Down Expand Up @@ -64,19 +64,19 @@ export class ExtHostEditors extends ExtHostEditorsShape {
options = {
position: TypeConverters.fromViewColumn(columnOrOptions),
preserveFocus: preserveFocus,
pinned: true
pinned: EditorPinned.SOFT
};
} else if (typeof columnOrOptions === 'object') {
options = {
position: TypeConverters.fromViewColumn(columnOrOptions.viewColumn),
preserveFocus: columnOrOptions.preserveFocus,
pinned: columnOrOptions.preview === undefined ? true : !columnOrOptions.preview
pinned: (columnOrOptions.preview === undefined || !columnOrOptions.preview) ? EditorPinned.SOFT : EditorPinned.NO
};
} else {
options = {
position: EditorPosition.ONE,
preserveFocus: false,
pinned: true
pinned: EditorPinned.SOFT
};
}

Expand Down
9 changes: 5 additions & 4 deletions src/vs/workbench/browser/fileResultsNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { Throttler } from 'vs/base/common/async';
import Event, { Emitter } from 'vs/base/common/event';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorOptions, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';
import { ITree } from 'vs/base/parts/tree/browser/tree';

export interface IOpenFileOptions {
Expand Down Expand Up @@ -36,7 +36,7 @@ export default class FileResultsNavigation extends Disposable {
this._openFile.fire({
editorOptions: {
preserveFocus: true,
pinned: false,
pinned: EditorPinned.NO,
revealIfVisible: true
},
sideBySide: false,
Expand All @@ -52,13 +52,14 @@ export default class FileResultsNavigation extends Disposable {
let keyboard = payload && payload.origin === 'keyboard';
let originalEvent: KeyboardEvent | MouseEvent = payload && payload.originalEvent;

let pinned = (payload && payload.origin === 'mouse' && originalEvent && originalEvent.detail === 2);
let pinned = (payload && payload.origin === 'mouse' && originalEvent && originalEvent.detail === 2) ? EditorPinned.SOFT
: EditorPinned.NO;
if (pinned && originalEvent) {
originalEvent.preventDefault(); // focus moves to editor, we need to prevent default
}

let sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey));
let preserveFocus = !((keyboard && (!payload || !payload.preserveFocus)) || pinned || (payload && payload.focusEditor));
let preserveFocus = !((keyboard && (!payload || !payload.preserveFocus)) || pinned !== EditorPinned.NO || (payload && payload.focusEditor));
this._openFile.fire({
editorOptions: {
preserveFocus,
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/browser/parts/editor/editor.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import {
CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, KeepEditorAction, CloseOtherEditorsInGroupAction, OpenToSideAction, RevertAndCloseEditorAction,
CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, CloseAllButPinnedAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, KeepEditorAction, CloseOtherEditorsInGroupAction, OpenToSideAction, RevertAndCloseEditorAction,
NavigateBetweenGroupsAction, FocusActiveGroupAction, FocusFirstGroupAction, FocusSecondGroupAction, FocusThirdGroupAction, EvenGroupWidthsAction, MaximizeGroupAction, MinimizeOtherGroupsAction, FocusPreviousGroup, FocusNextGroup, ShowEditorsInGroupOneAction,
toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_GROUP_ONE_PREFIX,
OpenPreviousEditorFromHistoryAction, ShowAllEditorsAction, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, ClearEditorHistoryAction, ShowEditorsInGroupTwoAction, MoveEditorRightInGroupAction, OpenNextEditorInGroup, OpenPreviousEditorInGroup, OpenNextRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction,
Expand Down Expand Up @@ -329,7 +329,8 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditor, Op
registry.registerWorkbenchAction(new SyncActionDescriptor(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'View: Clear Recent Files', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(KeepEditorAction, KeepEditorAction.ID, KeepEditorAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter) }), 'View: Keep Editor', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL), 'View: Close All Editors', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllButPinnedAction, CloseAllButPinnedAction.ID, CloseAllButPinnedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All But Pinned', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseRightEditorsInGroupAction, CloseRightEditorsInGroupAction.ID, CloseRightEditorsInGroupAction.LABEL), 'View: Close Editors to the Right', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseEditorsInGroupAction, CloseEditorsInGroupAction.ID, CloseEditorsInGroupAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_W) }), 'View: Close All Editors in Group', category);
Expand Down
87 changes: 77 additions & 10 deletions src/vs/workbench/browser/parts/editor/editorActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry,
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { Position, IEditor, Direction, IResourceInput, IEditorInput, POSITIONS } from 'vs/platform/editor/common/editor';
import { Position, IEditor, Direction, IResourceInput, IEditorInput, POSITIONS, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
Expand Down Expand Up @@ -64,7 +64,7 @@ export class SplitEditorAction extends Action {
} else {
options = new EditorOptions();
}
options.pinned = true;
options.pinned = EditorPinned.SOFT;

// Count editors
const visibleEditors = this.editorService.getVisibleEditors();
Expand Down Expand Up @@ -316,9 +316,9 @@ export abstract class BaseFocusSideGroupAction extends Action {
let options: EditorOptions;
const codeEditor = getCodeEditor(referenceEditor);
if (codeEditor) {
options = TextEditorOptions.fromEditor(codeEditor, { pinned: true });
options = TextEditorOptions.fromEditor(codeEditor, { pinned: EditorPinned.SOFT });
} else {
options = EditorOptions.create({ pinned: true });
options = EditorOptions.create({ pinned: EditorPinned.SOFT });
}

return this.editorService.openEditor(referenceEditor.input, options, this.getTargetEditorSide());
Expand All @@ -332,10 +332,10 @@ export abstract class BaseFocusSideGroupAction extends Action {
// For now only support to open files from history to the side
if (input instanceof EditorInput) {
if (hasResource(input, { filter: ['file', 'untitled'] })) {
return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide());
return this.editorService.openEditor(input, { pinned: EditorPinned.SOFT }, this.getTargetEditorSide());
}
} else {
return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide());
return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: EditorPinned.SOFT } }, this.getTargetEditorSide());
}
}
}
Expand Down Expand Up @@ -676,7 +676,7 @@ export class CloseAllEditorsAction extends Action {

// Just close all if there are no or one dirty editor
if (this.textFileService.getDirty().length < 2) {
return this.editorService.closeAllEditors();
return this.editorService.closeAllEditors(undefined, false);
}

// Otherwise ask for combined confirmation
Expand All @@ -694,7 +694,50 @@ export class CloseAllEditorsAction extends Action {

return saveOrRevertPromise.then(success => {
if (success) {
return this.editorService.closeAllEditors();
return this.editorService.closeAllEditors(undefined, false);
}
return undefined;
});
}
}

export class CloseAllButPinnedAction extends Action {

public static ID = 'workbench.action.closeAllButPinned';
public static LABEL = nls.localize('closeAllButPinned', "Close All But Pinned");

constructor(
id: string,
label: string,
@ITextFileService private textFileService: ITextFileService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super(id, label, 'action-close-all-files');
}

public run(): TPromise<any> {

// Just close all if there are no or one dirty editor
if (this.textFileService.getDirty().length < 2) {
return this.editorService.closeAllEditors(undefined, true);
}

// Otherwise ask for combined confirmation
const confirm = this.textFileService.confirmSave();
if (confirm === ConfirmResult.CANCEL) {
return undefined;
}

let saveOrRevertPromise: TPromise<boolean>;
if (confirm === ConfirmResult.DONT_SAVE) {
saveOrRevertPromise = this.textFileService.revertAll(null, { soft: true }).then(() => true);
} else {
saveOrRevertPromise = this.textFileService.saveAll(true).then(res => res.results.every(r => r.success));
}

return saveOrRevertPromise.then(success => {
if (success) {
return this.editorService.closeAllEditors(undefined, true);
}
return undefined;
});
Expand Down Expand Up @@ -725,7 +768,7 @@ export class CloseEditorsInOtherGroupsAction extends Action {
}

if (typeof position === 'number') {
return this.editorService.closeAllEditors(position);
return this.editorService.closeAllEditors(position, true);
}

return TPromise.as(false);
Expand Down Expand Up @@ -940,7 +983,31 @@ export class KeepEditorAction extends Action {
public run(context?: IEditorContext): TPromise<any> {
const target = getTarget(this.editorService, this.editorGroupService, context);
if (target) {
this.editorGroupService.pinEditor(target.position, target.input);
this.editorGroupService.pinEditor(target.position, target.input, EditorPinned.SOFT);
}

return TPromise.as(true);
}
}

export class PinEditorAction extends Action {

public static ID = 'workbench.action.pinEditor';
public static LABEL = nls.localize('pinEditor', "Pin Editor");

constructor(
id: string,
label: string,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super(id, label);
}

public run(context?: IEditorContext): TPromise<any> {
const target = getTarget(this.editorService, this.editorGroupService, context);
if (target) {
this.editorGroupService.pinEditor(target.position, target.input, EditorPinned.HARD);
}

return TPromise.as(true);
Expand Down
8 changes: 4 additions & 4 deletions src/vs/workbench/browser/parts/editor/editorGroupsControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import errors = require('vs/base/common/errors');
import { RunOnceScheduler } from 'vs/base/common/async';
import { isMacintosh } from 'vs/base/common/platform';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Position, POSITIONS } from 'vs/platform/editor/common/editor';
import { Position, POSITIONS, Pinned as EditorPinned } from 'vs/platform/editor/common/editor';
import { IEditorGroupService, ITabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
Expand Down Expand Up @@ -1050,11 +1050,11 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro

// When moving an editor, try to preserve as much view state as possible by checking
// for th editor to be a text editor and creating the options accordingly if so
let options = EditorOptions.create({ pinned: true });
let options = EditorOptions.create({ pinned: EditorPinned.SOFT });
const activeEditor = $this.editorService.getActiveEditor();
const editor = getCodeEditor(activeEditor);
if (editor && activeEditor.position === stacks.positionOfGroup(identifier.group) && identifier.editor.matches(activeEditor.input)) {
options = TextEditorOptions.fromEditor(editor, { pinned: true });
options = TextEditorOptions.fromEditor(editor, { pinned: EditorPinned.SOFT });
}

return options;
Expand Down Expand Up @@ -1127,7 +1127,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro

// Open in Editor
$this.windowService.focusWindow()
.then(() => editorService.openEditors(droppedResources.map(d => { return { input: { resource: d.resource, options: { pinned: true } }, position: splitEditor ? freeGroup : position }; })))
.then(() => editorService.openEditors(droppedResources.map(d => { return { input: { resource: d.resource, options: { pinned: EditorPinned.SOFT } }, position: splitEditor ? freeGroup : position }; })))
.then(() => {
if (splitEditor && splitTo !== freeGroup) {
groupService.moveGroup(freeGroup, splitTo);
Expand Down
Loading

0 comments on commit ac017d6

Please sign in to comment.