Skip to content
This repository was archived by the owner on Apr 1, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 14 additions & 26 deletions browser/src/Editor/NeovimEditor/NeovimBufferLayersView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import { NeovimActiveWindow } from "./NeovimActiveWindow"

import * as State from "./NeovimEditorStore"

import { StackLayer } from "../../UI/components/common"
import { EmptyArray } from "./../../Utility"
import styled, { StackLayer } from "../../UI/components/common"

export interface NeovimBufferLayersViewProps {
activeWindowId: number
Expand All @@ -25,21 +24,19 @@ export interface NeovimBufferLayersViewProps {
fontPixelHeight: number
}

const InnerLayerStyle: React.CSSProperties = {
position: "absolute",
top: "0px",
left: "0px",
right: "0px",
bottom: "0px",
overflowY: "auto",
overflowX: "auto",
}
const InnerLayer = styled.div`
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
overflow: hidden;
`

export class NeovimBufferLayersView extends React.PureComponent<NeovimBufferLayersViewProps, {}> {
public render(): JSX.Element {
const containers = this.props.windows.map(windowState => {
const layers =
this.props.layers[windowState.bufferId] || (EmptyArray as Oni.BufferLayer[])
const layers: Oni.BufferLayer[] = this.props.layers[windowState.bufferId] || []

const layerContext: Oni.BufferLayerRenderContext = {
isActive: windowState.windowId === this.props.activeWindowId,
Expand All @@ -55,20 +52,11 @@ export class NeovimBufferLayersView extends React.PureComponent<NeovimBufferLaye
bottomBufferLine: windowState.bottomBufferLine,
}

const layerElements = layers.map(l => {
const layerElements = layers.map(layer => {
return (
<div
key={
l.id +
"." +
windowState.windowId.toString() +
"." +
windowState.bufferId.toString()
}
style={InnerLayerStyle}
>
{l.render(layerContext)}
</div>
<InnerLayer key={`${layer.id}.${windowState.windowId}.${windowState.bufferId}`}>
{layer.render(layerContext)}
</InnerLayer>
)
})

Expand Down
84 changes: 63 additions & 21 deletions browser/src/Editor/OniEditor/IndentGuideBufferLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,22 @@ interface IProps {
color?: string
}

interface ConfigOptions {
skipFirst: boolean
color?: string
}

interface LinePropsWithLevels extends IndentLinesProps {
levelOfIndentation: number
}

interface IndentLinesProps {
top: number
left: number
height: number
line: string
indentBy: number
indentSize: number
characterWidth: number
}

Expand Down Expand Up @@ -71,31 +81,59 @@ class IndentGuideBufferLayer implements Oni.BufferLayer {
return "Indent Guide Lines"
}

private _getIndentLines = (guidePositions: IndentLinesProps[], color?: string) => {
private _getIndentLines = (guidePositions: IndentLinesProps[], options: ConfigOptions) => {
return flatten(
guidePositions.map(({ line, height, characterWidth, indentBy, left, top }, lineNo) => {
const indentation = characterWidth * this._userSpacing
return Array.from({ length: indentBy }, (_, level) => {
const adjustedLeft = left - level * indentation + characterWidth / 3
// skip the furthest (inwards) indent if there are one or more indents
const skipIndentLine = !level && indentBy >= 1
return (
!skipIndentLine && (
guidePositions.map((props, idx) => {
const indents: JSX.Element[] = []
// Create a line per indentation
for (
let levelOfIndentation = 0;
levelOfIndentation < props.indentBy;
levelOfIndentation++
) {
const lineProps = { ...props, levelOfIndentation }
const adjustedLeft = this._calculateLeftPosition(lineProps)
const shouldSkip = this._determineIfShouldSkip(lineProps, options)
const key = `${props.line.trim()}-${idx}-${levelOfIndentation}`
indents.push(
!shouldSkip && (
<IndentLine
top={top}
color={color}
height={height}
key={key}
top={props.top}
left={adjustedLeft}
color={options.color}
height={props.height}
data-id="indent-line"
key={`${line.trim()}-${lineNo}-${indentation}-${level}`}
/>
)
),
)
})
}
return indents
}),
)
}

private _determineIfShouldSkip(props: LinePropsWithLevels, options: ConfigOptions) {
const skipFirstIndentLine =
options.skipFirst && props.levelOfIndentation === props.indentBy - 1

return skipFirstIndentLine
}

/**
* Remove one indent from left positioning and move lines slightly inwards -
* by a third of a character for a better visual appearance
*/
private _calculateLeftPosition(props: LinePropsWithLevels) {
const adjustedLeft =
props.left -
props.indentSize -
props.levelOfIndentation * props.indentSize +
props.characterWidth / 3

return adjustedLeft
}

private _getWrappedLines(context: Oni.BufferLayerRenderContext): IWrappedLine[] {
const { lines } = context.visibleLines.reduce(
(acc, line, index) => {
Expand Down Expand Up @@ -137,13 +175,16 @@ class IndentGuideBufferLayer implements Oni.BufferLayer {
* @returns {JSX.Element[]} An array of react elements
*/
private _renderIndentLines = (bufferLayerContext: Oni.BufferLayerRenderContext) => {
// FIXME: Outstanding issues -
// 1. If the beginning of the visible lines is wrapping no lines are drawn
// 2. If a line wraps but the wrapped line has no content line positions are off by one

// TODO: If the beginning of the visible lines is wrapping no lines are drawn
const wrappedScreenLines = this._getWrappedLines(bufferLayerContext)
const color = this._configuration.getValue<string>("experimental.indentLines.color")

const options = {
color: this._configuration.getValue<string>("experimental.indentLines.color"),
skipFirst: this._configuration.getValue<boolean>("experimental.indentLines.skipFirst"),
}

const { visibleLines, fontPixelHeight, fontPixelWidth, topBufferLine } = bufferLayerContext
const indentSize = this._userSpacing * fontPixelWidth

const { allIndentations } = visibleLines.reduce(
(acc, line, currenLineNumber) => {
Expand Down Expand Up @@ -192,6 +233,7 @@ class IndentGuideBufferLayer implements Oni.BufferLayer {
const indent = {
left,
line,
indentSize,
top: adjustedTop,
height: adjustedHeight,
characterWidth: fontPixelWidth,
Expand All @@ -205,7 +247,7 @@ class IndentGuideBufferLayer implements Oni.BufferLayer {
{ allIndentations: [], wrappedHeightAdjustment: 0 },
)

return this._getIndentLines(allIndentations, color)
return this._getIndentLines(allIndentations, options)
}
}

Expand Down
10 changes: 8 additions & 2 deletions browser/src/Editor/OniEditor/OniEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,21 @@ export class OniEditor extends Utility.Disposable implements IEditor {
)

const imageExtensions = this._configuration.getValue("editor.imageLayerExtensions")
const indentExtensions = this._configuration.getValue("experimental.indentLines.filetypes")
const bannedIndentExtensions = this._configuration.getValue(
"experimental.indentLines.bannedFiletypes",
)

this._neovimEditor.bufferLayers.addBufferLayer(
buf => imageExtensions.includes(path.extname(buf.filePath)),
buf => new ImageBufferLayer(buf),
)

if (this._configuration.getValue("experimental.indentLines.enabled")) {
this._neovimEditor.bufferLayers.addBufferLayer(
buf => indentExtensions.includes(path.extname(buf.filePath)),
buf => {
const extension = path.extname(buf.filePath)
return extension && !bannedIndentExtensions.includes(extension)
},
buffer =>
new IndentLineBufferLayer({
buffer: buffer as IBuffer,
Expand Down
15 changes: 2 additions & 13 deletions browser/src/Services/Configuration/DefaultConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,8 @@ const BaseConfiguration: IConfigurationValues = {
],
"experimental.indentLines.enabled": false,
"experimental.indentLines.color": null,
"experimental.indentLines.filetypes": [
".tsx",
".ts",
".jsx",
".js",
".go",
".re",
".py",
".c",
".cc",
".lua",
".java",
],
"experimental.indentLines.skipFirst": false,
"experimental.indentLines.bannedFiletypes": [],
"experimental.markdownPreview.enabled": false,
"experimental.markdownPreview.autoScroll": true,

Expand Down
6 changes: 4 additions & 2 deletions browser/src/Services/Configuration/IConfigurationValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ export interface IConfigurationValues {
"experimental.colorHighlight.filetypes": string[]
// Whether the indent lines should be shown
"experimental.indentLines.enabled": boolean
// Whether or not to skip the first line of indentation
"experimental.indentLines.skipFirst": boolean
"experimental.indentLines.color": string
// Filetypes the indent lines are shown for
"experimental.indentLines.filetypes": string[]
// Filetypes the indent lines are not shown for
"experimental.indentLines.bannedFiletypes": string[]
// Whether the markdown preview pane should be shown
"experimental.markdownPreview.enabled": boolean
"experimental.markdownPreview.autoScroll": boolean
Expand Down
27 changes: 14 additions & 13 deletions browser/src/neovim/NeovimWindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import { NeovimInstance } from "./index"

import * as Utility from "./../Utility"

interface NeovimWindow {
id: number
}

export interface NeovimTabPageState {
tabId: number
activeWindow: NeovimActiveWindowState
Expand Down Expand Up @@ -88,7 +92,6 @@ export class NeovimWindowManager extends Utility.Disposable {
this.trackDisposable(this._neovimInstance.onScroll.subscribe(updateScroll))

const shouldMeasure$: Observable<void> = this._scrollObservable
.auditTime(25)
.map((evt: EventContext) => ({
version: evt.version,
bufferTotalLines: evt.bufferTotalLines,
Expand All @@ -102,10 +105,9 @@ export class NeovimWindowManager extends Utility.Disposable {

shouldMeasure$
.withLatestFrom(this._scrollObservable)
.switchMap((args: [any, EventContext]) => {
const [, evt] = args
return Observable.defer(() => this._remeasure(evt))
})
.switchMap(([, evt]: [any, EventContext]) =>
Observable.defer(() => this._remeasure(evt)),
)
.subscribe((tabState: NeovimTabPageState) => {
if (tabState) {
this._onWindowStateChangedEvent.dispatch(tabState)
Expand All @@ -124,9 +126,10 @@ export class NeovimWindowManager extends Utility.Disposable {

private async _remeasure(context: EventContext): Promise<NeovimTabPageState> {
const tabNumber = context.tabNumber
const allWindows = await this._neovimInstance.request<any[]>("nvim_tabpage_list_wins", [
tabNumber,
])
const allWindows = await this._neovimInstance.request<NeovimWindow[]>(
"nvim_tabpage_list_wins",
[tabNumber],
)

const activeWindow = await this._remeasureActiveWindow(context.windowNumber, context)

Expand All @@ -136,11 +139,9 @@ export class NeovimWindowManager extends Utility.Disposable {

const inactiveWindowIds = allWindows.filter(w => w.id !== context.windowNumber)

const windowPromise = await inactiveWindowIds.map(async (window: any) => {
return this._remeasureInactiveWindow(window.id)
})

const inactiveWindows = await Promise.all(windowPromise)
const inactiveWindows = await Promise.all(
inactiveWindowIds.map(window => this._remeasureInactiveWindow(window.id)),
)

return {
tabId: tabNumber,
Expand Down
14 changes: 1 addition & 13 deletions test/ci/IndentGuide.BufferLayerTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,7 @@ export const settings = {
"oni.useDefaultConfig": true,
"oni.loadInitVim": false,
"experimental.indentLines.enabled": true,
"experimental.indentLines.filetypes": [
".tsx",
".ts",
".jsx",
".js",
".go",
".re",
".py",
".c",
".cc",
".lua",
".java",
],
"experimental.indentLines.bannedFiletypes": [".md"],
"_internal.hasCheckedInitVim": true,
},
}
Loading