From 33a018a045a34d9bb8537188544c67d47f069908 Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 19:46:36 +0000 Subject: [PATCH 01/11] feat(tests): dts testing --- .github/workflows/dts.yml | 27 ++++++++++ Makefile | 10 ++++ tests/precognition/dts.lua | 90 ++++++++++++++++++++++++++++++++ tests/precognition/utils/dts.lua | 52 ++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 .github/workflows/dts.yml create mode 100644 tests/precognition/dts.lua create mode 100644 tests/precognition/utils/dts.lua diff --git a/.github/workflows/dts.yml b/.github/workflows/dts.yml new file mode 100644 index 0000000..63618fa --- /dev/null +++ b/.github/workflows/dts.yml @@ -0,0 +1,27 @@ +name: DTS + +on: + pull_request: + branches: + - "main" + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + nvim-versions: ['nightly'] + os: [ubuntu-latest] + fail-fast: false + name: DTS Tests + steps: + - name: checkout + uses: actions/checkout@v4 + + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: ${{ matrix.nvim-versions }} + + - name: run dts + run: make dts diff --git a/Makefile b/Makefile index bbf2ada..0fb7be0 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ TESTS_INIT=tests/minimal.lua TESTS_DIR=tests/ +DTS_SCRIPT=tests/precognition/dts.lua +SEED_START=0 +NUM_TESTS=500000 .PHONY: test @@ -9,3 +12,10 @@ test: --noplugin \ -u ${TESTS_INIT} \ -c "PlenaryBustedDirectory ${TESTS_DIR} { minimal_init = '${TESTS_INIT}' }" \ + +dts: + @nvim \ + --headless \ + --noplugin \ + -u ${TESTS_INIT} \ + -l ${DTS_SCRIPT} ${SEED_START} ${NUM_TESTS} \ diff --git a/tests/precognition/dts.lua b/tests/precognition/dts.lua new file mode 100644 index 0000000..49168d9 --- /dev/null +++ b/tests/precognition/dts.lua @@ -0,0 +1,90 @@ +local precognition = require("precognition") +local hm = require("precognition.horizontal_motions") +local dts = require("tests.precognition.utils.dts") + +local USAGE = [[ +Runs dts testing for precognition marks + +USAGE: +nvim -u tests/minimal.lua -l tests/precognition/dts.lua SEED_START NUM_SIMS + +]] + +local M = {} + +function M.test(seed) + local data = dts.generate_random_line(seed) + + --TODO: Currently bracket matching only works with M cpoptions + --see `:h %` + vim.o.cpoptions = vim.o.cpoptions .. "M" + + local cur_line = data.line + local cursorcol = data.cursor_col + local line_len = vim.fn.strcharlen(cur_line) + + 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, 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), + -- TODO: fix some edge cases around pairs and we can enable this + -- 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, + } + + local temp_buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(temp_buf, 0, -1, false, { cur_line }) + + for loc, col in pairs(virtual_line_marks) do + local key = precognition.default_hint_config[loc].text + vim.api.nvim_set_current_buf(temp_buf) + vim.fn.setcursorcharpos(1, cursorcol) + local cur_before = vim.fn.getcursorcharpos(0) + vim.api.nvim_feedkeys(key, "ntx", true) + local cur_after = vim.fn.getcursorcharpos(0) + local actual_col = cur_after[3] + if col ~= 0 then + if col ~= actual_col then + vim.print(string.format("[SEED: %d]%s", seed, cur_line)) + vim.print( + string.format("with cursor at %s, motion %s, expected %s, got %s", cursorcol, key, col, actual_col) + ) + vim.print( + string.format( + "before: %s, input %s, after: %s", + vim.inspect(cur_before), + key, + vim.inspect(cur_after) + ) + ) + vim.print(vim.inspect(virtual_line_marks)) + os.exit(1) + end + end + end + if seed % 10000 == 0 then + vim.print(string.format("[SEED: %d]", seed)) + end + vim.api.nvim_buf_delete(temp_buf, { force = true }) +end + +local seed_start = tonumber(_G.arg[1]) +local num_sims = tonumber(_G.arg[2]) + +if (not num_sims or type(num_sims) ~= "number") or (not seed_start or type(seed_start) ~= "number") then + print(USAGE) +else + local seed = seed_start + local seed_end = seed_start + num_sims + while seed <= seed_end do + M.test(seed) + seed = seed + 1 + end +end + +return M diff --git a/tests/precognition/utils/dts.lua b/tests/precognition/utils/dts.lua new file mode 100644 index 0000000..cf8b7e5 --- /dev/null +++ b/tests/precognition/utils/dts.lua @@ -0,0 +1,52 @@ +local M = {} + +local ranges = { + { 32, 126 }, -- Basic Latin (ASCII) + --TODO: Add other character ranges but this opens a load of multibyte edge cases + -- { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A + -- { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew + -- { 8192, 8303 }, -- General Punctuation + -- { 9728, 9983 }, -- Miscellaneous Symbols + -- { 12352, 12447 }, -- Hiragana + -- { 19904, 19967 }, -- Mahjong Tiles + -- { 0x1F300, 0x1F6FF }, -- Emoji +} + +---@class dts.Random +---@field cursor_col number +---@field line string + +---Generate a random line with Unicode characters. +---@param seed number +---@return dts.Random +function M.generate_random_line(seed) + math.randomseed(seed) -- Set the seed for reproducibility + + -- Randomize the line length (e.g., between 20 and 100 characters) + local line_length = math.random(20, 100) + + -- Function to generate a random printable Unicode character + local function random_unicode_char() + -- Randomly pick a range + local range = ranges[math.random(1, #ranges)] + -- Generate a random codepoint within the selected range + local codepoint = math.random(range[1], range[2]) + return vim.fn.nr2char(codepoint) -- Convert codepoint to UTF-8 character + end + + -- Generate the random line with Unicode characters + local line = "" + for _ = 1, line_length do + line = line .. random_unicode_char() + end + + -- Choose a random cursor position within the line + local cursor_col = math.random(1, vim.fn.strcharlen(line)) -- Ensure valid cursor position + ---@type dts.Random + return { + cursor_col = cursor_col, + line = line, + } +end + +return M From ecaaa79f45a2cd75dd8faf29a504e05113abcfc7 Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 22:09:21 +0000 Subject: [PATCH 02/11] feat!(simulation): v2 rewrite --- lua/precognition/horizontal_motions.lua | 303 ---------------- lua/precognition/init.lua | 30 +- lua/precognition/sim.lua | 37 ++ tests/minimal.lua | 13 + tests/precognition/e2e_spec.lua | 10 +- .../precognition/horizontal_motions_spec.lua | 327 ------------------ tests/precognition/inlay_hints_spec.lua | 4 +- tests/precognition/virtline_spec.lua | 61 ++-- 8 files changed, 103 insertions(+), 682 deletions(-) delete mode 100644 lua/precognition/horizontal_motions.lua create mode 100644 lua/precognition/sim.lua delete mode 100644 tests/precognition/horizontal_motions_spec.lua diff --git a/lua/precognition/horizontal_motions.lua b/lua/precognition/horizontal_motions.lua deleted file mode 100644 index e4e858d..0000000 --- a/lua/precognition/horizontal_motions.lua +++ /dev/null @@ -1,303 +0,0 @@ -local M = {} - -local supportedBrackets = { - open = { "(", "[", "{" }, - middle = { nil, nil, nil }, - close = { ")", "]", "}" }, -} - ----@param str string ----@param _cursorcol integer ----@param _linelen integer ----@return Precognition.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 Precognition.PlaceLoc -function M.line_end(_str, _cursorcol, linelen) - return linelen or nil -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, big_word) - local utils = require("precognition.utils") - local cc = utils.char_classes - - local offset = cursorcol - local char = vim.fn.strcharpart(str, offset - 1, 1) - local c_class = utils.char_class(char, big_word) - - if c_class ~= cc.whitespace then - 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 - - while utils.char_class(char, big_word) == cc.whitespace and offset <= linelen do - offset = offset + 1 - char = vim.fn.strcharpart(str, offset - 1, 1) - end - if offset > linelen then - return 0 - end - - return offset -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, big_word) - if cursorcol >= linelen then - return 0 - end - local utils = require("precognition.utils") - local cc = utils.char_classes - - local offset = cursorcol - local char = vim.fn.strcharpart(str, offset - 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.punctuation and next_char_class ~= cc.punctuation) - or (next_char_class == cc.punctuation and c_class ~= cc.punctuation) - then - offset = offset + 1 - char = vim.fn.strcharpart(str, offset - 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, 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, big_word) - if next_word_start then - c_class = utils.char_class(vim.fn.strcharpart(str, next_word_start - 1, 1), big_word) - next_char_class = utils.char_class(vim.fn.strcharpart(str, (next_word_start - 1) + 1, 1), big_word) - if next_char_class == cc.whitespace then - --next word is single char - rev_offset = next_word_start - elseif c_class == cc.punctuation and next_char_class ~= cc.punctuation then - --next word starts with punctuation - rev_offset = next_word_start - else - rev_offset = M.end_of_word(str, next_word_start, linelen, big_word) - end - end - end - - if rev_offset and rev_offset <= 0 then - return 0 - end - - if rev_offset ~= nil then - --e should never be behind the cursor - if rev_offset < cursorcol then - return 0 - end - return rev_offset - end - return offset - 1 -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, big_word) - local utils = require("precognition.utils") - local cc = utils.char_classes - - local offset = cursorcol - 1 - local char = vim.fn.strcharpart(str, offset - 1, 1) - local c_class = utils.char_class(char, big_word) - - if c_class == cc.whitespace then - 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, big_word) - end - - 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 0 - local remaining = string.sub(str, offset) - if remaining:match("^%s*$") and #remaining > 0 then - return 0 - end - end - - if offset == nil or offset > linelen or offset < 0 then - return 0 - end - return offset + 1 -end - ----@param str string ----@param cursorcol integer ----@param linelen integer ----@return Precognition.PlaceLoc -function M.matching_bracket(str, cursorcol, linelen) - local under_cursor = vim.fn.strcharpart(str, cursorcol - 1, 1) - local offset = cursorcol - - if - not vim.tbl_contains(supportedBrackets.open, under_cursor) - and not vim.tbl_contains(supportedBrackets.close, under_cursor) - then - -- walk until we find a bracket - return 0 - end - local idxFound = false - local bracketIdx - if not idxFound then - for i, bracket in ipairs(supportedBrackets.open) do - if bracket == under_cursor then - bracketIdx = i - idxFound = true - break - end - end - end - - if not idxFound then - for i, bracket in ipairs(supportedBrackets.close) do - if bracket == under_cursor then - bracketIdx = i - idxFound = true - break - end - end - end - - if not idxFound then - return 0 - end - - local openBracket = supportedBrackets.open[bracketIdx] or "" - local closeBracket = supportedBrackets.close[bracketIdx] or "" - local middleBracket = supportedBrackets.middle[bracketIdx] or "" - - if under_cursor == openBracket then - local depth = 1 - offset = offset + 1 - while offset <= linelen do - local char = vim.fn.strcharpart(str, offset - 1, 1) - if char == openBracket then - depth = depth + 1 - end - if char == closeBracket or char == middleBracket then - depth = depth - 1 - if depth == 0 then - break - end - end - offset = offset + 1 - end - end - - if under_cursor == closeBracket then - local depth = 1 - offset = offset - 1 - while offset >= 0 do - local char = vim.fn.strcharpart(str, offset - 1, 1) - if char == closeBracket then - depth = depth + 1 - end - if char == openBracket or char == middleBracket then - depth = depth - 1 - if depth == 0 then - break - end - end - offset = offset - 1 - end - end - - if offset < 0 or offset > linelen then - return 0 - end - return offset -end - ----@param str string ----@param cursorcol integer ----@param linelen integer ----@return Precognition.PlaceLoc -function M.matching_comment(str, cursorcol, linelen) - local offset = cursorcol - local char = vim.fn.strcharpart(str, offset - 1, 1) - local next_char = vim.fn.strcharpart(str, (offset - 1) + 1, 1) - local prev_char = vim.fn.strcharpart(str, (offset - 1) - 1, 1) - - if (char == "/" and next_char == "*") or (prev_char == "/" and char == "*") then - offset = offset + 1 - while offset <= linelen do - char = vim.fn.strcharpart(str, offset - 1, 1) - next_char = vim.fn.strcharpart(str, offset, 1) - if char == "*" and next_char == "/" then - -- return the slash of the closing comment - return offset + 1 - end - offset = offset + 1 - end - end - - if (char == "*" and next_char == "/") or (prev_char == "*" and char == "/") then - offset = offset - 1 - while offset >= 0 do - char = vim.fn.strcharpart(str, offset - 1, 1) - next_char = vim.fn.strcharpart(str, offset, 1) - if char == "/" and next_char == "*" then - return offset - end - offset = offset - 1 - end - end - - return 0 -end - ----@param str string ----@param cursorcol integer ----@param _linelen integer ----@return function -function M.matching_pair(str, cursorcol, _linelen) - local char = vim.fn.strcharpart(str, cursorcol - 1, 1) - if char == "/" or char == "*" then - return M.matching_comment - end - - if vim.tbl_contains(supportedBrackets.open, char) or vim.tbl_contains(supportedBrackets.close, char) then - return M.matching_bracket - end - - return function() - return 0 - end -end - -return M diff --git a/lua/precognition/init.lua b/lua/precognition/init.lua index 7b74bf7..560da09 100644 --- a/lua/precognition/init.lua +++ b/lua/precognition/init.lua @@ -243,29 +243,18 @@ local function display_marks() local line_len = vim.fn.strcharlen(cur_line) ---@type Precognition.ExtraPadding[] local extra_padding = {} - -- local after_cursor = vim.fn.strcharpart(cur_line, cursorcol + 1) - -- local before_cursor = vim.fn.strcharpart(cur_line, 0, cursorcol - 1) - -- local before_cursor_rev = string.reverse(before_cursor) - -- local under_cursor = vim.fn.strcharpart(cur_line, cursorcol - 1, 1) - - local hm = require("precognition.horizontal_motions") -- 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 = { - Caret = hm.line_start_non_whitespace(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, - } + local virtual_line_marks = require("precognition.sim").check(cur_line, cursorcol) + ---return 0 for any hint that is not found in the simmed table + setmetatable(virtual_line_marks, { + __index = function() + return 0 + end, + }) if compat.inlay_hints_enabled({ bufnr = 0 }) then local inlays_hints = vim.lsp.inlay_hint.get({ @@ -490,6 +479,9 @@ local state = { ns = function() return ns end, + default_hint_config = function() + return defaultHintConfig + end, is_visible = function() return visible end, diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua new file mode 100644 index 0000000..cfb34e7 --- /dev/null +++ b/lua/precognition/sim.lua @@ -0,0 +1,37 @@ +local mt = require("mini.test") + +local M = {} + +local function check_pos(string, col, default_config) + local result = {} + local locations = vim.tbl_keys(default_config) + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, { " ", string, " " }) + vim.api.nvim_set_current_buf(buf) + for _, motion_name in ipairs(locations) do + local motion_key = default_config[motion_name].text + vim.fn.setcursorcharpos(2, col) + vim.api.nvim_feedkeys(motion_key, "x", true) + local cur_pos = vim.fn.getcursorcharpos(0) + if cur_pos[2] == 2 then + if motion_name == "MatchingPair" and cur_pos[3] ~= col then + result[motion_name] = cur_pos[3] + else + result[motion_name] = cur_pos[3] + end + end + end + + return result +end + +M.check = function(line, col) + local remote = mt.new_child_neovim() + remote.start() + + local remote_data = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) + remote.stop() + return remote_data +end + +return M diff --git a/tests/minimal.lua b/tests/minimal.lua index 2023951..89c1194 100644 --- a/tests/minimal.lua +++ b/tests/minimal.lua @@ -7,6 +7,19 @@ local function tempdir(plugin) return vim.loop.os_tmpdir() .. "/" .. plugin end +local minitest_dir = os.getenv("MINI_TEST_DIR") or tempdir("mini.test") +if vim.fn.isdirectory(minitest_dir) == 0 then + vim.fn.system({ + "git", + "clone", + "https://github.com/echasnovski/mini.test", + minitest_dir, + }) +end +vim.opt.rtp:append(".") +vim.opt.rtp:append(minitest_dir) +require("mini.test").setup() + local plenary_dir = os.getenv("PLENARY_DIR") or tempdir("plenary.nvim") if vim.fn.isdirectory(plenary_dir) == 0 then vim.fn.system({ diff --git a/tests/precognition/e2e_spec.lua b/tests/precognition/e2e_spec.lua index 6917d7d..9ffb35b 100644 --- a/tests/precognition/e2e_spec.lua +++ b/tests/precognition/e2e_spec.lua @@ -63,7 +63,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b% e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq({ link = "Comment" }, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) @@ -75,7 +75,7 @@ describe("e2e tests", function() }) eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b % e w $", extmarks[3].virt_lines[1][1][1]) vim.api.nvim_win_set_cursor(0, { 2, 1 }) precognition.on_cursor_moved() @@ -101,7 +101,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b e w", extmarks[3].virt_lines[1][1][1]) + eq("b% e w", extmarks[3].virt_lines[1][1][1]) vim.api.nvim_win_set_cursor(0, { 4, 1 }) precognition.on_cursor_moved() @@ -166,7 +166,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b% e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq({ link = "Function" }, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) end) @@ -219,7 +219,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b% e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq(customMark, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) end) diff --git a/tests/precognition/horizontal_motions_spec.lua b/tests/precognition/horizontal_motions_spec.lua deleted file mode 100644 index 7d0e0c9..0000000 --- a/tests/precognition/horizontal_motions_spec.lua +++ /dev/null @@ -1,327 +0,0 @@ -local hm = require("precognition.horizontal_motions") ----@diagnostic disable-next-line: undefined-field -local eq = assert.are.same - -describe("boundaries", function() - it("finds the next word boundary", function() - local str = "abc efg" - eq(5, hm.next_word_boundary(str, 1, #str, false)) - eq(5, hm.next_word_boundary(str, 2, #str, false)) - eq(5, hm.next_word_boundary(str, 3, #str, false)) - eq(5, hm.next_word_boundary(str, 4, #str, false)) - eq(0, hm.next_word_boundary(str, 5, #str, false)) - eq(0, hm.next_word_boundary(str, 6, #str, false)) - eq(0, hm.next_word_boundary(str, 7, #str, false)) - - str = "slighly more complex test" - eq(9, hm.next_word_boundary(str, 1, #str, false)) - eq(9, hm.next_word_boundary(str, 2, #str, false)) - eq(14, hm.next_word_boundary(str, 10, #str, false)) - eq(14, hm.next_word_boundary(str, 13, #str, false)) - eq(22, hm.next_word_boundary(str, 15, #str, false)) - eq(22, hm.next_word_boundary(str, 21, #str, false)) - - str = " myFunction(example, stuff)" - eq(5, hm.next_word_boundary(str, 1, #str, false)) - eq(5, hm.next_word_boundary(str, 2, #str, false)) - eq(5, hm.next_word_boundary(str, 3, #str, false)) - eq(15, hm.next_word_boundary(str, 5, #str, false)) - eq(16, hm.next_word_boundary(str, 15, #str, false)) - eq(23, hm.next_word_boundary(str, 16, #str, false)) - eq(25, hm.next_word_boundary(str, 23, #str, false)) - eq(25, hm.next_word_boundary(str, 24, #str, false)) - eq(30, hm.next_word_boundary(str, 25, #str, false)) - eq(0, hm.next_word_boundary(str, 30, #str, false)) - end) - - it("finds next big word boundary", function() - local str = "a big.word string" - eq(12, hm.next_word_boundary(str, 3, #str, true)) - eq(12, hm.next_word_boundary(str, 4, #str, true)) - end) - - it("can walk string with w", function() - local test_string = "abcdefg hijklmn opqrstu vwxyz" - local pos = hm.next_word_boundary(test_string, 1, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("h", test_string:sub(pos, pos)) - if pos == 0 then - error("pos is 0") - end - pos = hm.next_word_boundary(test_string, pos, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("o", test_string:sub(pos, pos)) - pos = hm.next_word_boundary(test_string, pos, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("v", test_string:sub(pos, pos)) - pos = hm.next_word_boundary(test_string, pos, #test_string, false) - eq(0, pos) - end) - - describe("previous word boundary", function() - it("finds the previous word boundary", function() - local str = "abc efg" - eq(0, hm.prev_word_boundary(str, 1, #str, false)) - eq(1, hm.prev_word_boundary(str, 2, #str, false)) - eq(1, hm.prev_word_boundary(str, 3, #str, false)) - eq(1, hm.prev_word_boundary(str, 4, #str, false)) - eq(1, hm.prev_word_boundary(str, 5, #str, false)) - eq(5, hm.prev_word_boundary(str, 6, #str, false)) - eq(5, hm.prev_word_boundary(str, 7, #str, false)) - - str = "slighly more complex test" - eq(9, hm.prev_word_boundary(str, 10, #str, false)) - eq(9, hm.prev_word_boundary(str, 11, #str, false)) - eq(14, hm.prev_word_boundary(str, 15, #str, false)) - eq(14, hm.prev_word_boundary(str, 16, #str, false)) - eq(22, hm.prev_word_boundary(str, 23, #str, false)) - eq(22, hm.prev_word_boundary(str, 24, #str, false)) - eq(22, hm.prev_word_boundary(str, 25, #str, false)) - eq(0, hm.prev_word_boundary(str, 1, #str, false)) - - str = " myFunction(example, stuff)" - eq(0, hm.prev_word_boundary(str, 1, #str, false)) - eq(0, hm.prev_word_boundary(str, 2, #str, false)) - eq(0, hm.prev_word_boundary(str, 3, #str, false)) - eq(0, hm.prev_word_boundary(str, 4, #str, false)) - eq(0, hm.prev_word_boundary(str, 5, #str, false)) - eq(5, hm.prev_word_boundary(str, 6, #str, false)) - eq(5, hm.prev_word_boundary(str, 15, #str, false)) - eq(15, hm.prev_word_boundary(str, 16, #str, false)) - eq(16, hm.prev_word_boundary(str, 17, #str, false)) - eq(16, hm.prev_word_boundary(str, 18, #str, false)) - eq(16, hm.prev_word_boundary(str, 19, #str, false)) - eq(23, hm.prev_word_boundary(str, 25, #str, false)) - eq(25, hm.prev_word_boundary(str, 26, #str, false)) - eq(25, hm.prev_word_boundary(str, 27, #str, false)) - eq(25, hm.prev_word_boundary(str, 28, #str, false)) - eq(25, hm.prev_word_boundary(str, 29, #str, false)) - eq(25, hm.prev_word_boundary(str, 30, #str, false)) - end) - - it("finds previous big word boundary", function() - local str = "a big.word string" - eq(3, hm.prev_word_boundary(str, 10, #str, true)) - eq(3, hm.prev_word_boundary(str, 10, #str, true)) - - str = "big.word" - eq(1, hm.prev_word_boundary(str, 5, #str, true)) - end) - - it("can walk string with b", function() - local test_string = "abcdefg hijklmn opqrstu vwxyz" - local pos = hm.prev_word_boundary(test_string, 29, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("v", test_string:sub(pos, pos)) - pos = hm.prev_word_boundary(test_string, pos, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("o", test_string:sub(pos, pos)) - pos = hm.prev_word_boundary(test_string, pos, #test_string, false) - if pos == 0 then - error("pos is 0") - end - eq("h", test_string:sub(pos, pos)) - pos = hm.prev_word_boundary(test_string, pos, #test_string, false) - eq(1, pos) - end) - end) - - describe("end of current word", function() - it("finds the end of words", function() - local str = "abc efg" - eq(3, hm.end_of_word(str, 1, #str, false)) - eq(3, hm.end_of_word(str, 2, #str, false)) - eq(7, hm.end_of_word(str, 3, #str, false)) - - str = "slighly more complex test" - eq(7, hm.end_of_word(str, 1, #str, false)) - eq(7, hm.end_of_word(str, 2, #str, false)) - eq(12, hm.end_of_word(str, 10, #str, false)) - eq(20, hm.end_of_word(str, 13, #str, false)) - eq(20, hm.end_of_word(str, 15, #str, false)) - eq(25, hm.end_of_word(str, 21, #str, false)) - - str = " myFunction(example, stuff)" - eq(14, hm.end_of_word(str, 1, #str, false)) - eq(14, hm.end_of_word(str, 2, #str, false)) - eq(14, hm.end_of_word(str, 3, #str, false)) - eq(14, hm.end_of_word(str, 5, #str, false)) - eq(15, hm.end_of_word(str, 14, #str, false)) - eq(22, hm.end_of_word(str, 15, #str, false)) - eq(22, hm.end_of_word(str, 16, #str, false)) - eq(29, hm.end_of_word(str, 23, #str, false)) - eq(29, hm.end_of_word(str, 24, #str, false)) - eq(29, hm.end_of_word(str, 25, #str, false)) - eq(30, hm.end_of_word(str, 29, #str, false)) - eq(0, hm.end_of_word(str, 30, #str, false)) - end) - - it("finds the end of the current big word", function() - local str = "a big.word string" - eq(10, hm.end_of_word(str, 3, #str, true)) - end) - end) -end) - -describe("matching_pair returns the correction function", function() - it("returns the correct function for the given character", function() - local test_string = "()[]{}/*" - eq(hm.matching_pair(test_string, 1, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 2, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 3, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 4, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 5, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 6, #test_string), hm.matching_bracket) - eq(hm.matching_pair(test_string, 7, #test_string), hm.matching_comment) - eq(hm.matching_pair(test_string, 8, #test_string), hm.matching_comment) - end) - - it("returns a function that returns 0 for other characters", function() - local test_string = "abcdefghijklmnopqrstuvwxyz!@#$%^&*_+-=,.<>?|\\~`" - for i = 1, #test_string do - local func = hm.matching_pair(test_string, i, #test_string) - eq(0, func(test_string, i, #test_string)) - end - end) -end) - -describe("matching brackets", function() - it("if cursor is over a bracket it can find the pair", function() - local str = "abc (efg)" - eq(9, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 6, #str)) - eq(0, hm.matching_bracket(str, 7, #str)) - eq(0, hm.matching_bracket(str, 8, #str)) - eq(5, hm.matching_bracket(str, 9, #str)) - end) - - it("if cursor is over a square bracket it can find the pair", function() - local str = "abc [efg]" - eq(9, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 6, #str)) - eq(0, hm.matching_bracket(str, 7, #str)) - eq(0, hm.matching_bracket(str, 8, #str)) - eq(5, hm.matching_bracket(str, 9, #str)) - end) - - it("if cursor is over a curly bracket it can find the pair", function() - local str = "abc {efg}" - eq(9, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 6, #str)) - eq(0, hm.matching_bracket(str, 7, #str)) - eq(0, hm.matching_bracket(str, 8, #str)) - eq(5, hm.matching_bracket(str, 9, #str)) - end) - - it("nested brackets find the correct pair", function() - local str = "abc (efg [hij] klm)" - eq(19, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 6, #str)) - eq(14, hm.matching_bracket(str, 10, #str)) - eq(10, hm.matching_bracket(str, 14, #str)) - eq(0, hm.matching_bracket(str, 15, #str)) - eq(5, hm.matching_bracket(str, 19, #str)) - end) - - it("nested brackets of the same type find the correct pair", function() - local str = "abc (efg (hij) klm)" - eq(19, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 6, #str)) - eq(14, hm.matching_bracket(str, 10, #str)) - eq(10, hm.matching_bracket(str, 14, #str)) - eq(0, hm.matching_bracket(str, 15, #str)) - eq(5, hm.matching_bracket(str, 19, #str)) - end) - - it("if cursor is over an unclosed bracket it returns 0", function() - local str = "abc (efg" - eq(0, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 5, #str)) - eq(0, hm.matching_bracket(str, 5, #str)) - end) -end) - -describe("matching comments", function() - it("if cursor is over a comment it can find the pair", function() - local str = "abc /*efg*/" - eq(11, hm.matching_comment(str, 5, #str)) - eq(11, hm.matching_comment(str, 6, #str)) - eq(0, hm.matching_comment(str, 7, #str)) - eq(5, hm.matching_comment(str, 10, #str)) - eq(5, hm.matching_comment(str, 11, #str)) - end) - - it("if cursor is over an unclosed comment it returns 0", function() - local str = "abc /*efg" - eq(0, hm.matching_comment(str, 5, #str)) - eq(0, hm.matching_comment(str, 6, #str)) - end) -end) - -describe("edge case", function() - it("can handle empty strings", function() - eq(0, hm.next_word_boundary("", 1, 0, false)) - eq(0, hm.prev_word_boundary("", 1, 0, false)) - eq(0, hm.end_of_word("", 1, 0, false)) - end) - - it("can handle strings with only whitespace", function() - eq(0, hm.next_word_boundary(" ", 1, 1, false)) - eq(0, hm.prev_word_boundary(" ", 1, 1, false)) - eq(0, hm.end_of_word(" ", 1, 1, false)) - end) - - it("can handle strings with special characters in the middle", function() - local str = "vim.keymap.set('n', 't;', ':Test')" - eq(5, hm.next_word_boundary(str, 4, #str, false)) - eq(1, hm.prev_word_boundary(str, 4, #str, false)) - eq(10, hm.end_of_word(str, 4, #str, false)) - end) - - it("can handle strings with multiple consecutive special characters", function() - local str = "this || that" - eq(9, hm.next_word_boundary(str, 6, #str, false)) - eq(1, hm.prev_word_boundary(str, 6, #str, false)) - eq(7, hm.end_of_word(str, 6, #str, false)) - end) - - it("strings with spaces at the end", function() - local str = "there is a space " - eq(0, hm.end_of_word(str, 16, #str, false)) - end) - - it("single character next word ends", function() - local str = "show_something = true," - eq(14, hm.end_of_word(str, 1, #str, false)) - eq(16, hm.end_of_word(str, 14, #str, false)) - eq(16, hm.end_of_word(str, 15, #str, false)) - eq(22, hm.end_of_word(str, 21, #str, false)) - end) - - it("multibyte characters", function() - local str = "# 💭👀precognition.nvim" - local len = vim.fn.strcharlen(str) - eq(3, hm.next_word_boundary(str, 1, len, false)) - eq(17, hm.prev_word_boundary(str, 18, len, false)) - eq(3, hm.prev_word_boundary(str, 18, len, true)) - eq(3, hm.prev_word_boundary(str, 5, len, false)) - end) - - it("quoted strings", function() - local str = 'this = "that"' - eq(8, hm.end_of_word(str, 6, #str, false)) - - str = 'b = "^", c = 2 },' - eq(8, hm.end_of_word(str, 3, #str, false)) - end) -end) diff --git a/tests/precognition/inlay_hints_spec.lua b/tests/precognition/inlay_hints_spec.lua index cecf716..3af28be 100644 --- a/tests/precognition/inlay_hints_spec.lua +++ b/tests/precognition/inlay_hints_spec.lua @@ -134,7 +134,7 @@ describe("lsp based tests", function() details = true, }) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b% e w $", extmarks[3].virt_lines[1][1][1]) vim.lsp.inlay_hint.enable(true, { bufnr = buf }) -- NOTE:The test LSP replies with an inlay hint, that suggest "foo" as line 1, position 4 @@ -146,7 +146,7 @@ describe("lsp based tests", function() details = true, }) - eq("b e w $", extmarks[3].virt_lines[1][1][1]) + eq("b% e w $", extmarks[3].virt_lines[1][1][1]) end) after_each(function() diff --git a/tests/precognition/virtline_spec.lua b/tests/precognition/virtline_spec.lua index 26efc7d..75e5253 100644 --- a/tests/precognition/virtline_spec.lua +++ b/tests/precognition/virtline_spec.lua @@ -1,5 +1,4 @@ local precognition = require("precognition") -local hm = require("precognition.horizontal_motions") local utils = require("precognition.utils") ---@diagnostic disable-next-line: undefined-field local eq = assert.are.same @@ -79,12 +78,14 @@ describe("Build Virtual Line", function() local cur_line = line:gsub("\t", string.rep(" ", tab_width)) local line_len = vim.fn.strcharlen(cur_line) + local sim = require("precognition.sim").check(cur_line, cursorcol) + local virt_line = precognition.build_virt_line({ - 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), - Caret = hm.line_start_non_whitespace(cur_line, cursorcol, line_len), - Dollar = hm.line_end(cur_line, cursorcol, line_len), + w = sim["w"], + e = sim["e"], + b = sim["b"], + Caret = sim["Caret"], + Dollar = sim["Dollar"], }, line_len, {}) eq("b e w $", virt_line[1][1]) @@ -98,12 +99,14 @@ describe("Build Virtual Line", function() local cur_line = line:gsub("\t", string.rep(" ", tab_width)) local line_len = vim.fn.strcharlen(cur_line) + local sim = require("precognition.sim").check(cur_line, cursorcol) + local virt_line = precognition.build_virt_line({ - 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), - Caret = hm.line_start_non_whitespace(cur_line, cursorcol, line_len), - Dollar = hm.line_end(cur_line, cursorcol, line_len), + w = sim["w"], + e = sim["e"], + b = sim["b"], + Caret = sim["Caret"], + Dollar = sim["Dollar"], }, line_len, {}) eq(" ^ e w $", virt_line[1][1]) @@ -118,12 +121,14 @@ describe("Build Virtual Line", function() local line_len = vim.fn.strcharlen(cur_line) local extra_padding = { { start = 4, length = 4 } } + local sim = require("precognition.sim").check(cur_line, cursorcol) + local virt_line = precognition.build_virt_line({ - 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), - Caret = hm.line_start_non_whitespace(cur_line, cursorcol, line_len), - Dollar = hm.line_end(cur_line, cursorcol, line_len), + w = sim["w"], + e = sim["e"], + b = sim["b"], + Caret = sim["Caret"], + Dollar = sim["Dollar"], }, line_len, extra_padding) local total_added = 0 @@ -143,12 +148,14 @@ describe("Build Virtual Line", function() local line_len = vim.fn.strcharlen(cur_line) local extra_padding = { { start = 4, length = 4 }, { start = 10, length = 5 } } + local sim = require("precognition.sim").check(cur_line, cursorcol) + local virt_line = precognition.build_virt_line({ - 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), - Caret = hm.line_start_non_whitespace(cur_line, cursorcol, line_len), - Dollar = hm.line_end(cur_line, cursorcol, line_len), + w = sim["w"], + e = sim["e"], + b = sim["b"], + Caret = sim["Caret"], + Dollar = sim["Dollar"], }, line_len, extra_padding) local total_added = 0 @@ -170,12 +177,14 @@ describe("Build Virtual Line", function() utils.add_multibyte_padding(cur_line, extra_padding, line_len) + local sim = require("precognition.sim").check(cur_line, cursorcol) + local virt_line = precognition.build_virt_line({ - 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), - Caret = hm.line_start_non_whitespace(cur_line, cursorcol, line_len), - Dollar = hm.line_end(cur_line, cursorcol, line_len), + w = sim["w"], + e = sim["e"], + b = sim["b"], + Caret = sim["Caret"], + Dollar = sim["Dollar"], }, line_len, extra_padding) eq("^ b e", virt_line[1][1]) From e8f2ee3adc53a784d1359e88e7cc93de99379991 Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 22:23:06 +0000 Subject: [PATCH 03/11] fix(dts): adjust dts to new api --- tests/precognition/dts.lua | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/tests/precognition/dts.lua b/tests/precognition/dts.lua index 49168d9..d509652 100644 --- a/tests/precognition/dts.lua +++ b/tests/precognition/dts.lua @@ -1,5 +1,4 @@ local precognition = require("precognition") -local hm = require("precognition.horizontal_motions") local dts = require("tests.precognition.utils.dts") local USAGE = [[ @@ -15,27 +14,17 @@ local M = {} function M.test(seed) local data = dts.generate_random_line(seed) - --TODO: Currently bracket matching only works with M cpoptions - --see `:h %` - vim.o.cpoptions = vim.o.cpoptions .. "M" - local cur_line = data.line local cursorcol = data.cursor_col - local line_len = vim.fn.strcharlen(cur_line) - 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, 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), - -- TODO: fix some edge cases around pairs and we can enable this - -- 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, - } + ---@type Precognition.VirtLine + local virtual_line_marks = require("precognition.sim").check(cur_line, cursorcol) + ---return 0 for any hint that is not found in the simmed table + setmetatable(virtual_line_marks, { + __index = function() + return 0 + end, + }) local temp_buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(temp_buf, 0, -1, false, { cur_line }) From 0b3511d51624867d5cf1770a51560b3434c93cb3 Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 23:04:31 +0000 Subject: [PATCH 04/11] wip: fixups --- lua/precognition/sim.lua | 28 ++++++++++++++++++++++------ tests/precognition/dts.lua | 4 +++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index cfb34e7..396d2f4 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -2,6 +2,26 @@ local mt = require("mini.test") local M = {} +local remote_instance = nil + +-- Metatable for remote instance +local remote_mt = { + __gc = function(self) + if self.instance then + self.instance.stop() + end + end, +} + +local function get_remote() + if not remote_instance then + local remote = mt.new_child_neovim() + remote.start() + remote_instance = setmetatable({ instance = remote }, remote_mt) + end + return remote_instance.instance +end + local function check_pos(string, col, default_config) local result = {} local locations = vim.tbl_keys(default_config) @@ -26,12 +46,8 @@ local function check_pos(string, col, default_config) end M.check = function(line, col) - local remote = mt.new_child_neovim() - remote.start() - - local remote_data = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) - remote.stop() - return remote_data + local remote = get_remote() + return remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) end return M diff --git a/tests/precognition/dts.lua b/tests/precognition/dts.lua index d509652..6da3b1e 100644 --- a/tests/precognition/dts.lua +++ b/tests/precognition/dts.lua @@ -26,6 +26,8 @@ function M.test(seed) end, }) + virtual_line_marks.MatchingPair = nil + local temp_buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(temp_buf, 0, -1, false, { cur_line }) @@ -34,7 +36,7 @@ function M.test(seed) vim.api.nvim_set_current_buf(temp_buf) vim.fn.setcursorcharpos(1, cursorcol) local cur_before = vim.fn.getcursorcharpos(0) - vim.api.nvim_feedkeys(key, "ntx", true) + vim.api.nvim_feedkeys(key, "x", true) local cur_after = vim.fn.getcursorcharpos(0) local actual_col = cur_after[3] if col ~= 0 then From aa38e49dcd562bd91f844e8f1735d7b2535a999d Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 23:23:22 +0000 Subject: [PATCH 05/11] fix: improve matching pair detection accuracy --- lua/precognition/sim.lua | 10 +++++++--- tests/precognition/e2e_spec.lua | 10 +++++----- tests/precognition/inlay_hints_spec.lua | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index 396d2f4..55958a4 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -31,11 +31,14 @@ local function check_pos(string, col, default_config) for _, motion_name in ipairs(locations) do local motion_key = default_config[motion_name].text vim.fn.setcursorcharpos(2, col) + local start_col = vim.fn.getcursorcharpos(0)[3] vim.api.nvim_feedkeys(motion_key, "x", true) local cur_pos = vim.fn.getcursorcharpos(0) if cur_pos[2] == 2 then - if motion_name == "MatchingPair" and cur_pos[3] ~= col then - result[motion_name] = cur_pos[3] + if motion_name == "MatchingPair" then + if cur_pos[3] ~= start_col then + result[motion_name] = cur_pos[3] + end else result[motion_name] = cur_pos[3] end @@ -47,7 +50,8 @@ end M.check = function(line, col) local remote = get_remote() - return remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) + local result = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) + return result end return M diff --git a/tests/precognition/e2e_spec.lua b/tests/precognition/e2e_spec.lua index 9ffb35b..6917d7d 100644 --- a/tests/precognition/e2e_spec.lua +++ b/tests/precognition/e2e_spec.lua @@ -63,7 +63,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b% e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq({ link = "Comment" }, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) @@ -75,7 +75,7 @@ describe("e2e tests", function() }) eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b % e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) vim.api.nvim_win_set_cursor(0, { 2, 1 }) precognition.on_cursor_moved() @@ -101,7 +101,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b% e w", extmarks[3].virt_lines[1][1][1]) + eq("b e w", extmarks[3].virt_lines[1][1][1]) vim.api.nvim_win_set_cursor(0, { 4, 1 }) precognition.on_cursor_moved() @@ -166,7 +166,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b% e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq({ link = "Function" }, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) end) @@ -219,7 +219,7 @@ describe("e2e tests", function() end eq(vim.api.nvim_win_get_cursor(0)[1] - 1, extmarks[1]) - eq("b% e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) eq("PrecognitionHighlight", extmarks[3].virt_lines[1][1][2]) eq(customMark, vim.api.nvim_get_hl(0, { name = extmarks[3].virt_lines[1][1][2] })) end) diff --git a/tests/precognition/inlay_hints_spec.lua b/tests/precognition/inlay_hints_spec.lua index 3af28be..cecf716 100644 --- a/tests/precognition/inlay_hints_spec.lua +++ b/tests/precognition/inlay_hints_spec.lua @@ -134,7 +134,7 @@ describe("lsp based tests", function() details = true, }) - eq("b% e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) vim.lsp.inlay_hint.enable(true, { bufnr = buf }) -- NOTE:The test LSP replies with an inlay hint, that suggest "foo" as line 1, position 4 @@ -146,7 +146,7 @@ describe("lsp based tests", function() details = true, }) - eq("b% e w $", extmarks[3].virt_lines[1][1][1]) + eq("b e w $", extmarks[3].virt_lines[1][1][1]) end) after_each(function() From d513d694f971e0c87c6f384bf5f3a9d8d426fcbb Mon Sep 17 00:00:00 2001 From: tris203 Date: Thu, 19 Dec 2024 23:55:04 +0000 Subject: [PATCH 06/11] fixup: sim adjustments --- lua/precognition/sim.lua | 7 +++++++ tests/precognition/dts.lua | 14 +++++++++++--- tests/precognition/utils/dts.lua | 15 +++++++-------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index 55958a4..8c970f7 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -48,6 +48,13 @@ local function check_pos(string, col, default_config) return result end +M.stop = function() + if remote_instance and remote_instance.instance then + remote_instance.instance.stop() + remote_instance.instance = nil + end +end + M.check = function(line, col) local remote = get_remote() local result = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) diff --git a/tests/precognition/dts.lua b/tests/precognition/dts.lua index 6da3b1e..2932b84 100644 --- a/tests/precognition/dts.lua +++ b/tests/precognition/dts.lua @@ -54,13 +54,11 @@ function M.test(seed) ) ) vim.print(vim.inspect(virtual_line_marks)) + require("precognition.sim").stop() os.exit(1) end end end - if seed % 10000 == 0 then - vim.print(string.format("[SEED: %d]", seed)) - end vim.api.nvim_buf_delete(temp_buf, { force = true }) end @@ -72,8 +70,18 @@ if (not num_sims or type(num_sims) ~= "number") or (not seed_start or type(seed_ else local seed = seed_start local seed_end = seed_start + num_sims + local start_time = vim.uv.hrtime() while seed <= seed_end do M.test(seed) + if seed % 10000 == 0 then + vim.print(string.format("[SEED: %d]", seed)) + local cur_time = vim.uv.hrtime() + local elapsed_seconds = (cur_time - start_time) / 1e9 + local completed = seed - seed_start + local rate = completed / elapsed_seconds + local remaining = num_sims - completed + vim.print(string.format("%d sims remaing (est %d seconds)", remaining, remaining / rate)) + end seed = seed + 1 end end diff --git a/tests/precognition/utils/dts.lua b/tests/precognition/utils/dts.lua index cf8b7e5..35e99c4 100644 --- a/tests/precognition/utils/dts.lua +++ b/tests/precognition/utils/dts.lua @@ -2,14 +2,13 @@ local M = {} local ranges = { { 32, 126 }, -- Basic Latin (ASCII) - --TODO: Add other character ranges but this opens a load of multibyte edge cases - -- { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A - -- { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew - -- { 8192, 8303 }, -- General Punctuation - -- { 9728, 9983 }, -- Miscellaneous Symbols - -- { 12352, 12447 }, -- Hiragana - -- { 19904, 19967 }, -- Mahjong Tiles - -- { 0x1F300, 0x1F6FF }, -- Emoji + { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A + { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew + { 8192, 8303 }, -- General Punctuation + { 9728, 9983 }, -- Miscellaneous Symbols + { 12352, 12447 }, -- Hiragana + { 19904, 19967 }, -- Mahjong Tiles + { 0x1F300, 0x1F6FF }, -- Emoji } ---@class dts.Random From fe9032c9481363322f8bf6fd661a7c86a5dc935f Mon Sep 17 00:00:00 2001 From: tris203 Date: Fri, 20 Dec 2024 07:25:43 +0000 Subject: [PATCH 07/11] perf: cleanup buffer after position check Prevents buffer leak by properly deleting the temporary buffer after position check is complete in the simulator. --- lua/precognition/sim.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index 8c970f7..97afbe1 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -45,6 +45,8 @@ local function check_pos(string, col, default_config) end end + vim.api.nvim_buf_delete(buf, { force = true }) + return result end From 6d0b96e7e98dbcdd7e6ef189fea0105137f4bcea Mon Sep 17 00:00:00 2001 From: tris203 Date: Fri, 20 Dec 2024 08:00:52 +0000 Subject: [PATCH 08/11] test(horizontal_motions): restore hm tests --- .../precognition/horizontal_motions_spec.lua | 370 ++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 tests/precognition/horizontal_motions_spec.lua diff --git a/tests/precognition/horizontal_motions_spec.lua b/tests/precognition/horizontal_motions_spec.lua new file mode 100644 index 0000000..a293376 --- /dev/null +++ b/tests/precognition/horizontal_motions_spec.lua @@ -0,0 +1,370 @@ +local sim = require("precognition.sim") +---@diagnostic disable-next-line: undefined-field +local eq = assert.are.same + +local hm = {} + +hm.next_word_boundary = function(str, col, _, big) + local res = sim.check(str, col) + if big then + return res["W"] or 0 + else + return res["w"] or 0 + end +end + +hm.prev_word_boundary = function(str, col, _, big) + local res = sim.check(str, col) + if big then + return res["B"] or 0 + else + return res["b"] or 0 + end +end + +hm.end_of_word = function(str, col, _, big) + local res = sim.check(str, col) + if big then + return res["E"] or 0 + else + return res["e"] or 0 + end +end + +hm.matching_pair = function(_, _, _) + return hm.matching_bracket +end + +hm.matching_bracket = function(str, col, _) + local res = sim.check(str, col) + return res["MatchingPair"] or 0 +end + +hm.matching_comment = function(str, col, _) + local res = sim.check(str, col) + return res["MatchingPair"] or 0 +end + +describe("boundaries", function() + it("finds the next word boundary", function() + local str = "abc efg" + eq(5, hm.next_word_boundary(str, 1, #str, false)) + eq(5, hm.next_word_boundary(str, 2, #str, false)) + eq(5, hm.next_word_boundary(str, 3, #str, false)) + eq(5, hm.next_word_boundary(str, 4, #str, false)) + eq(0, hm.next_word_boundary(str, 5, #str, false)) + eq(0, hm.next_word_boundary(str, 6, #str, false)) + eq(0, hm.next_word_boundary(str, 7, #str, false)) + + str = "slighly more complex test" + eq(9, hm.next_word_boundary(str, 1, #str, false)) + eq(9, hm.next_word_boundary(str, 2, #str, false)) + eq(14, hm.next_word_boundary(str, 10, #str, false)) + eq(14, hm.next_word_boundary(str, 13, #str, false)) + eq(22, hm.next_word_boundary(str, 15, #str, false)) + eq(22, hm.next_word_boundary(str, 21, #str, false)) + + str = " myFunction(example, stuff)" + eq(5, hm.next_word_boundary(str, 1, #str, false)) + eq(5, hm.next_word_boundary(str, 2, #str, false)) + eq(5, hm.next_word_boundary(str, 3, #str, false)) + eq(15, hm.next_word_boundary(str, 5, #str, false)) + eq(16, hm.next_word_boundary(str, 15, #str, false)) + eq(23, hm.next_word_boundary(str, 16, #str, false)) + eq(25, hm.next_word_boundary(str, 23, #str, false)) + eq(25, hm.next_word_boundary(str, 24, #str, false)) + eq(30, hm.next_word_boundary(str, 25, #str, false)) + eq(0, hm.next_word_boundary(str, 30, #str, false)) + end) + + it("finds next big word boundary", function() + local str = "a big.word string" + eq(12, hm.next_word_boundary(str, 3, #str, true)) + eq(12, hm.next_word_boundary(str, 4, #str, true)) + end) + + it("can walk string with w", function() + local test_string = "abcdefg hijklmn opqrstu vwxyz" + local pos = hm.next_word_boundary(test_string, 1, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("h", test_string:sub(pos, pos)) + if pos == 0 then + error("pos is 0") + end + pos = hm.next_word_boundary(test_string, pos, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("o", test_string:sub(pos, pos)) + pos = hm.next_word_boundary(test_string, pos, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("v", test_string:sub(pos, pos)) + pos = hm.next_word_boundary(test_string, pos, #test_string, false) + eq(0, pos) + end) + + describe("previous word boundary", function() + it("finds the previous word boundary", function() + local str = "abc efg" + eq(0, hm.prev_word_boundary(str, 1, #str, false)) + eq(1, hm.prev_word_boundary(str, 2, #str, false)) + eq(1, hm.prev_word_boundary(str, 3, #str, false)) + eq(1, hm.prev_word_boundary(str, 4, #str, false)) + eq(1, hm.prev_word_boundary(str, 5, #str, false)) + eq(5, hm.prev_word_boundary(str, 6, #str, false)) + eq(5, hm.prev_word_boundary(str, 7, #str, false)) + + str = "slighly more complex test" + eq(9, hm.prev_word_boundary(str, 10, #str, false)) + eq(9, hm.prev_word_boundary(str, 11, #str, false)) + eq(14, hm.prev_word_boundary(str, 15, #str, false)) + eq(14, hm.prev_word_boundary(str, 16, #str, false)) + eq(22, hm.prev_word_boundary(str, 23, #str, false)) + eq(22, hm.prev_word_boundary(str, 24, #str, false)) + eq(22, hm.prev_word_boundary(str, 25, #str, false)) + eq(0, hm.prev_word_boundary(str, 1, #str, false)) + + str = " myFunction(example, stuff)" + eq(0, hm.prev_word_boundary(str, 1, #str, false)) + eq(0, hm.prev_word_boundary(str, 2, #str, false)) + eq(0, hm.prev_word_boundary(str, 3, #str, false)) + eq(0, hm.prev_word_boundary(str, 4, #str, false)) + eq(0, hm.prev_word_boundary(str, 5, #str, false)) + eq(5, hm.prev_word_boundary(str, 6, #str, false)) + eq(5, hm.prev_word_boundary(str, 15, #str, false)) + eq(15, hm.prev_word_boundary(str, 16, #str, false)) + eq(16, hm.prev_word_boundary(str, 17, #str, false)) + eq(16, hm.prev_word_boundary(str, 18, #str, false)) + eq(16, hm.prev_word_boundary(str, 19, #str, false)) + eq(23, hm.prev_word_boundary(str, 25, #str, false)) + eq(25, hm.prev_word_boundary(str, 26, #str, false)) + eq(25, hm.prev_word_boundary(str, 27, #str, false)) + eq(25, hm.prev_word_boundary(str, 28, #str, false)) + eq(25, hm.prev_word_boundary(str, 29, #str, false)) + eq(25, hm.prev_word_boundary(str, 30, #str, false)) + end) + + it("finds previous big word boundary", function() + local str = "a big.word string" + eq(3, hm.prev_word_boundary(str, 10, #str, true)) + eq(3, hm.prev_word_boundary(str, 10, #str, true)) + + str = "big.word" + eq(1, hm.prev_word_boundary(str, 5, #str, true)) + end) + + it("can walk string with b", function() + local test_string = "abcdefg hijklmn opqrstu vwxyz" + local pos = hm.prev_word_boundary(test_string, 29, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("v", test_string:sub(pos, pos)) + pos = hm.prev_word_boundary(test_string, pos, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("o", test_string:sub(pos, pos)) + pos = hm.prev_word_boundary(test_string, pos, #test_string, false) + if pos == 0 then + error("pos is 0") + end + eq("h", test_string:sub(pos, pos)) + pos = hm.prev_word_boundary(test_string, pos, #test_string, false) + eq(1, pos) + end) + end) + + describe("end of current word", function() + it("finds the end of words", function() + local str = "abc efg" + eq(3, hm.end_of_word(str, 1, #str, false)) + eq(3, hm.end_of_word(str, 2, #str, false)) + eq(7, hm.end_of_word(str, 3, #str, false)) + + str = "slighly more complex test" + eq(7, hm.end_of_word(str, 1, #str, false)) + eq(7, hm.end_of_word(str, 2, #str, false)) + eq(12, hm.end_of_word(str, 10, #str, false)) + eq(20, hm.end_of_word(str, 13, #str, false)) + eq(20, hm.end_of_word(str, 15, #str, false)) + eq(25, hm.end_of_word(str, 21, #str, false)) + + str = " myFunction(example, stuff)" + eq(14, hm.end_of_word(str, 1, #str, false)) + eq(14, hm.end_of_word(str, 2, #str, false)) + eq(14, hm.end_of_word(str, 3, #str, false)) + eq(14, hm.end_of_word(str, 5, #str, false)) + eq(15, hm.end_of_word(str, 14, #str, false)) + eq(22, hm.end_of_word(str, 15, #str, false)) + eq(22, hm.end_of_word(str, 16, #str, false)) + eq(29, hm.end_of_word(str, 23, #str, false)) + eq(29, hm.end_of_word(str, 24, #str, false)) + eq(29, hm.end_of_word(str, 25, #str, false)) + eq(30, hm.end_of_word(str, 29, #str, false)) + eq(0, hm.end_of_word(str, 30, #str, false)) + end) + + it("finds the end of the current big word", function() + local str = "a big.word string" + eq(10, hm.end_of_word(str, 3, #str, true)) + end) + end) +end) + +describe("matching_pair returns the correction function", function() + -- it("returns the correct function for the given character", function() + -- local test_string = "()[]{}/*" + -- eq(hm.matching_pair(test_string, 1, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 2, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 3, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 4, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 5, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 6, #test_string), hm.matching_bracket) + -- eq(hm.matching_pair(test_string, 7, #test_string), hm.matching_comment) + -- eq(hm.matching_pair(test_string, 8, #test_string), hm.matching_comment) + -- end) + + it("returns a function that returns 0 for other characters", function() + local test_string = "abcdefghijklmnopqrstuvwxyz!@#$%^&*_+-=,.<>?|\\~`" + for i = 1, #test_string do + local func = hm.matching_pair(test_string, i, #test_string) + eq(0, func(test_string, i, #test_string)) + end + end) +end) + +describe("matching brackets", function() + it("if cursor is over a bracket it can find the pair", function() + local str = "abc (efg)" + eq(9, hm.matching_bracket(str, 5, #str)) + eq(5, hm.matching_bracket(str, 6, #str)) + eq(5, hm.matching_bracket(str, 7, #str)) + eq(5, hm.matching_bracket(str, 8, #str)) + eq(5, hm.matching_bracket(str, 9, #str)) + end) + + it("if cursor is over a square bracket it can find the pair", function() + local str = "abc [efg]" + eq(9, hm.matching_bracket(str, 5, #str)) + eq(5, hm.matching_bracket(str, 6, #str)) + eq(5, hm.matching_bracket(str, 7, #str)) + eq(5, hm.matching_bracket(str, 8, #str)) + eq(5, hm.matching_bracket(str, 9, #str)) + end) + + it("if cursor is over a curly bracket it can find the pair", function() + local str = "abc {efg}" + eq(9, hm.matching_bracket(str, 5, #str)) + eq(5, hm.matching_bracket(str, 6, #str)) + eq(5, hm.matching_bracket(str, 7, #str)) + eq(5, hm.matching_bracket(str, 8, #str)) + eq(5, hm.matching_bracket(str, 9, #str)) + end) + + it("nested brackets find the correct pair", function() + local str = "abc (efg [hij] klm)" + eq(19, hm.matching_bracket(str, 5, #str)) + eq(14, hm.matching_bracket(str, 6, #str)) + eq(14, hm.matching_bracket(str, 10, #str)) + eq(10, hm.matching_bracket(str, 14, #str)) + eq(5, hm.matching_bracket(str, 15, #str)) + eq(5, hm.matching_bracket(str, 19, #str)) + end) + + it("nested brackets of the same type find the correct pair", function() + local str = "abc (efg (hij) klm)" + eq(19, hm.matching_bracket(str, 5, #str)) + eq(14, hm.matching_bracket(str, 6, #str)) + eq(14, hm.matching_bracket(str, 10, #str)) + eq(10, hm.matching_bracket(str, 14, #str)) + eq(5, hm.matching_bracket(str, 15, #str)) + eq(5, hm.matching_bracket(str, 19, #str)) + end) + + it("if cursor is over an unclosed bracket it returns 0", function() + local str = "abc (efg" + eq(0, hm.matching_bracket(str, 5, #str)) + eq(0, hm.matching_bracket(str, 5, #str)) + eq(0, hm.matching_bracket(str, 5, #str)) + end) +end) + +describe("matching comments", function() + it("if cursor is over a comment it can find the pair", function() + local str = "abc /*efg*/" + eq(10, hm.matching_comment(str, 5, #str)) + eq(10, hm.matching_comment(str, 6, #str)) + eq(5, hm.matching_comment(str, 7, #str)) + eq(5, hm.matching_comment(str, 10, #str)) + eq(5, hm.matching_comment(str, 11, #str)) + end) + + it("if cursor is over an unclosed comment it returns 0", function() + local str = "abc /*efg" + eq(0, hm.matching_comment(str, 5, #str)) + eq(0, hm.matching_comment(str, 6, #str)) + end) +end) + +describe("edge case", function() + it("can handle empty strings", function() + eq(0, hm.next_word_boundary("", 1, 0, false)) + eq(0, hm.prev_word_boundary("", 1, 0, false)) + eq(0, hm.end_of_word("", 1, 0, false)) + end) + + it("can handle strings with only whitespace", function() + eq(0, hm.next_word_boundary(" ", 1, 1, false)) + eq(0, hm.prev_word_boundary(" ", 1, 1, false)) + eq(0, hm.end_of_word(" ", 1, 1, false)) + end) + + it("can handle strings with special characters in the middle", function() + local str = "vim.keymap.set('n', 't;', ':Test')" + eq(5, hm.next_word_boundary(str, 4, #str, false)) + eq(1, hm.prev_word_boundary(str, 4, #str, false)) + eq(10, hm.end_of_word(str, 4, #str, false)) + end) + + it("can handle strings with multiple consecutive special characters", function() + local str = "this || that" + eq(9, hm.next_word_boundary(str, 6, #str, false)) + eq(1, hm.prev_word_boundary(str, 6, #str, false)) + eq(7, hm.end_of_word(str, 6, #str, false)) + end) + + it("strings with spaces at the end", function() + local str = "there is a space " + eq(0, hm.end_of_word(str, 16, #str, false)) + end) + + it("single character next word ends", function() + local str = "show_something = true," + eq(14, hm.end_of_word(str, 1, #str, false)) + eq(16, hm.end_of_word(str, 14, #str, false)) + eq(16, hm.end_of_word(str, 15, #str, false)) + eq(22, hm.end_of_word(str, 21, #str, false)) + end) + + it("multibyte characters", function() + local str = "# 💭👀precognition.nvim" + local len = vim.fn.strcharlen(str) + eq(3, hm.next_word_boundary(str, 1, len, false)) + eq(17, hm.prev_word_boundary(str, 18, len, false)) + eq(3, hm.prev_word_boundary(str, 18, len, true)) + eq(3, hm.prev_word_boundary(str, 5, len, false)) + end) + + it("quoted strings", function() + local str = 'this = "that"' + eq(8, hm.end_of_word(str, 6, #str, false)) + + str = 'b = "^", c = 2 },' + eq(8, hm.end_of_word(str, 3, #str, false)) + end) +end) From 0fe724cf47352b5feaf42aeed7af0d536e50665f Mon Sep 17 00:00:00 2001 From: tris203 Date: Fri, 20 Dec 2024 16:21:45 +0000 Subject: [PATCH 09/11] test(dts): add brackets back --- Makefile | 1 - lua/precognition/sim.lua | 1 + tests/precognition/dts.lua | 2 -- tests/precognition/utils/dts.lua | 14 +++++++------- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 0fb7be0..ca25237 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,5 @@ test: dts: @nvim \ --headless \ - --noplugin \ -u ${TESTS_INIT} \ -l ${DTS_SCRIPT} ${SEED_START} ${NUM_TESTS} \ diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index 97afbe1..faae70d 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -59,6 +59,7 @@ end M.check = function(line, col) local remote = get_remote() + remote.o.cpoptions = vim.o.cpoptions local result = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) return result end diff --git a/tests/precognition/dts.lua b/tests/precognition/dts.lua index 2932b84..c11dec6 100644 --- a/tests/precognition/dts.lua +++ b/tests/precognition/dts.lua @@ -26,8 +26,6 @@ function M.test(seed) end, }) - virtual_line_marks.MatchingPair = nil - local temp_buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(temp_buf, 0, -1, false, { cur_line }) diff --git a/tests/precognition/utils/dts.lua b/tests/precognition/utils/dts.lua index 35e99c4..2f11f93 100644 --- a/tests/precognition/utils/dts.lua +++ b/tests/precognition/utils/dts.lua @@ -2,13 +2,13 @@ local M = {} local ranges = { { 32, 126 }, -- Basic Latin (ASCII) - { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A - { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew - { 8192, 8303 }, -- General Punctuation - { 9728, 9983 }, -- Miscellaneous Symbols - { 12352, 12447 }, -- Hiragana - { 19904, 19967 }, -- Mahjong Tiles - { 0x1F300, 0x1F6FF }, -- Emoji + -- { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A + -- { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew + -- { 8192, 8303 }, -- General Punctuation + -- { 9728, 9983 }, -- Miscellaneous Symbols + -- { 12352, 12447 }, -- Hiragana + -- { 19904, 19967 }, -- Mahjong Tiles + -- { 0x1F300, 0x1F6FF }, -- Emoji } ---@class dts.Random From 73e873ddf5d51e4316e050cdad07a87081a6405f Mon Sep 17 00:00:00 2001 From: tris203 Date: Fri, 20 Dec 2024 16:28:48 +0000 Subject: [PATCH 10/11] fix(dts): enable other scopes and reorder option setting --- lua/precognition/sim.lua | 2 +- tests/precognition/utils/dts.lua | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index faae70d..8c8f8db 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -17,6 +17,7 @@ local function get_remote() if not remote_instance then local remote = mt.new_child_neovim() remote.start() + remote.o.cpoptions = vim.o.cpoptions remote_instance = setmetatable({ instance = remote }, remote_mt) end return remote_instance.instance @@ -59,7 +60,6 @@ end M.check = function(line, col) local remote = get_remote() - remote.o.cpoptions = vim.o.cpoptions local result = remote.lua_func(check_pos, line, col, require("precognition").default_hint_config) return result end diff --git a/tests/precognition/utils/dts.lua b/tests/precognition/utils/dts.lua index 2f11f93..35e99c4 100644 --- a/tests/precognition/utils/dts.lua +++ b/tests/precognition/utils/dts.lua @@ -2,13 +2,13 @@ local M = {} local ranges = { { 32, 126 }, -- Basic Latin (ASCII) - -- { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A - -- { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew - -- { 8192, 8303 }, -- General Punctuation - -- { 9728, 9983 }, -- Miscellaneous Symbols - -- { 12352, 12447 }, -- Hiragana - -- { 19904, 19967 }, -- Mahjong Tiles - -- { 0x1F300, 0x1F6FF }, -- Emoji + { 160, 591 }, -- Latin-1 Supplement and Latin Extended-A + { 880, 2047 }, -- Greek, Cyrillic, Armenian, Hebrew + { 8192, 8303 }, -- General Punctuation + { 9728, 9983 }, -- Miscellaneous Symbols + { 12352, 12447 }, -- Hiragana + { 19904, 19967 }, -- Mahjong Tiles + { 0x1F300, 0x1F6FF }, -- Emoji } ---@class dts.Random From f94af9d5128b0fdb7ff01866df4331ca6781cc74 Mon Sep 17 00:00:00 2001 From: tris203 Date: Fri, 20 Dec 2024 22:15:06 +0000 Subject: [PATCH 11/11] fix(sim): set opts --- lua/precognition/sim.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/precognition/sim.lua b/lua/precognition/sim.lua index 8c8f8db..c797fb6 100644 --- a/lua/precognition/sim.lua +++ b/lua/precognition/sim.lua @@ -13,11 +13,15 @@ local remote_mt = { end, } +local function set_opts(cpooptions) + vim.o.cpoptions = cpooptions +end + local function get_remote() if not remote_instance then local remote = mt.new_child_neovim() remote.start() - remote.o.cpoptions = vim.o.cpoptions + remote.lua_func(set_opts, vim.o.cpoptions) remote_instance = setmetatable({ instance = remote }, remote_mt) end return remote_instance.instance