From 10c529ab16344795785c99fbde067e5b9c87f248 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 31 Oct 2020 23:31:56 -0500 Subject: [PATCH 01/26] perf improvement MVP See last batch of comments on #24, also uses code from https://gist.github.com/romgrk/56169975ccd8fa2ffafd134afcdfeedc --- src/render/redraw.ts | 25 +++++++++++++++++-------- src/windows/window-manager.ts | 9 +++++++++ src/windows/window.ts | 12 +++++++++++- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 58fcc3b9..7dab02b1 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -307,6 +307,20 @@ const win_float_pos = (e: any) => { } } +let layoutTimeout: NodeJS.Timeout | undefined + +const refreshOrStartLayoutTimer = (winUpdates: boolean) => { + layoutTimeout = setTimeout(() => { + state_cursorVisible ? showCursor() : hideCursor() + if (state_cursorVisible) updateCursorChar() + dispatch.pub('redraw') + if (!winUpdates) return + + windows.disposeInvalidWindows() + windows.layout() + }, 10) +} + onRedraw((redrawEvents) => { // because of circular logic/infinite loop. cmdline_show updates UI, UI makes // a change in the cmdline, nvim sends redraw again. we cut that stuff out @@ -317,6 +331,7 @@ onRedraw((redrawEvents) => { const messageEvents: any = [] const eventCount = redrawEvents.length + for (let ix = 0; ix < eventCount; ix++) { const ev = redrawEvents[ix] const e = ev[0] @@ -373,12 +388,6 @@ onRedraw((redrawEvents) => { renderEvents.messageClearPromptsMaybeHack(state_cursorVisible) - requestAnimationFrame(() => { - state_cursorVisible ? showCursor() : hideCursor() - if (state_cursorVisible) updateCursorChar() - dispatch.pub('redraw') - if (!winUpdates) return - windows.disposeInvalidWindows() - windows.layout() - }) + if (!layoutTimeout) refreshOrStartLayoutTimer(winUpdates) + else clearTimeout(layoutTimeout), refreshOrStartLayoutTimer(winUpdates) }) diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index be87fe99..bb7f3c44 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -32,7 +32,16 @@ const getWindowById = (windowId: number) => { const getInstanceWindows = (id = instances.current) => [...windows.values()].filter((win) => win.id.startsWith(`i${id}`)) +let webglTimeout: NodeJS.Timeout | undefined; + const refreshWebGLGrid = () => { + if (webglTimeout) + clearTimeout(webglTimeout) + webglTimeout = setTimeout(refreshWebGLGridImplementation, 15) +} + +const refreshWebGLGridImplementation = () => { + webglTimeout = undefined webgl.clearAll() getInstanceWindows().forEach((w) => w.redrawFromGridBuffer()) } diff --git a/src/windows/window.ts b/src/windows/window.ts index 0649a1d2..ecf9cf3f 100644 --- a/src/windows/window.ts +++ b/src/windows/window.ts @@ -161,6 +161,8 @@ export default () => { container.appendChild(nameplate.element) container.appendChild(content) + const dimensions = new WeakMap() + const api = { get id() { return wininfo.id @@ -278,7 +280,15 @@ export default () => { } api.refreshLayout = () => { - const { top, left, width, height } = content.getBoundingClientRect() + let rect + if (dimensions.has(content)) { + rect = dimensions.get(content) + } + else { + rect = content.getBoundingClientRect() + dimensions.set(content, rect) + } + const { top, left, width, height } = rect const x = left const y = top - titleSpecs.height From dddcb56602af7b5692173e4910b5999087b25614 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 00:16:37 -0500 Subject: [PATCH 02/26] Initial impl for webgl cursor breaks things, still very much a WIP --- src/core/cursor.ts | 6 +++--- src/render/redraw.ts | 3 +-- src/render/webgl-text-bg.ts | 25 +++++++++++++++++++++++-- src/render/webgl.ts | 4 ++++ 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index a68e2a14..34378374 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -21,8 +21,8 @@ const cursorChar = document.createElement('span') const cursorline = document.getElementById('cursorline') as HTMLElement export const debugline = document.getElementById('debugline') as HTMLElement let cursorRequestedToBeHidden = false -let cursorEnabled = true -let cursorCharVisible = true +let cursorEnabled = false +let cursorCharVisible = false Object.assign(cursorline.style, { background: 'rgba(var(--background-alpha), 0.2)', @@ -90,7 +90,7 @@ export const setCursorColor = (color: string) => { cursorEl.style.background = color } -export const enableCursor = () => (cursorEnabled = true) +export const enableCursor = () => (cursorEnabled = false) export const disableCursor = () => (cursorEnabled = false) export const hideCursor = () => { diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 7dab02b1..56650017 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -8,7 +8,6 @@ import { getUpdatedFontAtlasMaybe, } from '../render/font-texture-atlas' import { - moveCursor, hideCursor, showCursor, updateCursorChar, @@ -92,7 +91,7 @@ const grid_cursor_goto = ([, [gridId, row, col]]: any) => { state_cursorVisible = gridId !== 1 if (gridId === 1) return windows.setActiveGrid(gridId) - moveCursor(gridId, row, col) + windows.webgl.updateCursorPosition(row, col) } const grid_scroll = ([ diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 6e8b0acc..cf82003a 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -2,6 +2,7 @@ import { getColorAtlas, colors } from '../render/highlight-attributes' import { WebGL, VarKind } from '../render/webgl-utils' import { cell } from '../core/workspace' import { hexToRGB } from '../ui/css' +import { cursor } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } @@ -15,6 +16,7 @@ export default (webgl: WebGL) => { colorAtlasResolution: VarKind.Uniform, colorAtlasTextureId: VarKind.Uniform, cellSize: VarKind.Uniform, + cursorPosition: VarKind.Uniform, }) program.setVertexShader( @@ -22,6 +24,7 @@ export default (webgl: WebGL) => { in vec2 ${v.quadVertex}; in vec2 ${v.cellPosition}; in float ${v.hlid}; + uniform vec2 ${v.cursorPosition}; uniform vec2 ${v.canvasResolution}; uniform vec2 ${v.colorAtlasResolution}; uniform vec2 ${v.cellSize}; @@ -44,7 +47,12 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - o_color = texture(${v.colorAtlasTextureId}, colorPosition); + vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); + if (${v.cursorPosition} == ${v.cellPosition}) { + o_color = vec4(1.0 - textureColor.r, 1.0 - textureColor.g, 1.0 - textureColor.b, 1); + } else { + o_color = textureColor; + } } ` ) @@ -75,6 +83,11 @@ export default (webgl: WebGL) => { colorAtlas.width, colorAtlas.height ) + webgl.gl.uniform2f( + program.vars.cursorPosition, + 0, + 0, + ) // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -194,6 +207,14 @@ export default (webgl: WebGL) => { webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) } + const updateCursorPosition = (row: number, col: number) => { + webgl.gl.uniform2f( + program.vars.cursorPosition, + col, + row, + ) + } + const updateColorAtlas = (colorAtlas: HTMLCanvasElement) => { webgl.loadCanvasTexture(colorAtlas, webgl.gl.TEXTURE0) webgl.gl.uniform2f( @@ -222,5 +243,5 @@ export default (webgl: WebGL) => { webgl.gl.clear(webgl.gl.COLOR_BUFFER_BIT) } - return { clear, clearAll, render, resize, updateColorAtlas, updateCellSize } + return { clear, clearAll, render, resize, updateColorAtlas, updateCellSize, updateCursorPosition } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 41eb3a71..7a4d30fc 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -31,6 +31,9 @@ const nutella = () => { textFGRenderer.resize(width, height) } + const updateCursorPosition = (row: number, col: number) => + textBGRenderer.updateCursorPosition(row, col) + const updateFontAtlas = (fontAtlas: HTMLCanvasElement) => { textFGRenderer.updateFontAtlas(fontAtlas) } @@ -143,6 +146,7 @@ const nutella = () => { updateCellSize, updateFontAtlas, updateColorAtlas, + updateCursorPosition, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, } From 1aaf7c2b7ffa1a681ffd11e69017c8885ace2209 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 09:48:01 -0600 Subject: [PATCH 03/26] More webgl cursor stuff --- src/core/cursor.ts | 133 +++++++++++------------------------- src/render/webgl-text-bg.ts | 34 +++++---- src/render/webgl.ts | 4 ++ 3 files changed, 66 insertions(+), 105 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index 34378374..a5d3665d 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -2,6 +2,7 @@ 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, @@ -12,82 +13,30 @@ export enum CursorShape { export const cursor = { row: 0, col: 0, - color: '#fff', + color: [0, 0, 0], shape: CursorShape.block, } -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 cursorRequestedToBeHidden = false let cursorEnabled = false let cursorCharVisible = false -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 +// export const getCursorBoundingClientRect = () => + // cursorline.getBoundingClientRect() - 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`, - }) +export const setCursorShape = (shape: CursorShape) => { + cursor.shape = 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] + + console.log('update cursor color', color, `rgb: ${r}, ${g}, ${b}`) + windows.webgl.updateCursorColor(r, g, b) } export const enableCursor = () => (cursorEnabled = false) @@ -97,42 +46,42 @@ export const hideCursor = () => { if (!cursorEnabled) return cursorRequestedToBeHidden = true - cursorEl.style.display = 'none' - cursorline.style.display = 'none' + // cursorEl.style.display = 'none' + // cursorline.style.display = 'none' } export const showCursor = () => { if (!cursorEnabled) return cursorRequestedToBeHidden = false - cursorEl.style.display = 'flex' - cursorline.style.display = 'none' + // 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) - : '' + // cursorChar.innerText = + // cursor.shape === CursorShape.block + // ? windows.getActive().editor.getChar(cursor.row, cursor.col) + // : '' - if (cursor.shape === CursorShape.block && !cursorCharVisible) - cursorChar.style.display = '' + // if (cursor.shape === CursorShape.block && !cursorCharVisible) + // cursorChar.style.display = '' } 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 + // 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 } export const moveCursor = (gridId: number, row: number, col: number) => { @@ -146,13 +95,13 @@ export const moveCursor = (gridId: number, row: number, col: number) => { const linePos = win.positionToWorkspacePixels(row, 0) const { width } = win.getWindowSize() - cursorEl.style.transform = translate(cursorPos.x, cursorPos.y) + // 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`, - }) + // Object.assign(cursorline.style, { + // transform: translate(linePos.x - paddingX, linePos.y), + // width: `${width}px`, + // height: `${cell.height}px`, + // }) updateCursorCharInternal(gridId, row, col) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index cf82003a..cbbc8bdd 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -17,6 +17,7 @@ export default (webgl: WebGL) => { colorAtlasTextureId: VarKind.Uniform, cellSize: VarKind.Uniform, cursorPosition: VarKind.Uniform, + cursorColor: VarKind.Uniform, }) program.setVertexShader( @@ -28,6 +29,7 @@ export default (webgl: WebGL) => { uniform vec2 ${v.canvasResolution}; uniform vec2 ${v.colorAtlasResolution}; uniform vec2 ${v.cellSize}; + uniform vec4 ${v.cursorColor}; uniform float ${v.hlidType}; uniform sampler2D ${v.colorAtlasTextureId}; @@ -47,10 +49,10 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); if (${v.cursorPosition} == ${v.cellPosition}) { - o_color = vec4(1.0 - textureColor.r, 1.0 - textureColor.g, 1.0 - textureColor.b, 1); + o_color = cursorColor; } else { + vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); o_color = textureColor; } } @@ -83,11 +85,8 @@ export default (webgl: WebGL) => { colorAtlas.width, colorAtlas.height ) - webgl.gl.uniform2f( - program.vars.cursorPosition, - 0, - 0, - ) + webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) + webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -207,12 +206,12 @@ export default (webgl: WebGL) => { webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) } + const updateCursorColor = (color: [number, number, number]) => { + webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) + } + const updateCursorPosition = (row: number, col: number) => { - webgl.gl.uniform2f( - program.vars.cursorPosition, - col, - row, - ) + webgl.gl.uniform2f(program.vars.cursorPosition, col, row) } const updateColorAtlas = (colorAtlas: HTMLCanvasElement) => { @@ -243,5 +242,14 @@ export default (webgl: WebGL) => { webgl.gl.clear(webgl.gl.COLOR_BUFFER_BIT) } - return { clear, clearAll, render, resize, updateColorAtlas, updateCellSize, updateCursorPosition } + return { + clear, + clearAll, + render, + resize, + updateColorAtlas, + updateCellSize, + updateCursorPosition, + updateCursorColor, + } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 7a4d30fc..8d82a992 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -31,6 +31,9 @@ const nutella = () => { textFGRenderer.resize(width, height) } + const updateCursorColor = (r: number, g: number, b: number) => + textBGRenderer.updateCursorColor([r, g, b]) + const updateCursorPosition = (row: number, col: number) => textBGRenderer.updateCursorPosition(row, col) @@ -147,6 +150,7 @@ const nutella = () => { updateFontAtlas, updateColorAtlas, updateCursorPosition, + updateCursorColor, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, } From 61667d401c571586a0ae54d5e5ac763c82355afc Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:08:16 -0600 Subject: [PATCH 04/26] Remove a bunch of stuff --- src/components/text-input.tsx | 34 -------- src/core/input.ts | 154 +--------------------------------- src/windows/window.ts | 21 ++--- 3 files changed, 12 insertions(+), 197 deletions(-) diff --git a/src/components/text-input.tsx b/src/components/text-input.tsx index 0f574b1f..df2803e4 100644 --- a/src/components/text-input.tsx +++ b/src/components/text-input.tsx @@ -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' @@ -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 const WhyInput = (props: any) => @@ -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() === '') { - 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() diff --git a/src/core/input.ts b/src/core/input.ts index 5b480e48..d008aa3d 100644 --- a/src/core/input.ts +++ b/src/core/input.ts @@ -1,10 +1,8 @@ -import { normalizeVimMode } from '../support/neovim-utils' import { input } from '../core/master-control' import { VimMode } from '../neovim/types' -import { $, is } from '../support/utils' +import { $, } from '../support/utils' import api from '../core/instance-api' import { remote } from 'electron' -import { Script } from 'vm' export enum InputType { Down = 'down', @@ -20,21 +18,11 @@ interface KeyShape extends KeyboardEvent { mode?: VimMode } -interface KeyTransform { - mode: string - event: 'hold' | 'up' | 'down' - match: KeyboardEvent - transform: string -} - type OnKeyFn = (inputKeys: string, inputType: InputType) => void const modifiers = ['Alt', 'Shift', 'Meta', 'Control'] const remaps = new Map() let isCapturing = true -let holding = '' -let xformed = false -let lastDown = '' let windowHasFocus = true let lastEscapeTimestamp = 0 let shouldClearEscapeOnNextAppFocus = false @@ -93,94 +81,12 @@ const formatInput = $(combineModsWithKey, wrapKey) const shortcuts = new Map() const globalShortcuts = new Map void>() -const resetInputState = () => { - xformed = false - lastDown = '' - holding = '' -} - export const focus = () => { isCapturing = true - resetInputState() } export const blur = () => { isCapturing = false - resetInputState() -} - -export const setupRemapModifiers = (mappings: RemapModifer[]) => { - if (!mappings) return - remaps.clear() - mappings.forEach((mapping) => remapModifier(mapping.from, mapping.to)) -} - -const vimscriptObjectToECMA = (obj: any) => - Object.entries(obj).reduce((res, [key, val]) => { - if (val === 'true') Reflect.set(res, key, true) - else if (val === 'false') Reflect.set(res, key, false) - else Reflect.set(res, key, val) - return res - }, {}) - -const setupTransforms = (transforms: KeyTransform[]) => { - if (!transforms) return - xfrmHold.clear() - xfrmDown.clear() - xfrmUp.clear() - - transforms.forEach(({ event, mode, match, transform }) => { - const nvimMode = normalizeVimMode(mode) - const fn = Reflect.get(addTransform, event) - if (!fn) return console.error('can not add key-transform for event:', event) - - const transformFn = new Script(transform).runInThisContext() - const matchObj = - nvimMode !== VimMode.SomeModeThatIProbablyDontCareAbout - ? Object.assign(vimscriptObjectToECMA(match), { mode: nvimMode }) - : vimscriptObjectToECMA(match) - - if (is.function(fn) && is.function(transformFn)) fn(matchObj, transformFn) - }) -} - -const remapModifier = (from: string, to: string) => remaps.set(from, to) - -type Transformer = (input: KeyboardEvent) => KeyboardEvent -export const xfrmHold = new Map() -export const xfrmDown = new Map() -export const xfrmUp = new Map() - -const keToStr = (e: KeyShape) => - [ - e.key, - (e.ctrlKey) | 0, - (e.metaKey) | 0, - (e.altKey) | 0, - (e.shiftKey) | 0, - ].join('') - -const defkey = { - ...new KeyboardEvent('keydown'), - key: '', - ctrlKey: false, - metaKey: false, - altKey: false, - shiftKey: false, -} - -const addTransform = { - hold: (e: any, fn: Transformer) => - xfrmHold.set(keToStr({ ...defkey, ...e }), (e) => ({ ...e, ...fn(e) })), - - down: (e: any, fn: Transformer) => - xfrmDown.set(keToStr({ ...defkey, ...e }), (e) => ({ ...e, ...fn(e) })), - - up: (e: any, fn: Transformer) => { - const before = keToStr({ ...defkey, ...e }) - const now = keToStr({ ...defkey, key: e.key }) - xfrmUp.set(before + now, (e) => ({ ...e, ...fn(e) })) - }, } export const stealInput = (onKeyFn: OnKeyFn) => { @@ -244,54 +150,9 @@ const sendKeys = async (e: KeyboardEvent, inputType: InputType) => { const keydownHandler = (e: KeyboardEvent) => { if (!windowHasFocus || !isCapturing) return - const es = keToStr(e) - lastDown = es - - if (xfrmDown.has(es)) { - const remapped = xfrmDown.get(holding)!(e) - sendKeys(remapped, InputType.Down) - return - } - - if (xfrmHold.has(es)) { - holding = es - return - } - - if (xfrmHold.has(holding)) { - const remapped = xfrmHold.get(holding)!(e) - sendKeys(remapped, InputType.Down) - xformed = true - return - } - sendKeys(e, InputType.Down) } -const keyupHandler = (e: KeyboardEvent) => { - if (!windowHasFocus || !isCapturing) return - - // one of the observed ways in which we can have a 'keyup' event without a - // 'keydown' event is when the window receives focus while a key is already - // pressed. this will happen with key combos like cmd+tab or alt+tab to - // switch applications in mac/windows. there is probably no good reason to - // send the keyup event key to neovim. in fact, this causes issues if we have - // a xform mapping of cmd -> escape, as it sends an 'esc' key to neovim - // terminal, thus swallowing the first key after app focus - if (!lastDown) return - const es = keToStr(e) - - const prevKeyAndThisOne = lastDown + es - if (xfrmUp.has(prevKeyAndThisOne)) - return sendKeys(xfrmUp.get(prevKeyAndThisOne)!(e), InputType.Up) - - if (holding === es) { - if (!xformed) sendKeys(e, InputType.Up) - xformed = false - holding = '' - } -} - // Need to handle key events from window for GUI elements like the external // cmdline, so if the key composition textarea isn't focused (which it won't // be when those elements are in use), handle the event from the window. @@ -301,19 +162,10 @@ window.addEventListener('keydown', (e) => { keydownHandler(e) }) -// Same as above, just for `keyup` event. -window.addEventListener('keyup', (e) => { - if (textarea) if (textarea === document.activeElement) return - - keyupHandler(e) -}) - textarea?.addEventListener('keydown', keydownHandler) -textarea?.addEventListener('keyup', keyupHandler) remote.getCurrentWindow().on('focus', () => { windowHasFocus = true - resetInputState() if (shouldClearEscapeOnNextAppFocus) { // so if i remap 'cmd' down+up -> 'esc' and then hit cmd+tab to switch apps // while in a terminal buffer, the application captures the 'cmd' (xform to @@ -335,13 +187,9 @@ remote.getCurrentWindow().on('focus', () => { remote.getCurrentWindow().on('blur', async () => { windowHasFocus = false - resetInputState() const lastEscapeFromNow = Date.now() - lastEscapeTimestamp const isTerminalMode = api.nvim.state.mode === VimMode.Terminal const fixTermEscape = isTerminalMode && lastEscapeFromNow < 25 if (fixTermEscape) shouldClearEscapeOnNextAppFocus = true }) - -api.onConfig.inputRemapModifiersDidChange(setupRemapModifiers) -api.onConfig.inputKeyTransformsDidChange(setupTransforms) diff --git a/src/windows/window.ts b/src/windows/window.ts index ecf9cf3f..188774e8 100644 --- a/src/windows/window.ts +++ b/src/windows/window.ts @@ -161,7 +161,7 @@ export default () => { container.appendChild(nameplate.element) container.appendChild(content) - const dimensions = new WeakMap() + // const dimensions = new WeakMap() const api = { get id() { @@ -280,15 +280,16 @@ export default () => { } api.refreshLayout = () => { - let rect - if (dimensions.has(content)) { - rect = dimensions.get(content) - } - else { - rect = content.getBoundingClientRect() - dimensions.set(content, rect) - } - const { top, left, width, height } = rect + // TODO(smolck): This doesn't work with splits + // let rect + // if (dimensions.has(content)) { + // rect = dimensions.get(content) + // } + // else { + // rect = content.getBoundingClientRect() + // dimensions.set(content, rect) + // } + const { top, left, width, height } = content.getBoundingClientRect() const x = left const y = top - titleSpecs.height From 8946efa1292ca94c6dbd7f773eb6ff5f87c5d9f9 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 10:59:13 -0600 Subject: [PATCH 05/26] More stuff to remove/change --- src/core/input.ts | 13 +------------ src/core/instance-api.ts | 5 ----- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/core/input.ts b/src/core/input.ts index d008aa3d..5d57ad29 100644 --- a/src/core/input.ts +++ b/src/core/input.ts @@ -9,19 +9,9 @@ export enum InputType { Up = 'up', } -interface RemapModifer { - from: string - to: string -} - -interface KeyShape extends KeyboardEvent { - mode?: VimMode -} - type OnKeyFn = (inputKeys: string, inputType: InputType) => void const modifiers = ['Alt', 'Shift', 'Meta', 'Control'] -const remaps = new Map() let isCapturing = true let windowHasFocus = true let lastEscapeTimestamp = 0 @@ -73,9 +63,8 @@ const wrapKey = (key: string): string => key.length > 1 && isUpper(key[0]) ? `<${key}>` : key const combineModsWithKey = (mods: string, key: string) => mods.length ? `${mods}-${key}` : key -const userModRemaps = (mods: string[]) => mods.map((m) => remaps.get(m) || m) const joinModsWithDash = (mods: string[]) => mods.join('-') -const mapMods = $(handleMods, userModRemaps, joinModsWithDash) +const mapMods = $(handleMods, joinModsWithDash) const mapKey = $(bypassEmptyMod, toVimKey) const formatInput = $(combineModsWithKey, wrapKey) const shortcuts = new Map() diff --git a/src/core/instance-api.ts b/src/core/instance-api.ts index 3bf1e045..d362ed8e 100644 --- a/src/core/instance-api.ts +++ b/src/core/instance-api.ts @@ -91,11 +91,6 @@ onSwitchVim(async () => { ee.emit('git.status', gitInfo.status) ee.emit('git.branch', gitInfo.branch) ee.emit('nvim.load', true) - - const mappings = await instance.request.nvimGetVar('veonim_remap_modifiers') - ee.emit('input.remap.modifiers', mappings) - const transforms = await instance.request.nvimGetVar('veonim_key_transforms') - ee.emit('input.key.transforms', transforms) }) const getBufferInfo = (): Promise => From 6e5887e4ae511d0fb222caf26ea0cc69e8f61d25 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 12:26:39 -0600 Subject: [PATCH 06/26] CursorNormal -> Cursor --- src/neovim/startup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neovim/startup.ts b/src/neovim/startup.ts index a79c5de5..48fe9532 100644 --- a/src/neovim/startup.ts +++ b/src/neovim/startup.ts @@ -83,7 +83,7 @@ startup.defineFunc.UivonimCreateHighlights` hi! link uvnFunction Function hi! link uvnBuiltin Constant hi! link uvnKeyword Keyword - hi! link uvnCursor CursorNormal + hi! link uvnCursor Cursor ` // autocmds in a separate function because chaining autocmds with "|" is bad From efdbbdb7017610e02a1a4b0c7f275d8f542532d2 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 13:51:23 -0600 Subject: [PATCH 07/26] More cursor stuff --- src/core/cursor.ts | 75 +++++------------------------------ src/render/redraw.ts | 2 - src/render/webgl-text-bg.ts | 10 ++++- src/render/webgl.ts | 3 ++ src/windows/window-manager.ts | 9 ----- 5 files changed, 23 insertions(+), 76 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index a5d3665d..75820bc9 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -1,7 +1,4 @@ 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 { @@ -11,16 +8,12 @@ export enum CursorShape { } export const cursor = { - row: 0, - col: 0, color: [0, 0, 0], shape: CursorShape.block, } let cursorRequestedToBeHidden = false let cursorEnabled = false -let cursorCharVisible = false - // export const getCursorBoundingClientRect = () => // cursorline.getBoundingClientRect() @@ -35,78 +28,32 @@ export const setCursorColor = (color: string) => { b /= 255 cursor.color = [r, g, b] - console.log('update cursor color', color, `rgb: ${r}, ${g}, ${b}`) windows.webgl.updateCursorColor(r, g, b) } -export const enableCursor = () => (cursorEnabled = false) -export const disableCursor = () => (cursorEnabled = false) +export const enableCursor = () => (windows.webgl.enableCursor(true), cursorEnabled = true) +export const disableCursor = () => (windows.webgl.enableCursor(false), cursorEnabled = false) export const hideCursor = () => { + return if (!cursorEnabled) return - cursorRequestedToBeHidden = true - // cursorEl.style.display = 'none' - // cursorline.style.display = 'none' + console.log('hide cursor') + windows.webgl.enableCursor(false) } export const showCursor = () => { + return 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 = '' -} - -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 + console.log('show cursor') + windows.webgl.enableCursor(true) } -export const moveCursor = (gridId: number, 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) +// export const showCursorline = () => (cursorline.style.display = '') - if (cursorRequestedToBeHidden) return - showCursor() +export const moveCursor = (row: number, col: number) => { + windows.webgl.updateCursorPosition(row, col) } setCursorShape(CursorShape.block) diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 56650017..9a6f738d 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -10,7 +10,6 @@ import { import { hideCursor, showCursor, - updateCursorChar, } from '../core/cursor' import * as windows from '../windows/window-manager' import * as dispatch from '../messaging/dispatch' @@ -311,7 +310,6 @@ let layoutTimeout: NodeJS.Timeout | undefined const refreshOrStartLayoutTimer = (winUpdates: boolean) => { layoutTimeout = setTimeout(() => { state_cursorVisible ? showCursor() : hideCursor() - if (state_cursorVisible) updateCursorChar() dispatch.pub('redraw') if (!winUpdates) return diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index cbbc8bdd..086b273a 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -18,6 +18,7 @@ export default (webgl: WebGL) => { cellSize: VarKind.Uniform, cursorPosition: VarKind.Uniform, cursorColor: VarKind.Uniform, + cursorEnabled: VarKind.Uniform, }) program.setVertexShader( @@ -30,6 +31,7 @@ export default (webgl: WebGL) => { uniform vec2 ${v.colorAtlasResolution}; uniform vec2 ${v.cellSize}; uniform vec4 ${v.cursorColor}; + uniform bool ${v.cursorEnabled}; uniform float ${v.hlidType}; uniform sampler2D ${v.colorAtlasTextureId}; @@ -49,7 +51,7 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - if (${v.cursorPosition} == ${v.cellPosition}) { + if (${v.cursorPosition} == ${v.cellPosition} && ${v.cursorEnabled}) { o_color = cursorColor; } else { vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); @@ -87,6 +89,8 @@ export default (webgl: WebGL) => { ) webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) + // @ts-ignore + webgl.gl.uniform1i(program.vars.cursorEnabled, true) // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -206,6 +210,9 @@ export default (webgl: WebGL) => { webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) } + // @ts-ignore + const enableCursor = (enable: boolean) => webgl.gl.uniform1i(program.vars.cursorEnabled, enable) + const updateCursorColor = (color: [number, number, number]) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) } @@ -249,6 +256,7 @@ export default (webgl: WebGL) => { resize, updateColorAtlas, updateCellSize, + enableCursor, updateCursorPosition, updateCursorColor, } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 8d82a992..0db3bf09 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -31,6 +31,8 @@ const nutella = () => { textFGRenderer.resize(width, height) } + const enableCursor = (enable: boolean) => textBGRenderer.enableCursor(enable) + const updateCursorColor = (r: number, g: number, b: number) => textBGRenderer.updateCursorColor([r, g, b]) @@ -151,6 +153,7 @@ const nutella = () => { updateColorAtlas, updateCursorPosition, updateCursorColor, + enableCursor, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, } diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index bb7f3c44..d9bfdb00 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -205,15 +205,6 @@ export const layout = () => { // wait for flex grid styles to be applied to all windows and trigger dom layout windowGridInfo.forEach(({ gridId }) => windows.get(gridId)!.refreshLayout()) refreshWebGLGrid() - - // cursorline width does not always get resized correctly after window - // layout changes, so we will force an update of the cursor to make sure - // it is correct. test case: two vert splits, move to left and :bo - state.activeGrid && - requestAnimationFrame(() => { - if (!windows.has(state.activeGrid)) return - moveCursor(state.activeInstanceGrid, cursor.row, cursor.col) - }) } const updateWindowNameplates = () => From 8eff4a4406bd406c3ce3cf3f0ecaf78b4454ccaa Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 19:34:43 -0600 Subject: [PATCH 08/26] More cursor stuff --- src/core/cursor.ts | 18 ++++++++---------- src/render/webgl-text-bg.ts | 14 +++++++------- src/render/webgl.ts | 4 ++-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index 75820bc9..de1bdc84 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -8,14 +8,15 @@ export enum CursorShape { } export const cursor = { + row: 0, + col: 0, color: [0, 0, 0], shape: CursorShape.block, } -let cursorRequestedToBeHidden = false let cursorEnabled = false // export const getCursorBoundingClientRect = () => - // cursorline.getBoundingClientRect() +// cursorline.getBoundingClientRect() export const setCursorShape = (shape: CursorShape) => { cursor.shape = shape @@ -31,28 +32,25 @@ export const setCursorColor = (color: string) => { windows.webgl.updateCursorColor(r, g, b) } -export const enableCursor = () => (windows.webgl.enableCursor(true), cursorEnabled = true) -export const disableCursor = () => (windows.webgl.enableCursor(false), cursorEnabled = false) +export const enableCursor = () => (cursorEnabled = true) +export const disableCursor = () => (cursorEnabled = false) export const hideCursor = () => { - return if (!cursorEnabled) return - console.log('hide cursor') - windows.webgl.enableCursor(false) + windows.webgl.showCursor(false) } export const showCursor = () => { - return if (!cursorEnabled) return - console.log('show cursor') - windows.webgl.enableCursor(true) + windows.webgl.showCursor(true) } // export const showCursorline = () => (cursorline.style.display = '') export const moveCursor = (row: number, col: number) => { + Object.assign(cursor, { row, col }) windows.webgl.updateCursorPosition(row, col) } diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 086b273a..4dae2d14 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -18,7 +18,7 @@ export default (webgl: WebGL) => { cellSize: VarKind.Uniform, cursorPosition: VarKind.Uniform, cursorColor: VarKind.Uniform, - cursorEnabled: VarKind.Uniform, + shouldShowCursor: VarKind.Uniform, }) program.setVertexShader( @@ -31,7 +31,7 @@ export default (webgl: WebGL) => { uniform vec2 ${v.colorAtlasResolution}; uniform vec2 ${v.cellSize}; uniform vec4 ${v.cursorColor}; - uniform bool ${v.cursorEnabled}; + uniform bool ${v.shouldShowCursor}; uniform float ${v.hlidType}; uniform sampler2D ${v.colorAtlasTextureId}; @@ -51,7 +51,7 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - if (${v.cursorPosition} == ${v.cellPosition} && ${v.cursorEnabled}) { + if (${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}) { o_color = cursorColor; } else { vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); @@ -90,7 +90,7 @@ export default (webgl: WebGL) => { webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) // @ts-ignore - webgl.gl.uniform1i(program.vars.cursorEnabled, true) + webgl.gl.uniform1i(program.vars.shouldShowCursor, true) // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -194,7 +194,7 @@ export default (webgl: WebGL) => { x: number, y: number, width: number, - height: number + height: number, ) => { readjustViewportMaybe(x, y, width, height) wrenderBuffer.setData(buffer) @@ -211,7 +211,7 @@ export default (webgl: WebGL) => { } // @ts-ignore - const enableCursor = (enable: boolean) => webgl.gl.uniform1i(program.vars.cursorEnabled, enable) + const showCursor = (enable: boolean) => webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) const updateCursorColor = (color: [number, number, number]) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) @@ -256,7 +256,7 @@ export default (webgl: WebGL) => { resize, updateColorAtlas, updateCellSize, - enableCursor, + showCursor, updateCursorPosition, updateCursorColor, } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 0db3bf09..c0d36544 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -31,7 +31,7 @@ const nutella = () => { textFGRenderer.resize(width, height) } - const enableCursor = (enable: boolean) => textBGRenderer.enableCursor(enable) + const showCursor = (enable: boolean) => textBGRenderer.showCursor(enable) const updateCursorColor = (r: number, g: number, b: number) => textBGRenderer.updateCursorColor([r, g, b]) @@ -153,7 +153,7 @@ const nutella = () => { updateColorAtlas, updateCursorPosition, updateCursorColor, - enableCursor, + showCursor, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, } From b37777905a280f1578f10001e3ee14f5e008d559 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 19:43:13 -0600 Subject: [PATCH 09/26] prettier --- src/bootstrap/galaxy.ts | 5 ++++- src/core/input.ts | 2 +- src/render/redraw.ts | 5 +---- src/render/webgl-text-bg.ts | 5 +++-- src/windows/window-manager.ts | 5 ++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/galaxy.ts b/src/bootstrap/galaxy.ts index 59cde13c..9303150e 100644 --- a/src/bootstrap/galaxy.ts +++ b/src/bootstrap/galaxy.ts @@ -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')) +) diff --git a/src/core/input.ts b/src/core/input.ts index 5d57ad29..8cebe9d5 100644 --- a/src/core/input.ts +++ b/src/core/input.ts @@ -1,6 +1,6 @@ import { input } from '../core/master-control' import { VimMode } from '../neovim/types' -import { $, } from '../support/utils' +import { $ } from '../support/utils' import api from '../core/instance-api' import { remote } from 'electron' diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 9a6f738d..747e0402 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -7,10 +7,7 @@ import { getCharIndex, getUpdatedFontAtlasMaybe, } from '../render/font-texture-atlas' -import { - hideCursor, - showCursor, -} from '../core/cursor' +import { hideCursor, showCursor } from '../core/cursor' import * as windows from '../windows/window-manager' import * as dispatch from '../messaging/dispatch' import { onRedraw, resizeGrid } from '../core/master-control' diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 4dae2d14..51024861 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -194,7 +194,7 @@ export default (webgl: WebGL) => { x: number, y: number, width: number, - height: number, + height: number ) => { readjustViewportMaybe(x, y, width, height) wrenderBuffer.setData(buffer) @@ -211,7 +211,8 @@ export default (webgl: WebGL) => { } // @ts-ignore - const showCursor = (enable: boolean) => webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) + const showCursor = (enable: boolean) => + webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) const updateCursorColor = (color: [number, number, number]) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index d9bfdb00..b5c6862e 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -32,11 +32,10 @@ const getWindowById = (windowId: number) => { const getInstanceWindows = (id = instances.current) => [...windows.values()].filter((win) => win.id.startsWith(`i${id}`)) -let webglTimeout: NodeJS.Timeout | undefined; +let webglTimeout: NodeJS.Timeout | undefined const refreshWebGLGrid = () => { - if (webglTimeout) - clearTimeout(webglTimeout) + if (webglTimeout) clearTimeout(webglTimeout) webglTimeout = setTimeout(refreshWebGLGridImplementation, 15) } From f1a3e6224983f5b561afc659c3a76090cb39c141 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 21:36:49 -0600 Subject: [PATCH 10/26] Remove layout timeout change (to be done in another PR) --- src/render/redraw.ts | 23 +++++++---------------- src/windows/window.ts | 11 ----------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 747e0402..caf349f0 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -302,19 +302,6 @@ const win_float_pos = (e: any) => { } } -let layoutTimeout: NodeJS.Timeout | undefined - -const refreshOrStartLayoutTimer = (winUpdates: boolean) => { - layoutTimeout = setTimeout(() => { - state_cursorVisible ? showCursor() : hideCursor() - dispatch.pub('redraw') - if (!winUpdates) return - - windows.disposeInvalidWindows() - windows.layout() - }, 10) -} - onRedraw((redrawEvents) => { // because of circular logic/infinite loop. cmdline_show updates UI, UI makes // a change in the cmdline, nvim sends redraw again. we cut that stuff out @@ -325,7 +312,6 @@ onRedraw((redrawEvents) => { const messageEvents: any = [] const eventCount = redrawEvents.length - for (let ix = 0; ix < eventCount; ix++) { const ev = redrawEvents[ix] const e = ev[0] @@ -382,6 +368,11 @@ onRedraw((redrawEvents) => { renderEvents.messageClearPromptsMaybeHack(state_cursorVisible) - if (!layoutTimeout) refreshOrStartLayoutTimer(winUpdates) - else clearTimeout(layoutTimeout), refreshOrStartLayoutTimer(winUpdates) + requestAnimationFrame(() => { + state_cursorVisible ? showCursor() : hideCursor() + dispatch.pub('redraw') + if (!winUpdates) return + windows.disposeInvalidWindows() + windows.layout() + }) }) diff --git a/src/windows/window.ts b/src/windows/window.ts index 188774e8..0649a1d2 100644 --- a/src/windows/window.ts +++ b/src/windows/window.ts @@ -161,8 +161,6 @@ export default () => { container.appendChild(nameplate.element) container.appendChild(content) - // const dimensions = new WeakMap() - const api = { get id() { return wininfo.id @@ -280,15 +278,6 @@ export default () => { } api.refreshLayout = () => { - // TODO(smolck): This doesn't work with splits - // let rect - // if (dimensions.has(content)) { - // rect = dimensions.get(content) - // } - // else { - // rect = content.getBoundingClientRect() - // dimensions.set(content, rect) - // } const { top, left, width, height } = content.getBoundingClientRect() const x = left From 49da5892298ecc68686c5ce7257e21616daf3398 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 1 Nov 2020 21:43:46 -0600 Subject: [PATCH 11/26] Remove rest of timeout code --- src/windows/window-manager.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index b5c6862e..13260acb 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -32,15 +32,7 @@ const getWindowById = (windowId: number) => { const getInstanceWindows = (id = instances.current) => [...windows.values()].filter((win) => win.id.startsWith(`i${id}`)) -let webglTimeout: NodeJS.Timeout | undefined - const refreshWebGLGrid = () => { - if (webglTimeout) clearTimeout(webglTimeout) - webglTimeout = setTimeout(refreshWebGLGridImplementation, 15) -} - -const refreshWebGLGridImplementation = () => { - webglTimeout = undefined webgl.clearAll() getInstanceWindows().forEach((w) => w.redrawFromGridBuffer()) } From 211efed0911e7b4a9a19d13d4f17bc6df9138734 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 5 Nov 2020 07:21:25 -0600 Subject: [PATCH 12/26] Initial cursor line implementation --- src/core/cursor.ts | 10 ++++++---- src/render/webgl-text-bg.ts | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index de1bdc84..09a041c7 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -2,9 +2,9 @@ import * as windows from '../windows/window-manager' import { hexToRGB } from '../ui/css' export enum CursorShape { - block, - line, - underline, + block = 0, + line = 1, + underline = 2, } export const cursor = { @@ -12,14 +12,16 @@ export const cursor = { col: 0, color: [0, 0, 0], shape: CursorShape.block, + size: 20, } let cursorEnabled = false // export const getCursorBoundingClientRect = () => // cursorline.getBoundingClientRect() -export const setCursorShape = (shape: CursorShape) => { +export const setCursorShape = (shape: CursorShape, size = 20) => { cursor.shape = shape + cursor.size = size; } export const setCursorColor = (color: string) => { diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 51024861..5ed305c6 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -18,6 +18,7 @@ export default (webgl: WebGL) => { cellSize: VarKind.Uniform, cursorPosition: VarKind.Uniform, cursorColor: VarKind.Uniform, + cursorShape: VarKind.Uniform, shouldShowCursor: VarKind.Uniform, }) @@ -32,6 +33,7 @@ export default (webgl: WebGL) => { uniform vec2 ${v.cellSize}; uniform vec4 ${v.cursorColor}; uniform bool ${v.shouldShowCursor}; + uniform int ${v.cursorShape}; uniform float ${v.hlidType}; uniform sampler2D ${v.colorAtlasTextureId}; @@ -39,8 +41,15 @@ export default (webgl: WebGL) => { out vec2 o_colorPosition; void main() { + bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}; vec2 absolutePixelPosition = ${v.cellPosition} * ${v.cellSize}; - vec2 vertexPosition = absolutePixelPosition + ${v.quadVertex}; + vec2 vertexPosition; + if (${v.cursorShape} == 1 && isCursorCell) { + vertexPosition = + absolutePixelPosition + vec2(${v.quadVertex}.x / 2.0, ${v.quadVertex}.y); + } else { + vertexPosition = absolutePixelPosition + ${v.quadVertex}; + } vec2 posFloat = vertexPosition / ${v.canvasResolution}; float posx = posFloat.x * 2.0 - 1.0; float posy = posFloat.y * -2.0 + 1.0; @@ -51,7 +60,7 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - if (${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}) { + if (isCursorCell) { o_color = cursorColor; } else { vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); @@ -118,6 +127,7 @@ export default (webgl: WebGL) => { pointer: program.vars.quadVertex, type: webgl.gl.FLOAT, size: 2, + offset: 0, }) const updateCellSize = (initial = false) => { @@ -125,14 +135,19 @@ export default (webgl: WebGL) => { boxes: new Float32Array([ 0, 0, + cell.width, cell.height, + 0, cell.height, + cell.width, 0, + cell.width, cell.height, + 0, 0, ]), @@ -219,6 +234,7 @@ export default (webgl: WebGL) => { } const updateCursorPosition = (row: number, col: number) => { + webgl.gl.uniform1i(program.vars.cursorShape, cursor.shape) webgl.gl.uniform2f(program.vars.cursorPosition, col, row) } From a5ef81448529f138b874ea1b9f0e6f18b2cc56ed Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 5 Nov 2020 10:06:09 -0600 Subject: [PATCH 13/26] Make the cursor line shape much smaller --- src/render/webgl-text-bg.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 5ed305c6..7cb9b368 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -36,17 +36,17 @@ export default (webgl: WebGL) => { uniform int ${v.cursorShape}; uniform float ${v.hlidType}; uniform sampler2D ${v.colorAtlasTextureId}; - out vec4 o_color; out vec2 o_colorPosition; void main() { bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}; + vec2 absolutePixelPosition = ${v.cellPosition} * ${v.cellSize}; vec2 vertexPosition; if (${v.cursorShape} == 1 && isCursorCell) { vertexPosition = - absolutePixelPosition + vec2(${v.quadVertex}.x / 2.0, ${v.quadVertex}.y); + absolutePixelPosition + vec2(${v.quadVertex}.x / 8.0, ${v.quadVertex}.y); } else { vertexPosition = absolutePixelPosition + ${v.quadVertex}; } @@ -135,19 +135,14 @@ export default (webgl: WebGL) => { boxes: new Float32Array([ 0, 0, - cell.width, cell.height, - 0, cell.height, - cell.width, 0, - cell.width, cell.height, - 0, 0, ]), From 4ff4c6f7a8c70b2023dfdc062a394c93a54695aa Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 5 Nov 2020 15:47:06 -0600 Subject: [PATCH 14/26] Render the line shape for the cursor --- src/render/webgl-text-bg.ts | 87 +++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 7cb9b368..22c2efed 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -9,6 +9,7 @@ export default (webgl: WebGL) => { const program = webgl.setupProgram({ quadVertex: VarKind.Attribute, + isCursorTri: VarKind.Attribute, cellPosition: VarKind.Attribute, hlid: VarKind.Attribute, hlidType: VarKind.Uniform, @@ -26,6 +27,7 @@ export default (webgl: WebGL) => { (v) => `#version 300 es in vec2 ${v.quadVertex}; in vec2 ${v.cellPosition}; + in float ${v.isCursorTri}; in float ${v.hlid}; uniform vec2 ${v.cursorPosition}; uniform vec2 ${v.canvasResolution}; @@ -43,13 +45,7 @@ export default (webgl: WebGL) => { bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}; vec2 absolutePixelPosition = ${v.cellPosition} * ${v.cellSize}; - vec2 vertexPosition; - if (${v.cursorShape} == 1 && isCursorCell) { - vertexPosition = - absolutePixelPosition + vec2(${v.quadVertex}.x / 8.0, ${v.quadVertex}.y); - } else { - vertexPosition = absolutePixelPosition + ${v.quadVertex}; - } + vec2 vertexPosition = absolutePixelPosition + ${v.quadVertex}; vec2 posFloat = vertexPosition / ${v.canvasResolution}; float posx = posFloat.x * 2.0 - 1.0; float posy = posFloat.y * -2.0 + 1.0; @@ -60,7 +56,19 @@ export default (webgl: WebGL) => { float color_y = ${v.hlidType} * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - if (isCursorCell) { + bool condition; + ${/* + TODO(smolck): I'm almost certain there's a way to do this + condition all in one without extra if statements, but my brain is + not finding it right now. + */''} + if (${v.cursorShape} == 1) { + condition = isCursorCell && isCursorTri == 1.0; + } else { + condition = isCursorCell; + } + + if (condition) { o_color = cursorColor; } else { vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); @@ -123,28 +131,53 @@ export default (webgl: WebGL) => { }, ]) - const quadBuffer = program.setupData({ - pointer: program.vars.quadVertex, - type: webgl.gl.FLOAT, - size: 2, - offset: 0, - }) + console.log(Float32Array.BYTES_PER_ELEMENT) + const quadBuffer = program.setupData([ + { + pointer: program.vars.quadVertex, + type: webgl.gl.FLOAT, + size: 2, + offset: 0, + }, + { + pointer: program.vars.isCursorTri, + type: webgl.gl.FLOAT, + size: 1, + offset: Float32Array.BYTES_PER_ELEMENT * 2 * 12 + } + ]) const updateCellSize = (initial = false) => { + const w = cell.width + const h = cell.height + const w6th = w / 6 + const next = { boxes: new Float32Array([ - 0, - 0, - cell.width, - cell.height, - 0, - cell.height, - cell.width, - 0, - cell.width, - cell.height, - 0, - 0, + 0, 0, + w6th, h, + 0, h, + + w6th, 0, + w6th, h, + 0, 0, + + w6th, 0, + w, h, + w6th, h, + + w, 0, + w, h, + w6th, 0, + + // TODO(smolck): More compact way of doing this. Also, note that the 1's + // specify which triangles of the above to color in for the cursor, and the zeroes + // which triangles not to color in, *if* the cursor is a line shape. If + // it isn't a line shape (atm a block shape), these are ignored. + 1, 1, 1, + 1, 1, 1, + 0, 0, 0, + 0, 0, 0, ]), lines: new Float32Array([ 0, @@ -212,7 +245,7 @@ export default (webgl: WebGL) => { // background quadBuffer.setData(quads.boxes) webgl.gl.uniform1f(program.vars.hlidType, 0) - webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) + webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 12, buffer.length / 4) // underlines quadBuffer.setData(quads.lines) From d2d69c30a9ce01e994d30417b924efd04d974f22 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 5 Nov 2020 15:49:26 -0600 Subject: [PATCH 15/26] Remove console.log --- src/render/webgl-text-bg.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 22c2efed..dcc4ba69 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -131,7 +131,6 @@ export default (webgl: WebGL) => { }, ]) - console.log(Float32Array.BYTES_PER_ELEMENT) const quadBuffer = program.setupData([ { pointer: program.vars.quadVertex, From f6f9590cd65a5a6f052d06278ea760ea21b2fd73 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 8 Nov 2020 22:32:01 -0600 Subject: [PATCH 16/26] "Fix" the underline issue --- src/render/webgl-text-bg.ts | 87 +++++++++++++++++++++++++---------- src/windows/window-manager.ts | 1 - 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index dcc4ba69..918f9600 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -6,6 +6,7 @@ import { cursor } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } + let shouldShowCursor = true const program = webgl.setupProgram({ quadVertex: VarKind.Attribute, @@ -42,7 +43,9 @@ export default (webgl: WebGL) => { out vec2 o_colorPosition; void main() { - bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}; + bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${ + v.shouldShowCursor + }; vec2 absolutePixelPosition = ${v.cellPosition} * ${v.cellSize}; vec2 vertexPosition = absolutePixelPosition + ${v.quadVertex}; @@ -57,11 +60,13 @@ export default (webgl: WebGL) => { vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; bool condition; - ${/* + ${ + /* TODO(smolck): I'm almost certain there's a way to do this condition all in one without extra if statements, but my brain is not finding it right now. - */''} + */ '' + } if (${v.cursorShape} == 1) { condition = isCursorCell && isCursorTri == 1.0; } else { @@ -107,7 +112,7 @@ export default (webgl: WebGL) => { webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) // @ts-ignore - webgl.gl.uniform1i(program.vars.shouldShowCursor, true) + webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -142,8 +147,8 @@ export default (webgl: WebGL) => { pointer: program.vars.isCursorTri, type: webgl.gl.FLOAT, size: 1, - offset: Float32Array.BYTES_PER_ELEMENT * 2 * 12 - } + offset: Float32Array.BYTES_PER_ELEMENT * 2 * 12, + }, ]) const updateCellSize = (initial = false) => { @@ -153,30 +158,50 @@ export default (webgl: WebGL) => { const next = { boxes: new Float32Array([ - 0, 0, - w6th, h, - 0, h, + 0, + 0, + w6th, + h, + 0, + h, - w6th, 0, - w6th, h, - 0, 0, + w6th, + 0, + w6th, + h, + 0, + 0, - w6th, 0, - w, h, - w6th, h, + w6th, + 0, + w, + h, + w6th, + h, - w, 0, - w, h, - w6th, 0, + w, + 0, + w, + h, + w6th, + 0, // TODO(smolck): More compact way of doing this. Also, note that the 1's // specify which triangles of the above to color in for the cursor, and the zeroes // which triangles not to color in, *if* the cursor is a line shape. If // it isn't a line shape (atm a block shape), these are ignored. - 1, 1, 1, - 1, 1, 1, - 0, 0, 0, - 0, 0, 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, ]), lines: new Float32Array([ 0, @@ -191,6 +216,13 @@ export default (webgl: WebGL) => { cell.height, 0, cell.height - 1, + + 0, + 0, + 0, + 0, + 0, + 0, ]), } @@ -248,13 +280,20 @@ export default (webgl: WebGL) => { // underlines quadBuffer.setData(quads.lines) + + // @ts-ignore TODO(smolck): HACKS + if (shouldShowCursor) webgl.gl.uniform1i(program.vars.shouldShowCursor, false) + webgl.gl.uniform1f(program.vars.hlidType, 2) webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) + + // @ts-ignore TODO(smolck): HACKS + webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) } - // @ts-ignore const showCursor = (enable: boolean) => - webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) + // @ts-ignore + (shouldShowCursor = enable, webgl.gl.uniform1i(program.vars.shouldShowCursor, enable)) const updateCursorColor = (color: [number, number, number]) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index 13260acb..f1810d80 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -1,7 +1,6 @@ import { generateColorLookupAtlas } from '../render/highlight-attributes' import { onSwitchVim, instances } from '../core/instance-manager' import CreateWindow, { Window, paddingX } from '../windows/window' -import { cursor, moveCursor } from '../core/cursor' import CreateWebGLRenderer from '../render/webgl' import { onElementResize } from '../ui/vanilla' import * as workspace from '../core/workspace' From b0ba912f6b97e669f2cf6b0a593b804867728079 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Wed, 11 Nov 2020 12:30:28 -0600 Subject: [PATCH 17/26] Fix cursor shape not changing on insert also add some code back that I removed, use `moveCursor` instead of `windows.webgl.updateCursorPosition` directly in `grid_cursor_goto`, and maybe some other things --- src/core/cursor.ts | 7 +++++++ src/render/redraw.ts | 4 ++-- src/render/webgl-text-bg.ts | 8 ++++++-- src/render/webgl.ts | 4 ++++ src/windows/window-manager.ts | 11 +++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index 09a041c7..ad8e8f18 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -16,12 +16,14 @@ export const cursor = { } let cursorEnabled = false +let cursorRequestedToBeHidden = false // export const getCursorBoundingClientRect = () => // cursorline.getBoundingClientRect() export const setCursorShape = (shape: CursorShape, size = 20) => { cursor.shape = shape cursor.size = size; + windows.webgl.updateCursorShape(shape) } export const setCursorColor = (color: string) => { @@ -39,12 +41,14 @@ export const disableCursor = () => (cursorEnabled = false) export const hideCursor = () => { if (!cursorEnabled) return + cursorRequestedToBeHidden = true windows.webgl.showCursor(false) } export const showCursor = () => { if (!cursorEnabled) return + cursorRequestedToBeHidden = false windows.webgl.showCursor(true) } @@ -53,6 +57,9 @@ export const showCursor = () => { export const moveCursor = (row: number, col: number) => { Object.assign(cursor, { row, col }) + + if (cursorRequestedToBeHidden) return + showCursor() windows.webgl.updateCursorPosition(row, col) } diff --git a/src/render/redraw.ts b/src/render/redraw.ts index 78ebb735..ac2f4e0c 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -7,7 +7,7 @@ import { getCharIndex, getUpdatedFontAtlasMaybe, } from '../render/font-texture-atlas' -import { hideCursor, showCursor } from '../core/cursor' +import { hideCursor, showCursor, moveCursor } from '../core/cursor' import * as windows from '../windows/window-manager' import * as dispatch from '../messaging/dispatch' import { onRedraw, resizeGrid } from '../core/master-control' @@ -87,7 +87,7 @@ const grid_cursor_goto = ([, [gridId, row, col]]: any) => { state_cursorVisible = gridId !== 1 if (gridId === 1) return windows.setActiveGrid(gridId) - windows.webgl.updateCursorPosition(row, col) + moveCursor(row, col) } const grid_scroll = ([ diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 918f9600..704e52ef 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -2,7 +2,7 @@ import { getColorAtlas, colors } from '../render/highlight-attributes' import { WebGL, VarKind } from '../render/webgl-utils' import { cell } from '../core/workspace' import { hexToRGB } from '../ui/css' -import { cursor } from '../core/cursor' +import { CursorShape } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } @@ -299,8 +299,11 @@ export default (webgl: WebGL) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) } + const updateCursorShape = (shape: CursorShape) => { + webgl.gl.uniform1i(program.vars.cursorShape, shape) + } + const updateCursorPosition = (row: number, col: number) => { - webgl.gl.uniform1i(program.vars.cursorShape, cursor.shape) webgl.gl.uniform2f(program.vars.cursorPosition, col, row) } @@ -341,6 +344,7 @@ export default (webgl: WebGL) => { updateCellSize, showCursor, updateCursorPosition, + updateCursorShape, updateCursorColor, } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index c0d36544..8152ce14 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -3,6 +3,7 @@ import CreateWebGL from '../render/webgl-utils' import { cell } from '../core/workspace' import TextFG from '../render/webgl-text-fg' import TextBG from '../render/webgl-text-bg' +import { CursorShape } from '../core/cursor' export interface WebGLView { resize: (rows: number, cols: number) => void @@ -33,6 +34,8 @@ const nutella = () => { const showCursor = (enable: boolean) => textBGRenderer.showCursor(enable) + const updateCursorShape = (shape: CursorShape) => textBGRenderer.updateCursorShape(shape) + const updateCursorColor = (r: number, g: number, b: number) => textBGRenderer.updateCursorColor([r, g, b]) @@ -151,6 +154,7 @@ const nutella = () => { updateCellSize, updateFontAtlas, updateColorAtlas, + updateCursorShape, updateCursorPosition, updateCursorColor, showCursor, diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index f1810d80..d6a25ed2 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -1,6 +1,7 @@ import { generateColorLookupAtlas } from '../render/highlight-attributes' import { onSwitchVim, instances } from '../core/instance-manager' import CreateWindow, { Window, paddingX } from '../windows/window' +import { cursor, moveCursor } from '../core/cursor' import CreateWebGLRenderer from '../render/webgl' import { onElementResize } from '../ui/vanilla' import * as workspace from '../core/workspace' @@ -8,6 +9,7 @@ import { throttle } from '../support/utils' import windowSizer from '../windows/sizer' import api from '../core/instance-api' + export const size = { width: 0, height: 0 } export const webgl = CreateWebGLRenderer() const windows = new Map() @@ -195,6 +197,15 @@ export const layout = () => { // wait for flex grid styles to be applied to all windows and trigger dom layout windowGridInfo.forEach(({ gridId }) => windows.get(gridId)!.refreshLayout()) refreshWebGLGrid() + + // cursorline width does not always get resized correctly after window + // layout changes, so we will force an update of the cursor to make sure + // it is correct. test case: two vert splits, move to left and :bo + state.activeGrid && + requestAnimationFrame(() => { + if (!windows.has(state.activeGrid)) return + moveCursor(cursor.row, cursor.col) + }) } const updateWindowNameplates = () => From 4c9a33efd559a4d4190238d35b280b7560fe44f8 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Wed, 11 Nov 2020 12:53:49 -0600 Subject: [PATCH 18/26] Questionable code to make the cursor not appear in inactive windows --- src/core/cursor.ts | 3 +++ src/render/webgl.ts | 18 ++++++++++++++++-- src/windows/window-manager.ts | 5 ++++- src/windows/window.ts | 5 ++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index ad8e8f18..9d2e4d07 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -8,6 +8,7 @@ export enum CursorShape { } export const cursor = { + visible: false, row: 0, col: 0, color: [0, 0, 0], @@ -44,6 +45,7 @@ export const hideCursor = () => { cursorRequestedToBeHidden = true windows.webgl.showCursor(false) + Object.assign(cursor, { visible: false }) } export const showCursor = () => { @@ -51,6 +53,7 @@ export const showCursor = () => { cursorRequestedToBeHidden = false windows.webgl.showCursor(true) + Object.assign(cursor, { visible: true }) } // export const showCursorline = () => (cursorline.style.display = '') diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 8152ce14..6623e233 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -3,7 +3,8 @@ import CreateWebGL from '../render/webgl-utils' import { cell } from '../core/workspace' import TextFG from '../render/webgl-text-fg' import TextBG from '../render/webgl-text-bg' -import { CursorShape } from '../core/cursor' +import { cursor as cursorState, CursorShape } from '../core/cursor' +import { getActiveGridId } from '../windows/window-manager' export interface WebGLView { resize: (rows: number, cols: number) => void @@ -18,6 +19,7 @@ export interface WebGLView { getGridLine: (row: number) => Float32Array getGridBuffer: () => Float32Array getBuffer: () => Float32Array + updateGridId: (gridId: number) => void } const nutella = () => { @@ -61,12 +63,15 @@ const nutella = () => { textFGRenderer.clearAll() } - const createView = (): WebGLView => { + const createView = (initialGridId: number): WebGLView => { + let gridId = initialGridId const viewport = { x: 0, y: 0, width: 0, height: 0 } const gridSize = { rows: 0, cols: 0 } const gridBuffer = CreateWebGLBuffer() let dataBuffer = new Float32Array() + const updateGridId = (newGridId: number) => gridId = newGridId + const resize = (rows: number, cols: number) => { const width = cols * cell.width const height = rows * cell.height @@ -96,15 +101,23 @@ const nutella = () => { const render = (elements: number) => { const buffer = dataBuffer.subarray(0, elements) const { x, y, width, height } = viewport + + const doHacks = gridId !== getActiveGridId() && cursorState.visible + if (doHacks) showCursor(false) textBGRenderer.render(buffer, x, y, width, height) textFGRenderer.render(buffer, x, y, width, height) + if (doHacks) showCursor(true) } const renderGridBuffer = () => { const { x, y, width, height } = viewport const buffer = gridBuffer.getBuffer() + + const doHacks = gridId !== getActiveGridId() && cursorState.visible + if (doHacks) showCursor(false) textBGRenderer.render(buffer, x, y, width, height) textFGRenderer.render(buffer, x, y, width, height) + if (doHacks) showCursor(true) } const clear = () => { @@ -140,6 +153,7 @@ const nutella = () => { moveRegionDown, clearGridBuffer, renderGridBuffer, + updateGridId, getGridCell: gridBuffer.getCell, getGridLine: gridBuffer.getLine, getGridBuffer: gridBuffer.getBuffer, diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index d6a25ed2..714c19f1 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -75,7 +75,9 @@ export const calculateGlobalOffset = (anchorWin: Window, float: Window) => { } } -export const createWebGLView = () => webgl.createView() +export const createWebGLView = (gridId: number) => webgl.createView(gridId) + +export const getActiveGridId = () => state.activeInstanceGrid export const setActiveGrid = (id: number) => Object.assign(state, { @@ -115,6 +117,7 @@ export const set = ( visible: true, id: wid, gridId: gid, + gridIdNumber: gridId, }) if (!windows.has(gid)) windows.set(gid, win) diff --git a/src/windows/window.ts b/src/windows/window.ts index 0649a1d2..d738d70b 100644 --- a/src/windows/window.ts +++ b/src/windows/window.ts @@ -14,6 +14,7 @@ import { makel } from '../ui/vanilla' export interface WindowInfo { id: string gridId: string + gridIdNumber: number row: number col: number width: number @@ -116,6 +117,7 @@ export default () => { const wininfo: WindowInfo = { id: '0', gridId: '0', + gridIdNumber: 0, row: 0, col: 0, width: 0, @@ -125,7 +127,7 @@ export default () => { anchor: '', } const layout = { x: 0, y: 0, width: 0, height: 0 } - const webgl = createWebGLView() + const webgl = createWebGLView(0) const container = makel({ flexFlow: 'column', @@ -229,6 +231,7 @@ export default () => { container.id = `${info.id}` container.setAttribute('gridid', info.gridId) + webgl.updateGridId(info.gridIdNumber) Object.assign(wininfo, info) } From 209ca5ce70d5a4955c4ad784c069734bb17010a0 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 12 Nov 2020 13:42:25 -0600 Subject: [PATCH 19/26] Show char under cursor (block), fix underlines --- src/render/webgl-text-bg.ts | 87 ++++++++++++++++++++++--------------- src/render/webgl-text-fg.ts | 47 +++++++++++++++++++- src/render/webgl.ts | 22 ++++++++-- 3 files changed, 115 insertions(+), 41 deletions(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 704e52ef..4867696b 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -110,7 +110,7 @@ export default (webgl: WebGL) => { colorAtlas.height ) webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) - webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) + webgl.gl.uniform4fv(program.vars.cursorColor, [1, 1, 1, 1]) // @ts-ignore webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) @@ -186,43 +186,53 @@ export default (webgl: WebGL) => { w6th, 0, - // TODO(smolck): More compact way of doing this. Also, note that the 1's + // TODO(smolck): Better way of doing this? Also, note that the 1's // specify which triangles of the above to color in for the cursor, and the zeroes // which triangles not to color in, *if* the cursor is a line shape. If // it isn't a line shape (atm a block shape), these are ignored. - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, + ...Array(6).fill(1), + ...Array(6).fill(0), ]), + // TODO(smolck): Don't draw double the tris for underliens too, maybe use + // a separate buffer for quadVertex somehow or something? lines: new Float32Array([ + /* Previous values (for future ref): + * 0, cell.height - 1, + * cell.width, cell.height, + * 0, cell.height, + * + * cell.width, cell.height - 1, + * cell.width, cell.height, + * 0, cell.height - 1, */ 0, - cell.height - 1, - cell.width, - cell.height, - 0, - cell.height, - cell.width, - cell.height - 1, - cell.width, - cell.height, + h - 1, + w6th, + h, 0, - cell.height - 1, + h, + w6th, + h - 1, + w6th, + h, 0, - 0, - 0, - 0, - 0, - 0, + h - 1, + + w6th, + h - 1, + w, + h, + w6th, + h, + + w, + h - 1, + w, + h, + w6th, + h - 1, + + ...Array(12).fill(0), ]), } @@ -281,19 +291,24 @@ export default (webgl: WebGL) => { // underlines quadBuffer.setData(quads.lines) - // @ts-ignore TODO(smolck): HACKS - if (shouldShowCursor) webgl.gl.uniform1i(program.vars.shouldShowCursor, false) - + // @ts-ignore <- for using a boolean with `uniform1i` + // Just want to ignore the cursor logic in the vertex shader for underlines, + // so set shouldShowCursor to false, then back to it's previous value after + // the draw call. + if (shouldShowCursor) + // @ts-ignore + webgl.gl.uniform1i(program.vars.shouldShowCursor, false) webgl.gl.uniform1f(program.vars.hlidType, 2) webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) - - // @ts-ignore TODO(smolck): HACKS + // @ts-ignore webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) } - const showCursor = (enable: boolean) => + const showCursor = (enable: boolean) => ( + (shouldShowCursor = enable), // @ts-ignore - (shouldShowCursor = enable, webgl.gl.uniform1i(program.vars.shouldShowCursor, enable)) + webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) + ) const updateCursorColor = (color: [number, number, number]) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) diff --git a/src/render/webgl-text-fg.ts b/src/render/webgl-text-fg.ts index fe79b017..643c4f9b 100644 --- a/src/render/webgl-text-fg.ts +++ b/src/render/webgl-text-fg.ts @@ -2,6 +2,7 @@ import { getColorAtlas } from '../render/highlight-attributes' import generateFontAtlas from '../render/font-texture-atlas' import { WebGL, VarKind } from '../render/webgl-utils' import { cell } from '../core/workspace' +import { CursorShape } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } @@ -18,6 +19,11 @@ export default (webgl: WebGL) => { colorAtlasTextureId: VarKind.Uniform, cellSize: VarKind.Uniform, cellPadding: VarKind.Uniform, + + shouldShowCursor: VarKind.Uniform, + cursorPosition: VarKind.Uniform, + cursorShape: VarKind.Uniform, + cursorColor: VarKind.Uniform, }) program.setVertexShader( @@ -33,10 +39,17 @@ export default (webgl: WebGL) => { uniform vec2 ${v.cellPadding}; uniform sampler2D ${v.colorAtlasTextureId}; + uniform vec4 ${v.cursorColor}; + uniform vec2 ${v.cursorPosition}; + uniform bool ${v.shouldShowCursor}; + uniform int ${v.cursorShape}; + out vec2 o_glyphPosition; out vec4 o_color; void main() { + bool isCursorCell = ${v.cursorPosition} == ${v.cellPosition} && ${v.shouldShowCursor}; + vec2 absolutePixelPosition = ${v.cellPosition} * ${v.cellSize}; vec2 vertexPosition = absolutePixelPosition + ${v.quadVertex} + ${v.cellPadding}; vec2 posFloat = vertexPosition / ${v.canvasResolution}; @@ -53,7 +66,13 @@ export default (webgl: WebGL) => { float color_y = 1.0 * texelSize + 1.0; vec2 colorPosition = vec2(color_x, color_y) / ${v.colorAtlasResolution}; - o_color = texture(${v.colorAtlasTextureId}, colorPosition); + vec4 textureColor = texture(${v.colorAtlasTextureId}, colorPosition); + + if (isCursorCell && cursorShape == 0) { + o_color = ${v.cursorColor}; + } else { + o_color = textureColor; + } } ` ) @@ -104,6 +123,12 @@ export default (webgl: WebGL) => { colorAtlas.height ) + webgl.gl.uniform4fv(program.vars.cursorColor, [0, 0, 0, 1]) + webgl.gl.uniform2f(program.vars.cursorPosition, 0, 0) + webgl.gl.uniform1i(program.vars.cursorShape, 0) // CursorShape.block = 0 + // @ts-ignore + webgl.gl.uniform1i(program.vars.shouldShowCursor, true) + // total size of all pointers. chunk size that goes to shader const wrenderStride = 4 * Float32Array.BYTES_PER_ELEMENT @@ -231,6 +256,22 @@ export default (webgl: WebGL) => { webgl.gl.uniform2f(program.vars.cellPadding, 0, cell.padding) } + const showCursor = (enable: boolean) => + // @ts-ignore + webgl.gl.uniform1i(program.vars.shouldShowCursor, enable) + + const updateCursorColor = (color: [number, number, number]) => { + webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) + } + + const updateCursorShape = (shape: CursorShape) => { + webgl.gl.uniform1i(program.vars.cursorShape, shape) + } + + const updateCursorPosition = (row: number, col: number) => { + webgl.gl.uniform2f(program.vars.cursorPosition, col, row) + } + const updateColorAtlas = (colorAtlas: HTMLCanvasElement) => { webgl.loadCanvasTexture(colorAtlas, webgl.gl.TEXTURE1) webgl.gl.uniform2f( @@ -263,5 +304,9 @@ export default (webgl: WebGL) => { updateFontAtlas, updateColorAtlas, updateCellSize, + updateCursorPosition, + updateCursorShape, + updateCursorColor, + showCursor, } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 6623e233..c4273887 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -34,15 +34,28 @@ const nutella = () => { textFGRenderer.resize(width, height) } - const showCursor = (enable: boolean) => textBGRenderer.showCursor(enable) + const showCursor = (enable: boolean) => { + textBGRenderer.showCursor(enable) + textFGRenderer.showCursor(enable) + } + + const updateCursorShape = (shape: CursorShape) => { + textBGRenderer.updateCursorShape(shape) + textFGRenderer.updateCursorShape(shape) + } - const updateCursorShape = (shape: CursorShape) => textBGRenderer.updateCursorShape(shape) + // const updateCharUnderCursorColor = (r: number, g: number, b: number) => + // textFGRenderer.updateCursorColor([r, g, b]) - const updateCursorColor = (r: number, g: number, b: number) => + const updateCursorColor = (r: number, g: number, b: number) => { textBGRenderer.updateCursorColor([r, g, b]) + textFGRenderer.updateCursorColor([1.0 - r, 1.0 - g, 1.0 - b]) + } - const updateCursorPosition = (row: number, col: number) => + const updateCursorPosition = (row: number, col: number) => { textBGRenderer.updateCursorPosition(row, col) + textFGRenderer.updateCursorPosition(row, col) + } const updateFontAtlas = (fontAtlas: HTMLCanvasElement) => { textFGRenderer.updateFontAtlas(fontAtlas) @@ -171,6 +184,7 @@ const nutella = () => { updateCursorShape, updateCursorPosition, updateCursorColor, + // updateCharUnderCursorColor, showCursor, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, From ae933dd779a9ee7f2749ce03252950c1bca74267 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 12 Nov 2020 15:37:35 -0600 Subject: [PATCH 20/26] Obey size of cursor --- src/core/cursor.ts | 1 + src/render/webgl-text-bg.ts | 34 +++++++++++++++++++--------------- src/render/webgl.ts | 6 ++---- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index 9d2e4d07..19fd4353 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -24,6 +24,7 @@ let cursorRequestedToBeHidden = false export const setCursorShape = (shape: CursorShape, size = 20) => { cursor.shape = shape cursor.size = size; + windows.webgl.updateCursorShape(shape) } diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index 4867696b..a86451c3 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -2,11 +2,12 @@ import { getColorAtlas, colors } from '../render/highlight-attributes' import { WebGL, VarKind } from '../render/webgl-utils' import { cell } from '../core/workspace' import { hexToRGB } from '../ui/css' -import { CursorShape } from '../core/cursor' +import { CursorShape, } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } let shouldShowCursor = true + let cursorSize = 20 const program = webgl.setupProgram({ quadVertex: VarKind.Attribute, @@ -151,39 +152,39 @@ export default (webgl: WebGL) => { }, ]) - const updateCellSize = (initial = false) => { + const updateCellSize = (initial = false, cursorSize = 20) => { const w = cell.width const h = cell.height - const w6th = w / 6 + const smallerW = w * (cursorSize / 100.0) const next = { boxes: new Float32Array([ 0, 0, - w6th, + smallerW, h, 0, h, - w6th, + smallerW, 0, - w6th, + smallerW, h, 0, 0, - w6th, + smallerW, 0, w, h, - w6th, + smallerW, h, w, 0, w, h, - w6th, + smallerW, 0, // TODO(smolck): Better way of doing this? Also, note that the 1's @@ -206,30 +207,30 @@ export default (webgl: WebGL) => { * 0, cell.height - 1, */ 0, h - 1, - w6th, + smallerW, h, 0, h, - w6th, + smallerW, h - 1, - w6th, + smallerW, h, 0, h - 1, - w6th, + smallerW, h - 1, w, h, - w6th, + smallerW, h, w, h - 1, w, h, - w6th, + smallerW, h - 1, ...Array(12).fill(0), @@ -314,6 +315,8 @@ export default (webgl: WebGL) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) } + const updateCursorSize = (size: number) => cursorSize = size + const updateCursorShape = (shape: CursorShape) => { webgl.gl.uniform1i(program.vars.cursorShape, shape) } @@ -360,6 +363,7 @@ export default (webgl: WebGL) => { showCursor, updateCursorPosition, updateCursorShape, + updateCursorSize, updateCursorColor, } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index c4273887..2f7b42f1 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -41,12 +41,11 @@ const nutella = () => { const updateCursorShape = (shape: CursorShape) => { textBGRenderer.updateCursorShape(shape) + textBGRenderer.updateCellSize(false, cursorState.size) + textFGRenderer.updateCursorShape(shape) } - // const updateCharUnderCursorColor = (r: number, g: number, b: number) => - // textFGRenderer.updateCursorColor([r, g, b]) - const updateCursorColor = (r: number, g: number, b: number) => { textBGRenderer.updateCursorColor([r, g, b]) textFGRenderer.updateCursorColor([1.0 - r, 1.0 - g, 1.0 - b]) @@ -184,7 +183,6 @@ const nutella = () => { updateCursorShape, updateCursorPosition, updateCursorColor, - // updateCharUnderCursorColor, showCursor, foregroundElement: foregroundGL.canvasElement, backgroundElement: backgroundGL.canvasElement, From 951c6ec5c5d0e2759ef58b91905a7ad39af0e44b Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Thu, 12 Nov 2020 15:43:42 -0600 Subject: [PATCH 21/26] comment --- src/render/webgl.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 2f7b42f1..064d5395 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -41,6 +41,7 @@ const nutella = () => { const updateCursorShape = (shape: CursorShape) => { textBGRenderer.updateCursorShape(shape) + // TODO(smolck): If cursor size changes need to update cells . . . textBGRenderer.updateCellSize(false, cursorState.size) textFGRenderer.updateCursorShape(shape) From c4898b4c2e2dce3e1e291a76e21d9bc064b6e99a Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Nov 2020 19:50:26 -0600 Subject: [PATCH 22/26] Revert 2fabcbb https://github.com/smolck/uivonim/commit/2fabcbb21037faeb9d4a73faddab3a49e15cdde0 caused issues with the cursor lagging, so revert it (for now?). --- src/render/redraw.ts | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/render/redraw.ts b/src/render/redraw.ts index ac2f4e0c..13dbbcf0 100644 --- a/src/render/redraw.ts +++ b/src/render/redraw.ts @@ -302,20 +302,6 @@ const win_float_pos = (e: any) => { } } -let layoutTimeout: NodeJS.Timeout | undefined - -const refreshOrStartLayoutTimer = (winUpdates: boolean) => { - layoutTimeout = setTimeout(() => { - renderEvents.messageClearPromptsMaybeHack(state_cursorVisible) - state_cursorVisible ? showCursor() : hideCursor() - dispatch.pub('redraw') - if (!winUpdates) return - - windows.disposeInvalidWindows() - windows.layout() - }, 10) -} - onRedraw((redrawEvents) => { // because of circular logic/infinite loop. cmdline_show updates UI, UI makes // a change in the cmdline, nvim sends redraw again. we cut that stuff out @@ -380,6 +366,11 @@ onRedraw((redrawEvents) => { else if (e === 'msg_ruler') renderEvents.msg_ruler(ev) } - if (layoutTimeout) clearTimeout(layoutTimeout) - refreshOrStartLayoutTimer(winUpdates) + renderEvents.messageClearPromptsMaybeHack(state_cursorVisible) + state_cursorVisible ? showCursor() : hideCursor() + dispatch.pub('redraw') + if (!winUpdates) return + + windows.disposeInvalidWindows() + windows.layout() }) From 8741acdca56d36d2f4158ba01a4195828556baf7 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Nov 2020 19:51:35 -0600 Subject: [PATCH 23/26] proper amount of vertices for underlines --- src/render/webgl-text-bg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index a86451c3..d826cb3a 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -300,7 +300,7 @@ export default (webgl: WebGL) => { // @ts-ignore webgl.gl.uniform1i(program.vars.shouldShowCursor, false) webgl.gl.uniform1f(program.vars.hlidType, 2) - webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 6, buffer.length / 4) + webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 12, buffer.length / 4) // @ts-ignore webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) } From 22502744f1db7c2700b964b9a1282ab80356c5f4 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Nov 2020 20:06:59 -0600 Subject: [PATCH 24/26] Support horizontal guicursor and format --- src/core/cursor.ts | 2 +- src/render/webgl-text-bg.ts | 36 ++++++++++++++++++----------------- src/render/webgl.ts | 2 +- src/windows/window-manager.ts | 1 - 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/core/cursor.ts b/src/core/cursor.ts index 19fd4353..baaa98da 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -23,7 +23,7 @@ let cursorRequestedToBeHidden = false export const setCursorShape = (shape: CursorShape, size = 20) => { cursor.shape = shape - cursor.size = size; + cursor.size = size windows.webgl.updateCursorShape(shape) } diff --git a/src/render/webgl-text-bg.ts b/src/render/webgl-text-bg.ts index d826cb3a..693b4ed7 100644 --- a/src/render/webgl-text-bg.ts +++ b/src/render/webgl-text-bg.ts @@ -2,12 +2,12 @@ import { getColorAtlas, colors } from '../render/highlight-attributes' import { WebGL, VarKind } from '../render/webgl-utils' import { cell } from '../core/workspace' import { hexToRGB } from '../ui/css' -import { CursorShape, } from '../core/cursor' +import { CursorShape } from '../core/cursor' export default (webgl: WebGL) => { const viewport = { x: 0, y: 0, width: 0, height: 0 } let shouldShowCursor = true - let cursorSize = 20 + let cursorShape = 0 /* CursorShape.block */ const program = webgl.setupProgram({ quadVertex: VarKind.Attribute, @@ -156,6 +156,7 @@ export default (webgl: WebGL) => { const w = cell.width const h = cell.height const smallerW = w * (cursorSize / 100.0) + const percentH = h * (cursorSize / 100.0) const next = { boxes: new Float32Array([ @@ -208,28 +209,28 @@ export default (webgl: WebGL) => { 0, h - 1, smallerW, - h, + percentH, 0, - h, + percentH, smallerW, h - 1, smallerW, - h, + percentH, 0, h - 1, smallerW, h - 1, w, - h, + percentH, smallerW, - h, + percentH, w, h - 1, w, - h, + percentH, smallerW, h - 1, @@ -284,25 +285,28 @@ export default (webgl: WebGL) => { readjustViewportMaybe(x, y, width, height) wrenderBuffer.setData(buffer) + if (shouldShowCursor && cursorShape == 2) + webgl.gl.uniform1i(program.vars.shouldShowCursor, 0 /* false */) // background quadBuffer.setData(quads.boxes) webgl.gl.uniform1f(program.vars.hlidType, 0) webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 12, buffer.length / 4) + webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor ? 1 : 0) + // underlines quadBuffer.setData(quads.lines) - // @ts-ignore <- for using a boolean with `uniform1i` // Just want to ignore the cursor logic in the vertex shader for underlines, // so set shouldShowCursor to false, then back to it's previous value after // the draw call. - if (shouldShowCursor) - // @ts-ignore - webgl.gl.uniform1i(program.vars.shouldShowCursor, false) + if (shouldShowCursor && cursorShape != 2 /* CursorShape.underline */) + webgl.gl.uniform1i(program.vars.shouldShowCursor, 0 /* false */) + webgl.gl.uniform1f(program.vars.hlidType, 2) webgl.gl.drawArraysInstanced(webgl.gl.TRIANGLES, 0, 12, buffer.length / 4) - // @ts-ignore - webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor) + + webgl.gl.uniform1i(program.vars.shouldShowCursor, shouldShowCursor ? 1 : 0) } const showCursor = (enable: boolean) => ( @@ -315,9 +319,8 @@ export default (webgl: WebGL) => { webgl.gl.uniform4fv(program.vars.cursorColor, [...color, 1]) } - const updateCursorSize = (size: number) => cursorSize = size - const updateCursorShape = (shape: CursorShape) => { + cursorShape = shape webgl.gl.uniform1i(program.vars.cursorShape, shape) } @@ -363,7 +366,6 @@ export default (webgl: WebGL) => { showCursor, updateCursorPosition, updateCursorShape, - updateCursorSize, updateCursorColor, } } diff --git a/src/render/webgl.ts b/src/render/webgl.ts index 064d5395..d689c655 100644 --- a/src/render/webgl.ts +++ b/src/render/webgl.ts @@ -83,7 +83,7 @@ const nutella = () => { const gridBuffer = CreateWebGLBuffer() let dataBuffer = new Float32Array() - const updateGridId = (newGridId: number) => gridId = newGridId + const updateGridId = (newGridId: number) => (gridId = newGridId) const resize = (rows: number, cols: number) => { const width = cols * cell.width diff --git a/src/windows/window-manager.ts b/src/windows/window-manager.ts index 714c19f1..036ff991 100644 --- a/src/windows/window-manager.ts +++ b/src/windows/window-manager.ts @@ -9,7 +9,6 @@ import { throttle } from '../support/utils' import windowSizer from '../windows/sizer' import api from '../core/instance-api' - export const size = { width: 0, height: 0 } export const webgl = CreateWebGLRenderer() const windows = new Map() From 47729c9b6f8a329b39f225fe49d9d779eb57b0c7 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Nov 2020 20:09:05 -0600 Subject: [PATCH 25/26] "Fix" TS errors --- src/components/extensions/grep.tsx | 4 ++-- src/components/extensions/lsp-references.tsx | 4 ++-- src/core/cursor.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/extensions/grep.tsx b/src/components/extensions/grep.tsx index 98cb546a..fcef0e57 100644 --- a/src/components/extensions/grep.tsx +++ b/src/components/extensions/grep.tsx @@ -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' @@ -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 = ( diff --git a/src/components/extensions/lsp-references.tsx b/src/components/extensions/lsp-references.tsx index 20f75c17..1f557f9c 100644 --- a/src/components/extensions/lsp-references.tsx +++ b/src/components/extensions/lsp-references.tsx @@ -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' @@ -82,7 +82,7 @@ const selectResult = (references: Refs[], ix: number, subix: number) => { line: lineNum - 1, column: column - 1, }) - showCursorline() + // TODO(smolck): showCursorline() } const highlightPattern = ( diff --git a/src/core/cursor.ts b/src/core/cursor.ts index baaa98da..ed7d7fe3 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -57,7 +57,7 @@ export const showCursor = () => { Object.assign(cursor, { visible: true }) } -// export const showCursorline = () => (cursorline.style.display = '') +// TODO(smolck): export const showCursorline = () => (cursorline.style.display = '') export const moveCursor = (row: number, col: number) => { Object.assign(cursor, { row, col }) From 596675f3c2a047a797624dcb264085932ab787f2 Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Nov 2020 20:10:37 -0600 Subject: [PATCH 26/26] cleanup --- src/bootstrap/index.html | 2 -- src/core/cursor.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/bootstrap/index.html b/src/bootstrap/index.html index f07f6a57..6f3e8c43 100644 --- a/src/bootstrap/index.html +++ b/src/bootstrap/index.html @@ -166,8 +166,6 @@
-
-
diff --git a/src/core/cursor.ts b/src/core/cursor.ts index ed7d7fe3..2660825a 100644 --- a/src/core/cursor.ts +++ b/src/core/cursor.ts @@ -18,8 +18,6 @@ export const cursor = { let cursorEnabled = false let cursorRequestedToBeHidden = false -// export const getCursorBoundingClientRect = () => -// cursorline.getBoundingClientRect() export const setCursorShape = (shape: CursorShape, size = 20) => { cursor.shape = shape