Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use webgl for cursor #44

Merged
merged 27 commits into from
Nov 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
10c529a
perf improvement MVP
smolck Nov 1, 2020
dddcb56
Initial impl for webgl cursor
smolck Nov 1, 2020
1aaf7c2
More webgl cursor stuff
smolck Nov 1, 2020
61667d4
Remove a bunch of stuff
smolck Nov 1, 2020
8946efa
More stuff to remove/change
smolck Nov 1, 2020
6e5887e
CursorNormal -> Cursor
smolck Nov 1, 2020
efdbbdb
More cursor stuff
smolck Nov 1, 2020
8eff4a4
More cursor stuff
smolck Nov 2, 2020
b377779
prettier
smolck Nov 2, 2020
f1a3e62
Remove layout timeout change (to be done in another PR)
smolck Nov 2, 2020
49da589
Remove rest of timeout code
smolck Nov 2, 2020
211efed
Initial cursor line implementation
smolck Nov 5, 2020
a5ef814
Make the cursor line shape much smaller
smolck Nov 5, 2020
4ff4c6f
Render the line shape for the cursor
smolck Nov 5, 2020
d2d69c3
Remove console.log
smolck Nov 5, 2020
d5a60e2
Merge branch 'master' into performance
smolck Nov 5, 2020
f6f9590
"Fix" the underline issue
smolck Nov 9, 2020
b0ba912
Fix cursor shape not changing on insert
smolck Nov 11, 2020
4c9a33e
Questionable code to make the cursor not appear in inactive windows
smolck Nov 11, 2020
209ca5c
Show char under cursor (block), fix underlines
smolck Nov 12, 2020
ae933dd
Obey size of cursor
smolck Nov 12, 2020
951c6ec
comment
smolck Nov 12, 2020
c4898b4
Revert 2fabcbb
smolck Nov 15, 2020
8741acd
proper amount of vertices for underlines
smolck Nov 15, 2020
2250274
Support horizontal guicursor and format
smolck Nov 15, 2020
47729c9
"Fix" TS errors
smolck Nov 15, 2020
596675f
cleanup
smolck Nov 15, 2020
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
5 changes: 4 additions & 1 deletion src/bootstrap/galaxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,7 @@ dispatch.sub('window.change', () => {
})

// TODO(smolck): Put this somewhere else?
api.onAction('update-nameplates', () => (windows.refresh(), console.log('refresh')))
api.onAction(
'update-nameplates',
() => (windows.refresh(), console.log('refresh'))
)
2 changes: 0 additions & 2 deletions src/bootstrap/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@
<div id="workspace">
<div id="webgl"></div>
<div id="windows"></div>
<div id="cursor"></div>
<div id="cursorline"></div>
<div id="debugline"></div>
<div id="plugins"></div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/extensions/grep.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RowNormal, RowHeader } from '../row-container'
import { PluginRight } from '../plugin-container'
import { vimBlur, vimFocus } from '../../ui/uikit'
import { showCursorline } from '../../core/cursor'
// TODO(smolck): import { showCursorline } from '../../core/cursor'
import Input from '../text-input'
import { badgeStyle } from '../../ui/styles'
import { render } from 'inferno'
Expand Down Expand Up @@ -67,7 +67,7 @@ const selectResult = (results: Result[], ix: number, subix: number) => {
const [path, items] = results[ix]
const { line, column } = items[subix]
api.nvim.jumpTo({ path, line, column })
showCursorline()
// TODO(smolck): showCursorline()
}

const highlightPattern = (
Expand Down
4 changes: 2 additions & 2 deletions src/components/extensions/lsp-references.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { RowNormal, RowHeader } from '../row-container'
import { PluginRight } from '../plugin-container'
import { vimBlur, vimFocus } from '../../ui/uikit'
import { simplifyPath } from '../../support/utils'
import { showCursorline } from '../../core/cursor'
// TODO(smolck): import { showCursorline } from '../../core/cursor'
import { badgeStyle } from '../../ui/styles'
import { render } from 'inferno'
import Input from '../text-input'
Expand Down Expand Up @@ -82,7 +82,7 @@ const selectResult = (references: Refs[], ix: number, subix: number) => {
line: lineNum - 1,
column: column - 1,
})
showCursorline()
// TODO(smolck): showCursorline()
}

