๐Ÿ’ YAML toolkit for Neovim users

Adds highlight feature

Closes #35

+112 -7
+2
README.md
··· 10 10 | `:YAMLYank [register]` | `yaml.yank_all([register])` | Yanks the full path and value of the current key/value pair. The default register is the unnamed one (`"`) | 11 11 | `:YAMLYankKey [register]` | `yaml.yank_key([register])` | Yanks the full path of the key for the current key/value pair. The default register is the unnamed one (`"`) | 12 12 | `:YAMLYankValue [register]` | `yaml.yank_value([register])` | Yanks the value of the current key/value pair. The default register is the unnamed one (`"`) | 13 + | `:YAMLHighlight <key>` | `yaml.highlight(key)` | Highlights the line(s) of an YAML `key` | 14 + | `:YAMLRemoveHighlight` | `yaml.remove_highlight()` | Removes the highlight created by `:YAMLHighlight`/`yaml.highlight(key)` | 13 15 | `:YAMLQuickfix` | `yaml.quickfix()` | Generates a quickfix with key/value pairs | 14 16 | `:YAMLSnacks` | `yaml.snacks()` | Full path key/value fuzzy finder via [Snacks](https://github.com/folke/snacks.nvim) **if installed** | 15 17 | `:YAMLTelescope` | `yaml.telescope()` | Full path key/value fuzzy finder via [Telescope](https://github.com/nvim-telescope/telescope.nvim) **if installed** |
+9
doc/help.txt
··· 35 35 Yanks the value of the key/value pair under the cursor to the selected 36 36 register. The default register is the unnamed one (see |:quotequote|). 37 37 38 + :YAMLHighlight <key> *:YAMLHighlight* 39 + 40 + Highlights the line(s) of the provided YAML key. The key should match 41 + the output format used in |:YAMLViem|. 42 + 43 + :YAMLRemoveHighlight *:YAMLRemoveHighlight* 44 + 45 + Removes the highlight created by |:YAMLHighlight|. 46 + 38 47 :YAMLQuickfix *YAMLQuickfix* 39 48 40 49 Creates a |:quickfix| list with the contents of the YAML, showing the full
+45
lua/yaml_nvim/init.lua
··· 137 137 yank(get_current_yaml_node(), false, true, register) 138 138 end 139 139 140 + M.current_highlight = nil 141 + 142 + M.highlight = function(key) 143 + if not is_yaml() then 144 + return 145 + end 146 + 147 + local restore_to = set_yaml_as_filetype() 148 + 149 + local target = nil 150 + for _, node in pairs(document.all_keys()) do 151 + if not document.is_value_a_block(node) then 152 + local parsed = pair.parse(node) 153 + if parsed.key == key then 154 + target = parsed 155 + break 156 + end 157 + end 158 + end 159 + if target == nil then 160 + vim.notify(key .. " not found") 161 + return 162 + end 163 + 164 + local pattern = "\\%" .. target.lines[1] .. "l" 165 + if target.lines[2] > target.lines[1] then 166 + pattern = "\\%>" .. target.lines[1] .. "l\\%<" .. target.lines[2] .. "l" 167 + end 168 + 169 + M.remove_highlight() 170 + M.current_highlight = vim.fn.matchadd("Visual", pattern) 171 + restore_filetype(restore_to) 172 + end 173 + 174 + M.remove_highlight = function() 175 + if M.current_highlight == nil then 176 + return 177 + end 178 + 179 + vim.fn.matchdelete(M.current_highlight) 180 + M.current_highlight = nil 181 + end 182 + 140 183 M.quickfix = function() 141 184 if not is_yaml() then 142 185 return ··· 189 232 vim.cmd("command! -nargs=? YAMLYank lua require('yaml_nvim').yank(<f-args>)") 190 233 vim.cmd("command! -nargs=? YAMLYankKey lua require('yaml_nvim').yank_key(<f-args>)") 191 234 vim.cmd("command! -nargs=? YAMLYankValue lua require('yaml_nvim').yank_value(<f-args>)") 235 + vim.cmd("command! -nargs=? YAMLHighlight lua require('yaml_nvim').highlight(<f-args>)") 236 + vim.cmd("command! YAMLRemoveHighlight lua require('yaml_nvim').remove_highlight()") 192 237 vim.cmd("command! YAMLQuickfix lua require('yaml_nvim').quickfix()") 193 238 194 239 if has_snacks then
+14 -7
lua/yaml_nvim/pair.lua
··· 28 28 return trim(string.gsub(value:sub(2, #value), "%s+", " ")) 29 29 end 30 30 31 - local function get_value(node, bufnr) 31 + local function get_value_node(node) 32 32 while node ~= nil do 33 33 if node:type() == "block_mapping_pair" then 34 34 if node:field("value")[1] ~= nil then 35 - local value = node:field("value")[1] 36 - return table.concat({ vim.treesitter.get_node_text(value, bufnr) }, "\n") 35 + return node 37 36 end 38 37 end 39 38 node = node:parent() 40 39 end 40 + end 41 + 42 + local function get_value(node, bufnr) 43 + local value = node:field("value")[1] 44 + return table.concat({ vim.treesitter.get_node_text(value, bufnr) }, "\n") 41 45 end 42 46 43 47 local function is_sequence_block(value) ··· 96 100 M.parse = function(node) 97 101 local bufnr = vim.api.nvim_get_current_buf() 98 102 local key = get_keys(node, bufnr) 99 - local value = get_value(node, bufnr) 100 - local line, col = node:start() 103 + local value_node = get_value_node(node) 104 + local value = get_value(value_node, bufnr) 101 105 local cleaned_value = clean_up_block_value(value) 102 106 local human = string.format("%s = %s", key, cleaned_value) 107 + local start_line, start_col = node:start() 108 + local end_line, _ = value_node:end_() 103 109 104 110 return { 105 111 key = key, 106 112 cleaned_value = cleaned_value, 107 113 human = human, 114 + lines = { start_line + 1, end_line + 1 }, 108 115 quickfix = { 109 116 bufnr = bufnr, 110 - col = col, 111 - lnum = line + 1, 117 + col = start_col, 118 + lnum = start_line + 1, 112 119 text = human, 113 120 valid = 1, 114 121 },
+12
tests/yaml_nvim/commands_spec.lua
··· 51 51 assert.stub(yank_value).was_called_with("8") 52 52 end) 53 53 54 + it("YAMLHighlight calls Lua function for highlighting", function() 55 + local highlight = stub(require("yaml_nvim"), "highlight") 56 + vim.cmd("YAMLHighlight worldcup.intro") 57 + assert.stub(highlight).was_called_with("worldcup.intro") 58 + end) 59 + 60 + it("YAMLRemoveHighlight calls Lua function for removing highlight", function() 61 + local remove = stub(require("yaml_nvim"), "remove_highlight") 62 + vim.cmd("YAMLRemoveHighlight") 63 + assert.stub(remove).was_called_with() 64 + end) 65 + 54 66 it("YAMLQuickfix calls Lua function", function() 55 67 local qf = stub(require("yaml_nvim"), "quickfix") 56 68 vim.cmd("YAMLQuickfix")
+30
tests/yaml_nvim/functions_spec.lua
··· 57 57 assert.are.equal("7", vim.fn.getreg("7")) 58 58 end) 59 59 60 + it("highlight calls the notify function with unknown key", function() 61 + local matchadelete = stub(vim.fn, "matchdelete") 62 + local notify = stub(vim, "notify") 63 + require("yaml_nvim").highlight("this.key.does.not.exist") 64 + assert.spy(notify).was.called_with("this.key.does.not.exist not found") 65 + assert.spy(matchadelete).was_not.called() 66 + end) 67 + 68 + it("highlight calls matchadd with the proper line", function() 69 + local matchadd = stub(vim.fn, "matchadd") 70 + require("yaml_nvim").highlight("worldcup.host") 71 + assert.spy(matchadd).was.called_with("Visual", "\\%2l") 72 + end) 73 + 74 + it("highlight calls matchadd with the proper lines", function() 75 + local matchadd = stub(vim.fn, "matchadd") 76 + require("yaml_nvim").highlight("worldcup.intro") 77 + assert.spy(matchadd).was.called_with("Visual", "\\%>5l\\%<7l") 78 + end) 79 + 80 + it("remove_highlight calls matchdelete", function() 81 + local matchadelete = stub(vim.fn, "matchdelete") 82 + local yaml = require("yaml_nvim") 83 + yaml.current_highlight = 42 84 + yaml.highlight("worldcup.host") 85 + yaml.remove_highlight() 86 + assert.spy(matchadelete).was.called_with(42) 87 + assert.are.equal(nil, yaml.current_highlight) 88 + end) 89 + 60 90 it("snacks calls Snacks's native qflist function", function() 61 91 stub(vim.fn, "setqflist") 62 92 local snacks = require("snacks")