Skip to content
This repository has been archived by the owner on Apr 1, 2020. It is now read-only.

Externalized UI: Implement Oni split mode #1682

Merged
merged 25 commits into from
Mar 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
05916d9
Add split bindings
bryphe Mar 1, 2018
9df5af6
Get tests green again
bryphe Mar 1, 2018
d3c44c2
Get split tests green
bryphe Mar 1, 2018
c8356d9
Add layout logic plus testc ases
bryphe Mar 1, 2018
a41e8f7
Fix lint issues
bryphe Mar 1, 2018
40ad37a
Get oni-splits working end-to-end
bryphe Mar 1, 2018
1d27104
Tweak positioning of splits
bryphe Mar 1, 2018
e45fff1
Add basic window layout algorithm
bryphe Mar 1, 2018
9298188
Fix lint issue
bryphe Mar 1, 2018
c94505a
Fix test issues
bryphe Mar 1, 2018
a5d3ab4
Fix window click behavior
bryphe Mar 1, 2018
0cd19eb
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 1, 2018
61997b3
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 2, 2018
9cd39a9
Fix compilation issue
bryphe Mar 2, 2018
c60b645
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 2, 2018
e63dfcb
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 2, 2018
d2d7958
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 2, 2018
658e770
Fix split direction issue
bryphe Mar 2, 2018
4658ae5
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 2, 2018
d1fe572
Fix lint issue
bryphe Mar 3, 2018
0cefa20
Hook up <C-w>s/<C-w>v bindings for oni.tabs.mode
bryphe Mar 3, 2018
1a85344
Fall back to native splits if editor.split.mode isn't set to oni
bryphe Mar 3, 2018
2bfac82
Merge branch 'master' into bryphe/feature/window-splits-integration
bryphe Mar 3, 2018
88f8b0b
Remove todo
bryphe Mar 3, 2018
b32d8ae
Fix class name for editor
bryphe Mar 3, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 53 additions & 20 deletions browser/src/Editor/OniEditor/OniEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as Log from "./../../Log"
import { PluginManager } from "./../../Plugins/PluginManager"

import { IColors } from "./../../Services/Colors"
import { commandManager } from "./../../Services/CommandManager"
import { CompletionProviders } from "./../../Services/Completion"
import { Configuration } from "./../../Services/Configuration"
import { IDiagnosticsDataSource } from "./../../Services/Diagnostics"
Expand All @@ -45,7 +46,7 @@ import { ErrorsContainer } from "./containers/ErrorsContainer"

import { NeovimEditor } from "./../NeovimEditor"

import { windowManager } from "./../../Services/WindowManager"
import { SplitDirection, windowManager } from "./../../Services/WindowManager"

import { ImageBufferLayer } from "./ImageBufferLayer"

Expand Down Expand Up @@ -165,6 +166,22 @@ export class OniEditor implements IEditor {
this._neovimEditor.enter()

editorManager.setActiveEditor(this)

commandManager.registerCommand({
command: "editor.split.horizontal",
execute: () => this._split("horizontal"),
enabled: () => editorManager.activeEditor === this,
name: null,
detail: null,
})

commandManager.registerCommand({
command: "editor.split.vertical",
execute: () => this._split("vertical"),
enabled: () => editorManager.activeEditor === this,
name: null,
detail: null,
})
}

public leave(): void {
Expand All @@ -182,25 +199,9 @@ export class OniEditor implements IEditor {
openMode === Oni.FileOpenMode.HorizontalSplit ||
openMode === Oni.FileOpenMode.VerticalSplit
) {
const newEditor = new OniEditor(
this._colors,
this._completionProviders,
this._configuration,
this._diagnostics,
this._languageManager,
this._menuManager,
this._overlayManager,
this._pluginManager,
this._snippetManager,
this._tasks,
this._themeManager,
this._tokenColors,
this._workspace,
)

// TODO
windowManager.createSplit("vertical", newEditor)
await newEditor.init([])
const splitDirection =
openMode === Oni.FileOpenMode.HorizontalSplit ? "horizontal" : "vertical"
const newEditor = await this._split(splitDirection)
return newEditor.openFile(file, { openMode: Oni.FileOpenMode.Edit })
}
}
Expand Down Expand Up @@ -251,4 +252,36 @@ export class OniEditor implements IEditor {
public render(): JSX.Element {
return this._neovimEditor.render()
}

private async _split(direction: SplitDirection): Promise<OniEditor> {
if (this._configuration.getValue("editor.split.mode") !== "oni") {
if (direction === "horizontal") {
await this._neovimEditor.neovim.command(":sp")
} else {
await this._neovimEditor.neovim.command(":vsp")
}

return this
}

const newEditor = new OniEditor(
this._colors,
this._completionProviders,
this._configuration,
this._diagnostics,
this._languageManager,
this._menuManager,
this._overlayManager,
this._pluginManager,
this._snippetManager,
this._tasks,
this._themeManager,
this._tokenColors,
this._workspace,
)

windowManager.createSplit(direction, newEditor, this)
await newEditor.init([])
return newEditor
}
}
61 changes: 42 additions & 19 deletions browser/src/Services/WindowManager/LinearSplitProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,27 @@
import {
Direction,
IAugmentedSplitInfo,
ISplitInfo,
IWindowSplitProvider,
SingleSplitProvider,
SplitDirection,
SplitOrLeaf,
} from "./index"

