Skip to content

Commit

Permalink
Add cursor overlay in beta (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbalatero authored Nov 4, 2020
1 parent 03249e1 commit c908f2a
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 1 deletion.
15 changes: 15 additions & 0 deletions lib/accessibility_buffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,21 @@ function AccessibilityBuffer:getRangeForLineNumber(lineNumber)
return Selection.fromRange(range)
end

function AccessibilityBuffer:isAtLastVisibleCharacter()
local visibleRange = self
:getCurrentElement()
:attributeValue("AXVisibleCharacterRange")

if not visibleRange then return false end

local selection = self:getSelectionRange()
if not selection then return false end

local lastVisibleIndex = visibleRange.length + visibleRange.location

return lastVisibleIndex <= selection.location
end

function AccessibilityBuffer.getCurrentApplication()
return ax.applicationElement(hs.application.frontmostApplication())
end
Expand Down
85 changes: 85 additions & 0 deletions lib/block_cursor.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
local AccessibilityBuffer = dofile(vimModeScriptPath .. "lib/accessibility_buffer.lua")

local BlockCursor = {}

function BlockCursor:new()
local canvas = hs.canvas.new({ x = 0, y = 0, h = 1, w = 1 })
local rectangleElementIndex = 1

canvas:level('overlay')
canvas:insertElement(
{
type = 'rectangle',
action = 'fill',
fillColor = { red = 0, green = 0, blue = 0, alpha = 0.2 },
frame = { x = "0%", y = "0%", h = "100%", w = "100%", },
withShadow = false
},
rectangleElementIndex
)

local cursor = {
canvas = canvas,
}

setmetatable(cursor, self)
self.__index = self

cursor.redrawTimer = hs.timer.new(1 / 60, function()
local result = cursor:_renderFrame()

if not result then
cursor:hide()
end
end)

return cursor
end

function BlockCursor:show()
if self.canvas:isShowing() then return nil end

self.redrawTimer:start()
self.canvas:show()
end

function BlockCursor:hide()
if not self.canvas:isShowing() then return nil end

self.canvas:hide()
self.redrawTimer:stop()
end

-- Renders a single frame. Returns `true` if successful.
function BlockCursor:_renderFrame()
local buffer = AccessibilityBuffer:new()
if not buffer:isValid() then return false end

local currentElement = buffer:getCurrentElement()

-- We don't want to draw the cursor if we're at the end of the textbox (or
-- past the end!)
if buffer:isAtLastVisibleCharacter() then return false end

-- Get the range for the next character after the blinking cursor
local range = buffer:getSelectionRange()
local caretRange = {
location = range.location,
length = 1,
}

-- Get the { h, w, x, y } bounding box for the next character's range so we
-- can draw over it.
local bounds = currentElement:parameterizedAttributeValue(
"AXBoundsForRange",
caretRange
)

-- move the position and resize
self.canvas:topLeft({ x = bounds.x, y = bounds.y })
self.canvas:size({ h = bounds.h, w = bounds.w })

return true
end

return BlockCursor
15 changes: 14 additions & 1 deletion lib/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ function Config:new(options)
alert = {
font = "Courier New"
},
betaFeatures = {},
shouldShowAlertInNormalMode = true,
shouldDimScreenInNormalMode = true
shouldDimScreenInNormalMode = true,
}

setmetatable(config, self)
Expand All @@ -26,4 +27,16 @@ function Config:setOptions(options)
end
end

function Config:isBetaFeatureEnabled(feature)
return not not self.betaFeatures[feature]
end

function Config:enableBetaFeature(feature)
self.betaFeatures[feature] = true
end

function Config:disableBetaFeature(feature)
self.betaFeatures[feature] = false
end

return Config
2 changes: 2 additions & 0 deletions lib/state.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ local function createStateMachine(vim)
},
callbacks = {
onenterNormal = function()
vim:enableBlockCursor()
vim:disableSequence()
vim:resetCommandState()
vim:setNormalMode()
vim:enterModal('normal')
end,
onenterInsert = function()
vim.visualCaretPosition = nil
vim:disableBlockCursor()
vim:exitAllModals()
vim:setInsertMode()
vim:resetCommandState()
Expand Down
18 changes: 18 additions & 0 deletions lib/vim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dofile(vimModeScriptPath .. "lib/utils/benchmark.lua")
local AccessibilityBuffer = dofile(vimModeScriptPath .. "lib/accessibility_buffer.lua")
local AccessibilityStrategy = dofile(vimModeScriptPath .. "lib/strategies/accessibility_strategy.lua")
local AppWatcher = dofile(vimModeScriptPath .. "lib/app_watcher.lua")
local BlockCursor = dofile(vimModeScriptPath .. "lib/block_cursor.lua")
local CommandState = dofile(vimModeScriptPath .. "lib/command_state.lua")
local Config = dofile(vimModeScriptPath .. "lib/config.lua")
local KeySequence = dofile(vimModeScriptPath .. "lib/key_sequence.lua")
Expand Down Expand Up @@ -51,6 +52,7 @@ function VimMode:new()

vim:resetCommandState()

vim.blockCursor = BlockCursor:new()
vim.config = Config:new()
vim.enabled = true
vim.mode = 'insert'
Expand Down Expand Up @@ -98,6 +100,10 @@ end

---------------------------

function VimMode:enableBetaFeature(feature)
self.config:enableBetaFeature(feature)
end

function VimMode:shouldShowAlertInNormalMode(showAlert)
self.config.shouldShowAlertInNormalMode = showAlert
return self
Expand Down Expand Up @@ -220,6 +226,18 @@ function VimMode:exit()
self.state:enterInsert()
end

function VimMode:enableBlockCursor()
if not self.config:isBetaFeatureEnabled('block_cursor_overlay') then return end

self.blockCursor:show()
end

function VimMode:disableBlockCursor()
if not self.config:isBetaFeatureEnabled('block_cursor_overlay') then return end

self.blockCursor:hide()
end

function VimMode:setInsertMode()
self.mode = "insert"

Expand Down

0 comments on commit c908f2a

Please sign in to comment.