Skip to content

Commit

Permalink
Merge branch 'main' into count_motions
Browse files Browse the repository at this point in the history
  • Loading branch information
tris203 authored May 17, 2024
2 parents 4eff360 + d895349 commit 2ea19ae
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 25 deletions.
38 changes: 23 additions & 15 deletions lua/precognition/horizontal_motions.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local utils = require("precognition.utils")
local cc = utils.char_classes

local M = {}

Expand Down Expand Up @@ -28,14 +29,14 @@ function M.next_word_boundary(str, cursorcol, _linelen)
local char = vim.fn.strcharpart(str, offset - 1, 1)
local c_class = utils.char_class(char)

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

while utils.char_class(char) == 0 and offset <= len do
while utils.char_class(char) == cc.whitespace and offset <= len do
offset = offset + 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
Expand All @@ -48,11 +49,10 @@ end

---@param str string
---@param cursorcol integer
---@param _linelen integer
---@param linelen integer
---@return Precognition.PlaceLoc
function M.end_of_word(str, cursorcol, _linelen)
local len = vim.fn.strcharlen(str)
if cursorcol >= len then
function M.end_of_word(str, cursorcol, linelen)
if cursorcol >= linelen then
return 0
end
local offset = cursorcol
Expand All @@ -61,28 +61,36 @@ function M.end_of_word(str, cursorcol, _linelen)
local next_char_class = utils.char_class(vim.fn.strcharpart(str, (offset - 1) + 1, 1))
local rev_offset

if (c_class == 1 and next_char_class ~= 1) or (next_char_class == 1 and c_class ~= 1) then
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))
end

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

if c_class == 0 or next_char_class == 0 then
local next_word_start = M.next_word_boundary(str, offset, 0)
if c_class == cc.whitespace or next_char_class == cc.whitespace then
local next_word_start = M.next_word_boundary(str, cursorcol, linelen)
if next_word_start then
rev_offset = M.end_of_word(str, next_word_start + 1, 0)
next_char_class = utils.char_class(vim.fn.strcharpart(str, (next_word_start - 1) + 1, 1))
--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)
end
end
end

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

Expand All @@ -106,8 +114,8 @@ function M.prev_word_boundary(str, cursorcol, _linelen)
local char = vim.fn.strcharpart(str, offset - 1, 1)
local c_class = utils.char_class(char)

if c_class == 0 then
while utils.char_class(char) == 0 and offset >= 0 do
if c_class == cc.whitespace then
while utils.char_class(char) == cc.whitespace and offset >= 0 do
offset = offset - 1
char = vim.fn.strcharpart(str, offset - 1, 1)
end
Expand Down
16 changes: 12 additions & 4 deletions lua/precognition/utils.lua
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
local M = {}

---@enum cc
M.char_classes = {
whitespace = 0,
other = 1,
word = 2,
}

---@param char string
---@return integer
function M.char_class(char)
local cc = M.char_classes
local byte = string.byte(char)

if byte and byte < 0x100 then
if char == " " or char == "\t" or char == "\0" then
return 0 -- whitespace
return cc.whitespace
end
if char == "_" or char:match("%w") then
return 2 -- word character
return cc.word
end
return 1 -- other
return cc.other
end

return 1 -- scary unicode edge cases go here
return cc.other -- scary unicode edge cases go here
end

---@param bufnr? integer
Expand Down
9 changes: 9 additions & 0 deletions tests/precognition/char_spec.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
local utils = require("precognition.utils")
local cc = utils.char_classes
---@diagnostic disable-next-line: undefined-field
local eq = assert.are.same

describe("static classes", function()
it("are set correctly", function()
eq(cc.whitespace, 0)
eq(cc.other, 1)
eq(cc.word, 2)
end)
end)

describe("char classing", function()
it("white space is classeed", function()
eq(utils.char_class(" "), 0)
Expand Down
20 changes: 14 additions & 6 deletions tests/precognition/horizontal_motions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ describe("boundaries", function()
eq(3, hm.end_of_word("abc efg", 2, 7))
eq(7, hm.end_of_word("abc efg", 3, 7))

eq(7, hm.end_of_word("slighly more complex test", 1, 22))
eq(7, hm.end_of_word("slighly more complex test", 2, 22))
eq(12, hm.end_of_word("slighly more complex test", 10, 22))
eq(20, hm.end_of_word("slighly more complex test", 13, 22))
eq(20, hm.end_of_word("slighly more complex test", 15, 22))
eq(25, hm.end_of_word("slighly more complex test", 21, 22))
eq(7, hm.end_of_word("slighly more complex test", 1, 25))
eq(7, hm.end_of_word("slighly more complex test", 2, 25))
eq(12, hm.end_of_word("slighly more complex test", 10, 25))
eq(20, hm.end_of_word("slighly more complex test", 13, 25))
eq(20, hm.end_of_word("slighly more complex test", 15, 25))
eq(25, hm.end_of_word("slighly more complex test", 21, 25))

eq(14, hm.end_of_word(" myFunction(example, stuff)", 1, 30))
eq(14, hm.end_of_word(" myFunction(example, stuff)", 2, 30))
Expand Down Expand Up @@ -175,4 +175,12 @@ describe("edge case", function()
local str = "there is a space "
eq(0, hm.end_of_word(str, 16, #str))
end)

it("single character next word ends", function()
local str = "show_something = true,"
eq(14, hm.end_of_word(str, 1, #str))
eq(16, hm.end_of_word(str, 14, #str))
eq(16, hm.end_of_word(str, 15, #str))
eq(22, hm.end_of_word(str, 21, #str))
end)
end)

0 comments on commit 2ea19ae

Please sign in to comment.