From 2feea7e6b2e27afd9b5571dd60baccc75ea9b160 Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Fri, 17 May 2024 15:27:22 +0100 Subject: [PATCH 1/2] fix: e motion (#21) --- lua/precognition/horizontal_motions.lua | 21 ++++++++++++------- .../precognition/horizontal_motions_spec.lua | 20 ++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lua/precognition/horizontal_motions.lua b/lua/precognition/horizontal_motions.lua index 4782af3..0abaf64 100644 --- a/lua/precognition/horizontal_motions.lua +++ b/lua/precognition/horizontal_motions.lua @@ -48,11 +48,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 @@ -69,20 +68,26 @@ function M.end_of_word(str, cursorcol, _linelen) end if c_class ~= 0 and next_char_class ~= 0 then - while utils.char_class(char) == c_class and offset <= len do + 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) + 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 == 0 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 diff --git a/tests/precognition/horizontal_motions_spec.lua b/tests/precognition/horizontal_motions_spec.lua index 2ac76eb..ef12043 100644 --- a/tests/precognition/horizontal_motions_spec.lua +++ b/tests/precognition/horizontal_motions_spec.lua @@ -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)) @@ -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) From d8953491dc4697e0f245ce0a777457ec834e8952 Mon Sep 17 00:00:00 2001 From: Tristan Knight Date: Fri, 17 May 2024 19:11:13 +0100 Subject: [PATCH 2/2] chore: enum types (#22) --- lua/precognition/horizontal_motions.lua | 19 +++++++++++-------- lua/precognition/utils.lua | 16 ++++++++++++---- tests/precognition/char_spec.lua | 9 +++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lua/precognition/horizontal_motions.lua b/lua/precognition/horizontal_motions.lua index 0abaf64..d5e1b82 100644 --- a/lua/precognition/horizontal_motions.lua +++ b/lua/precognition/horizontal_motions.lua @@ -1,4 +1,5 @@ local utils = require("precognition.utils") +local cc = utils.char_classes local M = {} @@ -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 @@ -60,26 +61,28 @@ 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 + 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 + 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 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 == 0 then + if next_char_class == cc.whitespace then rev_offset = next_word_start else rev_offset = M.end_of_word(str, next_word_start, linelen) @@ -111,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 diff --git a/lua/precognition/utils.lua b/lua/precognition/utils.lua index d12b50d..442031a 100644 --- a/lua/precognition/utils.lua +++ b/lua/precognition/utils.lua @@ -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 diff --git a/tests/precognition/char_spec.lua b/tests/precognition/char_spec.lua index 0fb3c2c..098b7b5 100644 --- a/tests/precognition/char_spec.lua +++ b/tests/precognition/char_spec.lua @@ -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)