Skip to content

Commit

Permalink
fix: more type safety for DX
Browse files Browse the repository at this point in the history
  • Loading branch information
tris203 committed May 5, 2024
1 parent f1f6b48 commit e720d53
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 134 deletions.
20 changes: 10 additions & 10 deletions lua/precognition/horizontal_motions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ local M = {}
---@param str string
---@param _cursorcol integer
---@param _linelen integer
---@return integer | nil
---@return PlaceLoc
function M.line_start_non_whitespace(str, _cursorcol, _linelen)
return str:find("%S") or 0
end

---@param _str string
---@param _cursorcol integer
---@param linelen integer
---@return integer | nil
---@return PlaceLoc
function M.line_end(_str, _cursorcol, linelen)
return linelen or nil
end

---@param str string
---@param cursorcol integer
---@param _linelen integer
---@return integer | nil
---@return PlaceLoc
function M.next_word_boundary(str, cursorcol, _linelen)
local offset = cursorcol
local len = vim.fn.strcharlen(str)
Expand All @@ -40,7 +40,7 @@ function M.next_word_boundary(str, cursorcol, _linelen)
char = vim.fn.strcharpart(str, offset - 1, 1)
end
if offset > len then
return nil
return 0
end

return offset
Expand All @@ -49,11 +49,11 @@ end
---@param str string
---@param cursorcol integer
---@param _linelen integer
---@return integer | nil
---@return PlaceLoc
function M.end_of_word(str, cursorcol, _linelen)
local len = vim.fn.strcharlen(str)
if cursorcol >= len then
return nil
return 0
end
local offset = cursorcol
local char = vim.fn.strcharpart(str, offset - 1, 1)
Expand Down Expand Up @@ -83,7 +83,7 @@ function M.end_of_word(str, cursorcol, _linelen)
end

if rev_offset ~= nil and rev_offset <= 0 then
return nil
return 0
end

if rev_offset ~= nil then
Expand All @@ -95,7 +95,7 @@ end
---@param str string
---@param cursorcol integer
---@param _linelen integer
---@return integer | nil
---@return PlaceLoc
function M.prev_word_boundary(str, cursorcol, _linelen)
local len = vim.fn.strcharlen(str)
local offset = cursorcol - 1
Expand All @@ -116,12 +116,12 @@ function M.prev_word_boundary(str, cursorcol, _linelen)
--if remaining string is whitespace, return nil_wrap
local remaining = string.sub(str, offset)
if remaining:match("^%s*$") and #remaining > 0 then
return nil
return 0
end
end

if offset == nil or offset > len or offset < 0 then
return nil
return 0
end
return offset + 1
end
Expand Down
116 changes: 72 additions & 44 deletions lua/precognition/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@ local vm = require("precognition.vertical_motions")

local M = {}

---@alias SupportedHints "^" | "$" | "w" | "e" | "b"
---@alias SupportedGutterHints "G" | "gg" | "{" | "}"
---@alias Dollar "$"
---@alias PrevParagraph "{"
---@alias NextParagraph "}"

---@class HintOpts
---@field text string
---@field prio integer

---@class HintConfig
---@alias PlaceLoc integer

---@class (exact) HintConfig
---@field w HintOpts
---@field e HintOpts
---@field b HintOpts
---@field ["^"] HintOpts
---@field ["$"] HintOpts
---@field Carat HintOpts
---@field Dollar HintOpts

---@class GutterHintConfig
---@field G HintOpts
---@field gg HintOpts
---@field ["{"] HintOpts
---@field ["}"] HintOpts
---@field PrevParagraph HintOpts
---@field NextParagraph HintOpts

---@class Precognition.Config
---@field startVisible boolean
Expand All @@ -33,28 +36,38 @@ local M = {}
---@field hints? HintConfig
---@field gutterHints? GutterHintConfig

---@alias Precognition.VirtLine { SupportedHints: integer | nil }

---@alias Precognition.GutterHints { SupportedGutterHints: integer | nil }
---@class (exact) Precognition.VirtLine
---@field w PlaceLoc
---@field e PlaceLoc
---@field b PlaceLoc
---@field Carat PlaceLoc
---@field Dollar PlaceLoc

---@class (exact) Precognition.GutterHints
---@field G PlaceLoc
---@field gg PlaceLoc
---@field PrevParagraph PlaceLoc
---@field NextParagraph PlaceLoc

---@type HintConfig
local defaultHintConfig = {
Carat = { text = "^", prio = 1 },
Dollar = { text = "$", prio = 1 },
w = { text = "w", prio = 10 },
b = { text = "b", prio = 9 },
e = { text = "e", prio = 8 },
}

---@type Precognition.Config
local default = {
startVisible = true,
hints = {
["^"] = { text = "^", prio = 1 },
["$"] = { text = "$", prio = 1 },
["w"] = { text = "w", prio = 10 },
-- ["W"] = "W",
["b"] = { text = "b", prio = 9 },
["e"] = { text = "e", prio = 8 },
-- ["ge"] = "ge", -- should we support multi-char / multi-byte hints?
},
hints = defaultHintConfig,
gutterHints = {
--prio is not currentlt used for gutter hints
["G"] = { text = "G", prio = 1 },
["gg"] = { text = "gg", prio = 1 },
["{"] = { text = "{", prio = 1 },
["}"] = { text = "}", prio = 1 },
G = { text = "G", prio = 1 },
gg = { text = "gg", prio = 1 },
PrevParagraph = { text = "{", prio = 1 },
NextParagraph = { text = "}", prio = 1 },
},
}