export class LinearSplitProvider implements IWindowSplitProvider {
private _splitProviders: IWindowSplitProvider[] = []
export const getInverseDirection = (splitDirection: SplitDirection): SplitDirection => {
switch (splitDirection) {
case "horizontal":
return "vertical"
case "vertical":
default:
return "horizontal"
}
}

constructor(private _direction: SplitDirection) {}
export class LinearSplitProvider implements IWindowSplitProvider {
constructor(
private _direction: SplitDirection,
private _splitProviders: IWindowSplitProvider[] = [],
) {}

public contains(split: IAugmentedSplitInfo): boolean {
return this._getProviderForSplit(split) != null
Expand Down Expand Up @@ -46,18 +57,16 @@ export class LinearSplitProvider implements IWindowSplitProvider {
direction: SplitDirection,
referenceSplit?: IAugmentedSplitInfo,
): boolean {
// If there are no children, we can just match direction
if (this._splitProviders.length === 0) {
this._direction = getInverseDirection(direction)
this._splitProviders.push(new SingleSplitProvider(split))
return true
}

// If there is no reference split, we can just tack this split on
if (!referenceSplit) {
if (direction === this._direction) {
this._splitProviders.push(new SingleSplitProvider(split))
} else {
const childSplitProvider = new LinearSplitProvider(this._direction)
childSplitProvider._splitProviders = this._splitProviders
this._splitProviders = [childSplitProvider]
this._splitProviders.push(new SingleSplitProvider(split))
this._direction = direction
}

this._splitProviders.push(new SingleSplitProvider(split))
return true
}

Expand All @@ -67,7 +76,7 @@ export class LinearSplitProvider implements IWindowSplitProvider {
return false
}

const result = containingSplit.split(split, direction)
const result = containingSplit.split(split, direction, referenceSplit)

// Containing split handled it, so we're good
if (result) {
Expand All @@ -77,11 +86,25 @@ export class LinearSplitProvider implements IWindowSplitProvider {
// If the split requested is oriented differently,
// create a new provider to handle that
if (direction !== this._direction) {
// TODO
} else {
// Otherwise, we can - let's wrap up the split in a provider
const singleSplitProvider = new SingleSplitProvider(split)
this._splitProviders.push(singleSplitProvider)
} else {
// Otherwise, we can - let's wrap up the split in a provider

const previousIndex = this._splitProviders.indexOf(containingSplit)
const elementsBefore = this._splitProviders.slice(0, previousIndex)
const elementsAfter = this._splitProviders.slice(
previousIndex + 1,
this._splitProviders.length,
)

const children = [containingSplit, new SingleSplitProvider(split)]
const childSplitProvider = new LinearSplitProvider(
getInverseDirection(this._direction),
children,
)

this._splitProviders = [...elementsBefore, childSplitProvider, ...elementsAfter]
}

return true
Expand Down Expand Up @@ -136,7 +159,7 @@ export class LinearSplitProvider implements IWindowSplitProvider {
return this._splitProviders[newIndex].move(null, direction)
}

public getState(): SplitOrLeaf<IAugmentedSplitInfo> {
public getState(): ISplitInfo<IAugmentedSplitInfo> {
return {
type: "Split",
direction: this._direction,
Expand Down
36 changes: 17 additions & 19 deletions browser/src/Services/WindowManager/WindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export class AugmentedWindow implements IAugmentedSplitInfo {

constructor(private _id: string, private _innerSplit: Oni.IWindowSplit | any) {}

public get innerSplit(): Oni.IWindowSplit {
return this._innerSplit
}

public render(): JSX.Element {
return this._innerSplit.render()
}
Expand Down Expand Up @@ -146,27 +150,10 @@ export class WindowManager {
this._rootNavigator.setRelationship(this._leftDock, this._primarySplit, "right")
}

// public split(
// direction: SplitDirection,
// newSplit: Oni.IWindowSplit,
// referenceSplit?: Oni.IWindowSplit,
// ) {

// this._primarySplit.split(augmentedWindow, direction, referenceSplit)
// const newState = this._primarySplit.getState() as ISplitInfo<Oni.IWindowSplit>

// this._store.dispatch({
// type: "SET_PRIMARY_SPLITS",
// splits: newState,
// })

// this._focusNewSplit(newSplit)
// }

public createSplit(
splitLocation: Direction | SplitDirection,
newSplit: Oni.IWindowSplit,
referenceSplit?: any,
referenceSplit?: Oni.IWindowSplit,
): WindowSplitHandle {
const nextId = this._lastId++
const windowId = "oni.window." + nextId.toString()
Expand All @@ -189,7 +176,8 @@ export class WindowManager {
}
case "horizontal":
case "vertical":
this._primarySplit.split(augmentedWindow, splitLocation, referenceSplit)
const augmentedRefSplit = this._getAugmentedWindowSplitFromSplit(referenceSplit)
this._primarySplit.split(augmentedWindow, splitLocation, augmentedRefSplit)
const newState = this._primarySplit.getState() as ISplitInfo<Oni.IWindowSplit>

this._store.dispatch({
Expand All @@ -203,6 +191,11 @@ export class WindowManager {
return new WindowSplitHandle(this._store, this, windowId)
}

public getSplitHandle(split: Oni.IWindowSplit): WindowSplitHandle {
const augmentedSplit = this._getAugmentedWindowSplitFromSplit(split)
return new WindowSplitHandle(this._store, this, augmentedSplit.id)
}

public move(direction: Direction): void {
const focusedSplit = this._store.getState().focusedSplitId

Expand Down Expand Up @@ -259,6 +252,11 @@ export class WindowManager {
this._focusNewSplit(split)
}

private _getAugmentedWindowSplitFromSplit(split: Oni.IWindowSplit): IAugmentedSplitInfo {
const augmentedWindows = Object.values(this._idToSplit)
return augmentedWindows.find(aw => aw.innerSplit === split) || null
}

private _focusNewSplit(newSplit: any): void {
if (this.activeSplit && this.activeSplit.leave) {
this.activeSplit.leave()
Expand Down
2 changes: 2 additions & 0 deletions browser/src/Services/WindowManager/WindowManagerStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface IAugmentedSplitInfo extends Oni.IWindowSplit {
// Internal bookkeeping
id: string

innerSplit: Oni.IWindowSplit

// Potential API methods
enter?(): void
leave?(): void
Expand Down
1 change: 1 addition & 0 deletions browser/src/Services/WindowManager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* to the active editor, and managing transitions between editors.
*/

export * from "./layoutFromSplitInfo"
export * from "./LinearSplitProvider"
export * from "./RelationalSplitNavigator"
export * from "./SingleSplitProvider"
Expand Down
69 changes: 69 additions & 0 deletions browser/src/Services/WindowManager/layoutFromSplitInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* layoutFromSplitInfo.ts
*
* Function to layout splits into a particular window
*/

import * as Oni from "oni-api"

import { IAugmentedSplitInfo, ISplitInfo, SplitOrLeaf } from "./WindowManagerStore"

export interface LayoutResultInfo {
rectangle: Oni.Shapes.Rectangle
split: IAugmentedSplitInfo
}

export interface LayoutResult {
[windowId: string]: LayoutResultInfo
}

export const layoutFromSplitInfo = (
splits: ISplitInfo<IAugmentedSplitInfo>,
width: number,
height: number,
): LayoutResult => {
return layoutFromSplitInfoHelper(splits, Oni.Shapes.Rectangle.create(0, 0, width, height))
}

const layoutFromSplitInfoHelper = (
split: SplitOrLeaf<IAugmentedSplitInfo>,
rectangle: Oni.Shapes.Rectangle,
): LayoutResult => {
// Base case..
if (split.type === "Leaf") {
return {
[split.contents.id]: {
rectangle,
split: split.contents,
},
}
}

if (split.splits.length === 0) {
return {}
}

// Recursive case
//
// TODO: Handle specified sizes for the windows. We're just distributing the space evenly, currently.
const splitWidth =
split.direction === "horizontal" ? rectangle.width / split.splits.length : rectangle.width
const splitHeight =
split.direction === "vertical" ? rectangle.height / split.splits.length : rectangle.height

let ret = {}

for (let i = 0; i < split.splits.length; i++) {
const x = split.direction === "horizontal" ? rectangle.x + splitWidth * i : rectangle.x
const y = split.direction === "vertical" ? rectangle.y + splitHeight * i : rectangle.y

const rect = Oni.Shapes.Rectangle.create(x, y, splitWidth, splitHeight)

ret = {
...ret,
...layoutFromSplitInfoHelper(split.splits[i], rect),
}
}

return ret
}
Loading