diff --git a/README.md b/README.md index c24124b..99b1d7b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ start neovim with `nvim --cmd "set rtp+=$(pwd)" .` to automatically load the fi ## up next -* text.lua testing * action.lua testing? ## TODO: needed functionality diff --git a/lua/zettelkasten/action.lua b/lua/zettelkasten/action.lua index 28863e9..9edc778 100644 --- a/lua/zettelkasten/action.lua +++ b/lua/zettelkasten/action.lua @@ -47,8 +47,9 @@ function A.make_link(visual) else selection, start_col = t.get_current_word() end - vim.api.nvim_set_current_line(t.replace_text(selection, l.new(selection), - start_col)) + vim.api.nvim_set_current_line(t.replace_text_in_current_line(selection, + l.new(selection), + start_col)) end return {open = A.open, open_selected = A.open_selected, make_link = A.make_link} diff --git a/lua/zettelkasten/text.lua b/lua/zettelkasten/text.lua index a3ea7e1..a9a8092 100644 --- a/lua/zettelkasten/text.lua +++ b/lua/zettelkasten/text.lua @@ -7,7 +7,7 @@ function T.get_current_selection() local line, start_col, end_col = vim.fn.getpos("'<")[2], vim.fn.getpos("'<")[3], vim.fn.getpos("'>")[3] - local selection = vim.fn.getline(line, line)[1]:sub(start_col, end_col) + local selection = T.get_line(line):sub(start_col, end_col) return selection, start_col end @@ -20,7 +20,7 @@ function T.get_current_word(big) if not big then pattern = [[\S]] end local cur_col = vim.api.nvim_win_get_cursor(0)[2] - local line = vim.api.nvim_get_current_line() + local line = T.get_line() local word_before_cur = vim.fn.matchstrpos(line:sub(1, cur_col + 1), pattern .. "*$") @@ -70,8 +70,8 @@ end -- which can prevent falsely substituting the wrong text fragment if an -- identical one exists earlier on the line. (E.g. I want to replace the -- second 'test' in 'test test 1 2 3'). -function T.replace_text(text, new_text, start_col) - local line_full = vim.api.nvim_get_current_line() +function T.replace_text_in_current_line(text, new_text, start_col) + local line_full = T.get_line() local line_edited if start_col then line_edited = line_full:sub(1, start_col - 1) .. @@ -85,12 +85,12 @@ end --- Return editor line contents. -- Returns the content of the line number passed in or the currently active --- line if no number passed in. Lines are, as per neovim function, --- *zero-indexed* compared to what you see in e.g. the editor sidebar. +-- line if no number passed in. Lines are, different to the neovim function, +-- *one-indexed*. --- @param linenr number --- @return string function T.get_line(linenr) - if linenr then return vim.api.nvim_buf_get_lines(0, linenr, linenr + 1) end + if linenr then return vim.api.nvim_buf_get_lines(0, linenr - 1, linenr, false)[1] end return vim.api.nvim_get_current_line() end diff --git a/lua/zettelkasten/text_spec.lua b/lua/zettelkasten/text_spec.lua index 2436402..dc08260 100644 --- a/lua/zettelkasten/text_spec.lua +++ b/lua/zettelkasten/text_spec.lua @@ -3,30 +3,106 @@ local t = require 'zettelkasten.text' before_each(function() _G.vim = {g = {}, b = {}} end) after_each(function() _G.vim = nil end) -describe("get_line", function() - it("returns current line contents if no line nr passed", function() - vim.api = { - nvim_get_current_line = function() - return "hello my old friend" - end - } - assert.same("hello my old friend", t.get_line()) - end) - it("returns zero-indexed line contents", function() - vim.api = { - nvim_buf_get_lines = function(...) - local args = table.pack(...) - if args[1] == 0 and args[2] + 1 == args[3] then - return "hello my new enemy" +describe("get_current_selection", function() + before_each(function() + vim.fn = { + getpos = function(mark) + if mark == "'<" then + return {0, 1, 15} + elseif mark == "'>" then + return {0, 1, 23} end - return "wrong arguments" end } - assert.same("hello my new enemy", t.get_line(1)) + vim.api = { + nvim_buf_get_lines = function() + return {"unfortunately we did it not"} + end + } + end) + it("returns the selected area", + function() assert.same("we did it", t.get_current_selection()) end) + it("returns the starting selection column", function() + local _, result = t.get_current_selection() + assert.same(15, result) end) end) --- describe("Zettelkasten", function() --- it("should create an anchor for the current datetime", --- function() assert.same(os.date('%y%m%d%H%M'), ZK.create_anchor()) end) --- end) +describe("get_current_word", function() + it("returns the complete word the cursor is over", function() + vim.api = { + nvim_get_current_line = function() + return "we found aWord here" + end, + nvim_win_get_cursor = function() return {0, 12, 0} end + } + vim.fn = { + matchstrpos = function(txt, _) + if #txt == 13 then return {"aWor", 1} end + end, + matchstr = function(_, _) return "rd" end + } + assert.same("aWord", t.get_current_word()) + end) +end) + +describe("replace_text", function() + before_each(function() + vim.api = { + nvim_get_current_line = function() + return "we-are? pretty pretty" + end + } + end) + + it("returns the current editor line with input text correctly replaced", + function() + assert.same("you-are? pretty pretty", + t.replace_text_in_current_line("we", "you")) + end) + + it("only replaces exactly one instance of whatever it matches", function() + assert.same("we-are? awesome pretty", + t.replace_text_in_current_line("pretty", "awesome")) + end) + + it("avoids replacing the first line match if the second should be replaced", + function() + assert.same("we-are? pretty awesome", + t.replace_text_in_current_line("pretty", "awesome", 15)) + end) + + it("correctly replaces dashes, or other lua special matching characters", + function() + assert.same("we-are! amazingly? pretty pretty", + t.replace_text_in_current_line("we-are", "we-are! amazingly")) + end) + +end) + +describe("get_line", function() + before_each(function() + vim.api = { + nvim_get_current_line = function() + return "hello my old friend" + end, + nvim_buf_get_lines = function(...) + local args = table.pack(...) + if args[1] == 0 and args[2] + 1 == args[3] then + return {"hello my new enemy"} + end + return {"wrong arguments"} + end + } + end) + it("returns current line contents if no line nr passed", + function() assert.same("hello my old friend", t.get_line()) end) + it("returns arbitrary line contents when numbered", + function() assert.same("hello my new enemy", t.get_line(1)) end) + it("takes a 1-indexed line but calls the nvim internal 0-index", function() + local gl = mock(vim.api) + t.get_line(1) + assert.spy(gl.nvim_buf_get_lines).was_called_with(0, 0, 1, false) + mock.revert(t) + end) +end)