Skip to content

Commit

Permalink
feat: big word support (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
tris203 authored May 21, 2024
1 parent fd62c75 commit 672a00f
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 136 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
>
> 1. foreknowledge of an event, especially as a form of extrasensory perception.
**precognition.nvim** is a nvim plugin for discovering motions (Both vertical and horizontal) to navigate your current buffer
**precognition.nvim** assists with discovering motions (Both vertical and horizontal) to navigate your current buffer

![image](https://github.com/tris203/precognition.nvim/assets/18444302/ea24caee-85da-42d8-b0e9-555b47268643)

Expand All @@ -28,9 +28,12 @@ return {
-- w = { text = "w", prio = 10 },
-- b = { text = "b", prio = 9 },
-- e = { text = "e", prio = 8 },
-- W = { text = "W", prio = 7 },
-- B = { text = "B", prio = 6 },
-- E = { text = "E", prio = 5 },
-- },
-- gutterHints = {
-- --prio is not currentlt used for gutter hints
-- -- prio is not currently used for gutter hints
-- G = { text = "G", prio = 1 },
-- gg = { text = "gg", prio = 1 },
-- PrevParagraph = { text = "{", prio = 1 },
Expand Down
39 changes: 21 additions & 18 deletions lua/precognition/horizontal_motions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,22 @@ end
---@param str string
---@param cursorcol integer
---@param _linelen integer
---@param big_word boolean
---@return Precognition.PlaceLoc
function M.next_word_boundary(str, cursorcol, _linelen)
function M.next_word_boundary(str, cursorcol, _linelen, big_word)
local offset = cursorcol
local len = vim.fn.strcharlen(str)
local char = vim.fn.strcharpart(str, offset - 1, 1)
local c_class = utils.char_class(char)
local c_class = utils.char_class(char, big_word)

if c_class ~= cc.whitespace then
while utils.char_class(char) == c_class and offset <= len do
while utils.char_class(char, big_word) == c_class and offset <= len do
offset = offset + 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
end

while utils.char_class(char) == cc.whitespace and offset <= len do
while utils.char_class(char, big_word) == cc.whitespace and offset <= len do
offset = offset + 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
Expand All @@ -56,42 +57,43 @@ end
---@param str string
---@param cursorcol integer
---@param linelen integer
---@param big_word boolean
---@return Precognition.PlaceLoc
function M.end_of_word(str, cursorcol, linelen)
function M.end_of_word(str, cursorcol, linelen, big_word)
if cursorcol >= linelen then
return 0
end
local offset = cursorcol
local char = vim.fn.strcharpart(str, offset - 1, 1)
local c_class = utils.char_class(char)
local next_char_class = utils.char_class(vim.fn.strcharpart(str, (offset - 1) + 1, 1))
local c_class = utils.char_class(char, big_word)
local next_char_class = utils.char_class(vim.fn.strcharpart(str, (offset - 1) + 1, 1), big_word)
local rev_offset

if
(c_class == cc.other and next_char_class ~= cc.other) or (next_char_class == cc.other and c_class ~= cc.other)
then
offset = offset + 1
char = vim.fn.strcharpart(str, offset - 1, 1)
c_class = utils.char_class(char)
next_char_class = utils.char_class(vim.fn.strcharpart(str, (offset - 1) + 1, 1))
c_class = utils.char_class(char, big_word)
next_char_class = utils.char_class(vim.fn.strcharpart(str, (offset - 1) + 1, 1), big_word)
end

if c_class ~= cc.whitespace and next_char_class ~= cc.whitespace then
while utils.char_class(char) == c_class and offset <= linelen do
while utils.char_class(char, big_word) == c_class and offset <= linelen do
offset = offset + 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
end

if c_class == cc.whitespace or next_char_class == cc.whitespace then
local next_word_start = M.next_word_boundary(str, cursorcol, linelen)
local next_word_start = M.next_word_boundary(str, cursorcol, linelen, big_word)
if next_word_start then
next_char_class = utils.char_class(vim.fn.strcharpart(str, (next_word_start - 1) + 1, 1))
next_char_class = utils.char_class(vim.fn.strcharpart(str, (next_word_start - 1) + 1, 1), big_word)
--next word is single char
if next_char_class == cc.whitespace then
rev_offset = next_word_start
else
rev_offset = M.end_of_word(str, next_word_start, linelen)
rev_offset = M.end_of_word(str, next_word_start, linelen, big_word)
end
end
end
Expand All @@ -113,22 +115,23 @@ end
---@param str string
---@param cursorcol integer
---@param _linelen integer
---@param big_word boolean
---@return Precognition.PlaceLoc
function M.prev_word_boundary(str, cursorcol, _linelen)
function M.prev_word_boundary(str, cursorcol, _linelen, big_word)
local len = vim.fn.strcharlen(str)
local offset = cursorcol - 1
local char = vim.fn.strcharpart(str, offset - 1, 1)
local c_class = utils.char_class(char)
local c_class = utils.char_class(char, big_word)

if c_class == cc.whitespace then
while utils.char_class(char) == cc.whitespace and offset >= 0 do
while utils.char_class(char, big_word) == cc.whitespace and offset >= 0 do
offset = offset - 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
c_class = utils.char_class(char)
c_class = utils.char_class(char, big_word)
end

while utils.char_class(char) == c_class and offset >= 0 do
while utils.char_class(char, big_word) == c_class and offset >= 0 do
offset = offset - 1
char = vim.fn.strcharpart(str, offset - 1, 1)
--if remaining string is whitespace, return nil_wrap
Expand Down
12 changes: 9 additions & 3 deletions lua/precognition/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ local defaultHintConfig = {
w = { text = "w", prio = 10 },
b = { text = "b", prio = 9 },
e = { text = "e", prio = 8 },
W = { text = "W", prio = 7 },
B = { text = "B", prio = 6 },
E = { text = "E", prio = 5 },
}

---@type Precognition.Config
Expand Down Expand Up @@ -213,9 +216,12 @@ local function display_marks()
---@type Precognition.VirtLine
local virtual_line_marks = {
Caret = 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),
w = hm.next_word_boundary(cur_line, cursorcol, line_len, false),
e = hm.end_of_word(cur_line, cursorcol, line_len, false),
b = hm.prev_word_boundary(cur_line, cursorcol, line_len, false),
W = hm.next_word_boundary(cur_line, cursorcol, line_len, true),
E = hm.end_of_word(cur_line, cursorcol, line_len, true),
B = hm.prev_word_boundary(cur_line, cursorcol, line_len, true),
MatchingPair = hm.matching_pair(cur_line, cursorcol, line_len)(cur_line, cursorcol, line_len),
Dollar = hm.line_end(cur_line, cursorcol, line_len),
Zero = 1,
Expand Down
6 changes: 4 additions & 2 deletions lua/precognition/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ M.char_classes = {
}

---@param char string
---@param big_word boolean
---@return integer
function M.char_class(char)
function M.char_class(char, big_word)
big_word = big_word or false
local cc = M.char_classes
local byte = string.byte(char)

Expand All @@ -18,7 +20,7 @@ function M.char_class(char)
return cc.whitespace
end
if char == "_" or char:match("%w") then
return cc.word
return big_word and cc.other or cc.word
end
return cc.other
end
Expand Down
41 changes: 31 additions & 10 deletions tests/precognition/char_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,42 @@ end)

describe("char classing", function()
it("white space is classeed", function()
eq(utils.char_class(" "), 0)
eq(utils.char_class("\t"), 0)
eq(utils.char_class("\0"), 0)
eq(utils.char_class(" ", false), 0)
eq(utils.char_class("\t", false), 0)
eq(utils.char_class("\0", false), 0)
end)

it("word characters are classed", function()
eq(utils.char_class("_"), 2)
eq(utils.char_class("a"), 2)
eq(utils.char_class("A"), 2)
eq(utils.char_class("0"), 2)
eq(utils.char_class("_", false), 2)
eq(utils.char_class("a", false), 2)
eq(utils.char_class("A", false), 2)
eq(utils.char_class("0", false), 2)
end)

it("other characters are classed", function()
eq(utils.char_class("!"), 1)
eq(utils.char_class("@"), 1)
eq(utils.char_class("."), 1)
eq(utils.char_class("!", false), 1)
eq(utils.char_class("@", false), 1)
eq(utils.char_class(".", false), 1)
end)
end)

describe("big_word classing", function()
it("big_word whitespace is classed", function()
eq(utils.char_class(" ", true), 0)
eq(utils.char_class("\t", true), 0)
eq(utils.char_class("\0", true), 0)
end)

it("big_word word characters are classed", function()
eq(utils.char_class("_", true), 1)
eq(utils.char_class("a", true), 1)
eq(utils.char_class("A", true), 1)
eq(utils.char_class("0", true), 1)
end)

it("big_word other characters are classed", function()
eq(utils.char_class("!", true), 1)
eq(utils.char_class("@", true), 1)
eq(utils.char_class(".", true), 1)
end)
end)
Loading

0 comments on commit 672a00f

Please sign in to comment.