Expand Down Expand Up @@ -83,19 +96,32 @@ local gutter_group = "precognition_gutter"
---@param line_len integer
---@return table
local function build_virt_line(marks, line_len)
if not marks then
return {}
end
if line_len == 0 then
return {}
end
local virt_line = {}
local line = string.rep(" ", line_len)

for mark, loc in pairs(marks) do
local hint = config.hints[mark].text or mark
local col = loc

if col ~= nil then
if col ~= 0 then
local existing = line:sub(col, col)
if existing == " " and existing ~= hint then
line = line:sub(1, col - 1) .. hint .. line:sub(col + 1)
else -- if the character is not a space, then we need to check the prio
if existing ~= "" and config.hints[mark].prio > config.hints[existing].prio then
local existingKey
for key, value in pairs(config.hints) do
if value.text == existing then
existingKey = key
break
end
end
if existing ~= " " and config.hints[mark].prio > config.hints[existingKey].prio then
line = line:sub(1, col - 1) .. hint .. line:sub(col + 1)
end
end
Expand All @@ -108,13 +134,13 @@ end

---@return Precognition.GutterHints
local function build_gutter_hints()
---@type Precognition.GutterHints
local gutter_hints = {
["G"] = vm.file_end(),
["gg"] = vm.file_start(),
["{"] = vm.prev_paragraph_line(),
["}"] = vm.next_paragraph_line(),
G = vm.file_end(),
gg = vm.file_start(),
PrevParagraph = vm.prev_paragraph_line(),
NextParagraph = vm.next_paragraph_line(),
}

return gutter_hints
end

Expand All @@ -136,17 +162,16 @@ local function apply_gutter_hints(gutter_hints, bufnr)
text = config.gutterHints[hint].text,
texthl = "Comment",
})
local ok, res =
pcall(vim.fn.sign_place, 0, gutter_group, gutter_name_prefix .. config.gutterHints[hint].text, bufnr, {
lnum = loc,
priority = 100,
})
local ok, res = pcall(vim.fn.sign_place, 0, gutter_group, gutter_name_prefix .. hint, bufnr, {
lnum = loc,
priority = 100,
})
if ok then
gutter_signs_cache[hint] = { line = loc, id = res }
end
if not ok and loc ~= 0 then
vim.notify_once(
"Failed to place sign: " .. config.gutterHints[hint].text .. " at line " .. loc,
"Failed to place sign: " .. hint .. " at line " .. loc .. vim.inspect(res),
vim.log.levels.WARN
)
end
Expand All @@ -171,14 +196,17 @@ local function on_cursor_hold()

-- FIXME: Lua patterns don't play nice with utf-8, we need a better way to
-- get char offsets for more complex motions.
--
---@type Precognition.VirtLine
local virtual_line_marks = {
Carat = hm.line_start_non_whitespace(cur_line, cursorcol, line_len),
w = hm.next_word_boundary(cur_line, cursorcol, line_len),
e = hm.end_of_word(cur_line, cursorcol, line_len),
b = hm.prev_word_boundary(cur_line, cursorcol, line_len),
Dollar = hm.line_end(cur_line, cursorcol, line_len),
}

local virt_line = build_virt_line({
["w"] = hm.next_word_boundary(cur_line, cursorcol, line_len),
["e"] = hm.end_of_word(cur_line, cursorcol, line_len),
["b"] = hm.prev_word_boundary(cur_line, cursorcol, line_len),
["^"] = hm.line_start_non_whitespace(cur_line, cursorcol, line_len),
["$"] = hm.line_end(cur_line, cursorcol, line_len),
}, line_len)
local virt_line = build_virt_line(virtual_line_marks, line_len)

-- TODO: can we add indent lines to the virt line to match indent-blankline or similar (if installed)?

Expand Down Expand Up @@ -216,7 +244,7 @@ local function on_insert_enter(ev)
end

local function on_buf_edit()
apply_gutter_hints(build_gutter_hints(), vim.api.nvim_get_current_buf())
apply_gutter_hints(build_gutter_hints())
end

local function on_buf_leave(ev)
Expand Down
12 changes: 6 additions & 6 deletions lua/precognition/vertical_motions.lua
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
local M = {}

---@return integer
---@return PlaceLoc
function M.file_start()
return 1
end

---@param bufnr? integer
---@return integer
---@return PlaceLoc
function M.file_end(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
return vim.api.nvim_buf_line_count(bufnr)
end

---@param bufnr? integer
---@return integer | nil
---@return PlaceLoc
function M.next_paragraph_line(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
local loc
local loc = 0
vim.api.nvim_buf_call(bufnr, function()
local found
local visibleline = vim.fn.line("w$")
Expand All @@ -43,10 +43,10 @@ function M.next_paragraph_line(bufnr)
end

---@param bufnr? integer
---@return integer | nil
---@return PlaceLoc
function M.prev_paragraph_line(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
local loc
local loc = 0
vim.api.nvim_buf_call(bufnr, function()
local found
local visibleline = vim.fn.line("w0")
Expand Down
Loading

0 comments on commit e720d53

Please sign in to comment.