const highlightPattern = (
Expand Down
34 changes: 0 additions & 34 deletions src/components/text-input.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Loading from './loading'
import { paddingVH, cvar } from '../ui/css'
import { xfrmUp } from '../core/input'
import { FormEvent } from 'inferno'
import Icon from './icon'

Expand Down Expand Up @@ -59,25 +58,6 @@ const nopMaybe = (obj: object) =>
get: (_, key) => Reflect.get(obj, key) || (() => {}),
}) as Props

const keToStr = (e: KeyboardEvent) =>
[
e.key,
(e.ctrlKey as any) | 0,
(e.metaKey as any) | 0,
(e.altKey as any) | 0,
(e.shiftKey as any) | 0,
].join('')

// TODO: could be better? it's global so will be shared between different
// inputs. however only one input will have focus at a time, so perhaps
// it's not a big deal
//
// the reason this has to live outside the function is because the view
// function will be triggered on re-render. pressing keys will potentially
// trigger re-renders, thus reseting the value of lastDown when inside
// the function.
let lastDown = ''

// TODO(smolck): But why though? Has to be another way to get access to
// `onComponentDidMount` with normal stuff like <input>
const WhyInput = (props: any) => <input {...props} />
Expand Down Expand Up @@ -167,24 +147,10 @@ const textInput = (
setFocus(e.currentTarget, focus)
setPosition(e.currentTarget, position)
}}
onKeyUp={(e: KeyboardEvent) => {
const prevKeyAndThisOne = lastDown + keToStr(e)

if (xfrmUp.has(prevKeyAndThisOne)) {
const { key } = xfrmUp.get(prevKeyAndThisOne)!(e)
if (key.toLowerCase() === '<esc>') {
lastDown = ''
;(e.target as HTMLInputElement).blur()
return $.hide()
}
}
}}
onKeyDown={(e: KeyboardEvent) => {
const { ctrlKey: ctrl, metaKey: meta, key } = e
const cm = ctrl || meta

lastDown = keToStr(e)

if (key === 'Tab') {
e.preventDefault()
return $.tab()
Expand Down
145 changes: 25 additions & 120 deletions src/core/cursor.ts
Original file line number Diff line number Diff line change
@@ -1,163 +1,68 @@
import * as windows from '../windows/window-manager'
import { partialFill, translate } from '../ui/css'
import { paddingX } from '../windows/window'
import { cell } from '../core/workspace'
import { hexToRGB } from '../ui/css'

export enum CursorShape {
block,
line,
underline,
block = 0,
line = 1,
underline = 2,
}

export const cursor = {
visible: false,
row: 0,
col: 0,
color: '#fff',
color: [0, 0, 0],
shape: CursorShape.block,
size: 20,
}

const cursorEl = document.getElementById('cursor') as HTMLElement
const cursorChar = document.createElement('span')
const cursorline = document.getElementById('cursorline') as HTMLElement
export const debugline = document.getElementById('debugline') as HTMLElement
let cursorEnabled = false
let cursorRequestedToBeHidden = false
let cursorEnabled = true
let cursorCharVisible = true

Object.assign(cursorline.style, {
background: 'rgba(var(--background-alpha), 0.2)',
position: 'absolute',
'mix-blend-mode': 'screen',
height: `${cell.height}px`,
'z-index': 60,
})

Object.assign(debugline.style, {
display: 'none',
position: 'absolute',
'mix-blend-mode': 'screen',
height: `${cell.height}px`,
'z-index': 60,
})

Object.assign(cursorEl.style, {
'z-index': 70,
position: 'absolute',
display: 'none',
'justify-content': 'center',
'align-items': 'center',
})

Object.assign(cursorChar.style, {
filter: 'invert(1) grayscale(1)',
'font-family': 'var(--font)',
'font-size': 'calc(var(--font-size) * 1px)',
})

cursorEl.appendChild(cursorChar)

export const getCursorBoundingClientRect = () =>
cursorline.getBoundingClientRect()

export const setCursorShape = (shape: CursorShape, size = 20) => {
cursor.shape = shape
cursor.size = size

if (shape === CursorShape.block)
Object.assign(cursorEl.style, {
background: cursor.color,
height: `${cell.height}px`,
width: `${cell.width}px`,
})

if (shape === CursorShape.line)
Object.assign(cursorEl.style, {
background: cursor.color,
height: `${cell.height}px`,
width: `${(cell.width * (size / 100)).toFixed(2)}px`,
})

if (shape === CursorShape.underline)
Object.assign(cursorEl.style, {
background: partialFill('horizontal', cursor.color, size),
height: `${cell.height}px`,
width: `${cell.width}px`,
})
windows.webgl.updateCursorShape(shape)
}

export const setCursorColor = (color: string) => {
cursorChar.style.color = color
cursor.color = color
cursorEl.style.background = color
let [r, g, b] = hexToRGB(color)
r /= 255
g /= 255
b /= 255
cursor.color = [r, g, b]

windows.webgl.updateCursorColor(r, g, b)
}

export const enableCursor = () => (cursorEnabled = true)
export const disableCursor = () => (cursorEnabled = false)

export const hideCursor = () => {
if (!cursorEnabled) return

cursorRequestedToBeHidden = true
cursorEl.style.display = 'none'
cursorline.style.display = 'none'

windows.webgl.showCursor(false)
Object.assign(cursor, { visible: false })
}

export const showCursor = () => {
if (!cursorEnabled) return

cursorRequestedToBeHidden = false
cursorEl.style.display = 'flex'
cursorline.style.display = 'none'
}

export const showCursorline = () => (cursorline.style.display = '')

export const updateCursorChar = () => {
cursorChar.innerText =
cursor.shape === CursorShape.block
? windows.getActive().editor.getChar(cursor.row, cursor.col)
: ''

if (cursor.shape === CursorShape.block && !cursorCharVisible)
cursorChar.style.display = ''
windows.webgl.showCursor(true)
Object.assign(cursor, { visible: true })
}

const updateCursorCharInternal = (gridId: number, row: number, col: number) => {
if (cursor.shape !== CursorShape.block) {
cursorChar.style.display = 'none'
cursorCharVisible = false
cursorChar.innerText = ''
return
}

const char = windows.get(gridId).editor.getChar(row, col)
cursorChar.innerText = char
cursorChar.style.display = ''
cursorCharVisible = true
}
// TODO(smolck): export const showCursorline = () => (cursorline.style.display = '')

export const moveCursor = (gridId: number, row: number, col: number) => {
export const moveCursor = (row: number, col: number) => {
Object.assign(cursor, { row, col })

// even if cursor(line) is hidden, we still need to update the positions.
// once the cursor elements are re-activated, the position updated while
// hidden must be accurate. (e.g. using jumpTo() in grep/references/etc)
const win = windows.get(gridId)
const cursorPos = win.positionToWorkspacePixels(row, col)
const linePos = win.positionToWorkspacePixels(row, 0)
const { width } = win.getWindowSize()

cursorEl.style.transform = translate(cursorPos.x, cursorPos.y)

Object.assign(cursorline.style, {
transform: translate(linePos.x - paddingX, linePos.y),
width: `${width}px`,
height: `${cell.height}px`,
})

updateCursorCharInternal(gridId, row, col)

if (cursorRequestedToBeHidden) return
showCursor()
windows.webgl.updateCursorPosition(row, col)
}

setCursorShape(CursorShape.block)
Loading