diff --git a/README.md b/README.md index 4dd24ca..2aa79dd 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ The plugin works with all languages inheriting from html, css and tsx treesitter - Class concealing - Class sorting (without [prettier-plugin](https://github.com/tailwindlabs/prettier-plugin-tailwindcss)) - Completion utilities (using [nvim-cmp](https://github.com/hrsh7th/nvim-cmp)) +- Class motions > [!NOTE] > Language services like autocompletion, diagnostics and hover are already provided by [tailwindcss-language-server](https://github.com/tailwindlabs/tailwindcss-intellisense/tree/master/packages/tailwindcss-language-server). @@ -100,6 +101,8 @@ Available commands: - `TailwindColorToggle`: toggles color hints. - `TailwindSort`: sorts all classes in the current buffer. - `TailwindSortSelection`: sorts selected classes in visual mode. +- `TailwindNextClass`: moves the cursor to the nearest next class node. +- `TailwindPrevClass`: moves the cursor to the nearest previous class node. ## Utilities diff --git a/lua/tailwind-tools/init.lua b/lua/tailwind-tools/init.lua index 6e4f313..a0f29e8 100644 --- a/lua/tailwind-tools/init.lua +++ b/lua/tailwind-tools/init.lua @@ -5,6 +5,7 @@ local lsp = require("tailwind-tools.lsp") local state = require("tailwind-tools.state") local config = require("tailwind-tools.config") local conceal = require("tailwind-tools.conceal") +local motions = require("tailwind-tools.motions") ---@param options TailwindTools.Option M.setup = function(options) @@ -34,6 +35,8 @@ M.setup = function(options) vim.api.nvim_create_user_command("TailwindColorEnable", lsp.enable_color, { nargs = 0 }) vim.api.nvim_create_user_command("TailwindColorDisable", lsp.disable_color, { nargs = 0 }) vim.api.nvim_create_user_command("TailwindColorToggle", lsp.toggle_colors, { nargs = 0 }) + vim.api.nvim_create_user_command("TailwindNextClass", motions.move_to_next_class, { nargs = 0 }) + vim.api.nvim_create_user_command("TailwindPrevClass", motions.move_to_prev_class, { nargs = 0 }) vim.api.nvim_create_autocmd("LspAttach", { group = vim.g.tailwind_tools.conceal_au, diff --git a/lua/tailwind-tools/motions.lua b/lua/tailwind-tools/motions.lua new file mode 100644 index 0000000..3598028 --- /dev/null +++ b/lua/tailwind-tools/motions.lua @@ -0,0 +1,49 @@ +local M = {} + +local treesitter = require("tailwind-tools.treesitter") + +M.move_to_next_class = function() + local nodes = treesitter.get_class_nodes(0, true) + + if not nodes then return end + + local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) + + table.sort(nodes, function(a, b) + local a_row, a_col = treesitter.get_class_range(a, 0) + local b_row, b_col = treesitter.get_class_range(b, 0) + return a_row == b_row and a_col < b_col or a_row < b_row + end) + + for _, node in ipairs(nodes) do + local node_row, node_col = treesitter.get_class_range(node, 0) + + if node_row > cursor_row - 1 or (node_row == cursor_row - 1 and node_col > cursor_col) then + return vim.api.nvim_win_set_cursor(0, { node_row + 1, node_col }) + end + end +end + +M.move_to_prev_class = function() + local nodes = treesitter.get_class_nodes(0, true) + + if not nodes then return end + + local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) + + table.sort(nodes, function(a, b) + local a_row, a_col = treesitter.get_class_range(a, 0) + local b_row, b_col = treesitter.get_class_range(b, 0) + return a_row == b_row and a_col > b_col or a_row > b_row + end) + + for _, node in ipairs(nodes) do + local node_row, node_col = treesitter.get_class_range(node, 0) + + if node_row < cursor_row - 1 or (node_row == cursor_row - 1 and node_col < cursor_col) then + return vim.api.nvim_win_set_cursor(0, { node_row + 1, node_col }) + end + end +end + +return M diff --git a/tests/init.lua b/tests/init.lua index fedd34f..918f008 100644 --- a/tests/init.lua +++ b/tests/init.lua @@ -17,5 +17,5 @@ vim.o.swapfile = false require("lazy").setup({ { "nvim-lua/plenary.nvim" }, - { dir = "../", dependencies = { "nvim-treesitter/nvim-treesitter" } }, + { dir = "./", opts = {}, dependencies = { "nvim-treesitter/nvim-treesitter" } }, }) diff --git a/tests/motions/index.html b/tests/motions/index.html new file mode 100644 index 0000000..9cbd377 --- /dev/null +++ b/tests/motions/index.html @@ -0,0 +1,20 @@ + + + + + + + Test + + + +
Test
+
+
+ Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint + cillum sint consectetur cupidatat. +
+
+ + + diff --git a/tests/motions/jump_spec.lua b/tests/motions/jump_spec.lua new file mode 100644 index 0000000..ec17551 --- /dev/null +++ b/tests/motions/jump_spec.lua @@ -0,0 +1,31 @@ +local assert = require("luassert") + +local function assert_cursor(expected_row, expected_col) + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + assert.same(expected_row, row, "Mismatched row") + assert.same(expected_col, col, "Mismatched col") +end + +describe("jump motion:", function() + vim.cmd.edit("tests/motions/index.html") + + it("should go to the next class", function() + vim.cmd.TailwindNextClass() + assert_cursor(11, 14) + vim.cmd.TailwindNextClass() + assert_cursor(12, 14) + vim.cmd.TailwindNextClass() + assert_cursor(13, 16) + vim.cmd.TailwindNextClass() + assert_cursor(13, 16) + end) + + it("should go to the prev class", function() + vim.cmd.TailwindPrevClass() + assert_cursor(12, 14) + vim.cmd.TailwindPrevClass() + assert_cursor(11, 14) + vim.cmd.TailwindPrevClass() + assert_cursor(11, 14) + end) +end)