Repository: gennaro-tedesco/nvim-jqx Branch: master Commit: 07393e80fa80 Files: 15 Total size: 24.6 KB Directory structure: gitextract_nk9l8pf_/ ├── .github/ │ └── workflows/ │ ├── panvimdoc.yml │ └── release.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── doc/ │ ├── jqx.txt │ └── tags ├── examples/ │ ├── test.json │ └── test.yaml ├── lua/ │ └── nvim-jqx/ │ ├── config.lua │ ├── floating.lua │ ├── init.lua │ └── jqx.lua └── plugin/ └── nvim-jqx.vim ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/panvimdoc.yml ================================================ name: panvimdoc on: workflow_dispatch: push: paths: - "README.md" - "**.yml" jobs: docs: runs-on: ubuntu-latest name: pandoc to vimdoc permissions: contents: write steps: - uses: actions/checkout@v3 - name: panvimdoc uses: kdheepak/panvimdoc@main with: vimdoc: jqx version: "Neovim >= 0.8.0" demojify: true treesitter: true - uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "Auto generate docs" branch: ${{ github.head_ref }} ================================================ FILE: .github/workflows/release.yml ================================================ name: release on: workflow_dispatch: push: tags: - "v*.*.*" jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Release uses: softprops/action-gh-release@v1 luarocks-release: runs-on: ubuntu-latest name: LuaRocks upload steps: - name: Checkout uses: actions/checkout@v3 - name: LuaRocks Upload uses: nvim-neorocks/luarocks-tag-release@v2.1.0 env: LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} with: copy_directories: | doc license: "MIT" ================================================ FILE: .gitignore ================================================ /plugin/reload.vim ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/JohnnyMorganz/StyLua rev: v0.14.3 hooks: - id: stylua ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 Gennaro Tedesco Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================



nvim-jqx

luarocks releases

Populate the quickfix with json entries

InstallationUsageCustomisationFeedback

If only one could easily browse and preview json files in neovim. Oh wait, `nvim-jqx` does just that! ## Installation Install it using your favourite plugin manager: for instance - with [lazy.nvim](https://github.com/folke/lazy.nvim) ```lua { "gennaro-tedesco/nvim-jqx", event = {"BufReadPost"}, ft = { "json", "yaml" }, }, ``` Notice that `jq` is a prerequisite, as this plugin executes `jq` queries internally. ## Usage `nvim-jqx` exposes two commands: `JqxList` and `JqxQuery`. Open a json file and issue `JqxList`: the json is prettified and the quickfix window is populated with the first level keys. Press `X` on a key to query its values and show the results in a floating window; alternatively `` takes you to its location in the file. ![JqxListdemo](https://user-images.githubusercontent.com/15387611/113495463-4bd24500-94f2-11eb-88b5-64c1ee965886.gif) `JqxList` also accepts an optional argument representing the json type you want to subselect: for example `JqxList number` populates the quickfix with entries of type number only, so do `JqxList string`, `JqxList boolean` and so forth, respectively: this is quite useful for big files where you want to have a quick peek at, say, some numerical values only or similar. For a full list of available types see `h: jqx-usage` or simply hit `` to show the autocomplete for available types. To execute more complicated and generic `jq` commands use `JqxQuery` instead; the prompt helps autocomplete with the file keys for easy typing. Open a json file `test.json` and issue `JqxQuery `: this translates into `jq "." test.json` as shown below ``` # JqxQuery grammar JqxQuery friends[2].name "Michael Marquez" # jq equivalent jq '.friends[2].name' test.json "Michael Marquez" ``` ![JqxQuerydemo](https://user-images.githubusercontent.com/15387611/113495732-ab7d2000-94f3-11eb-8781-0497771b60a1.gif) Default commands | command | description | | :--------------- | :------------------------------------------------ | | `JqxList` | populate the quickfix window with json keys | | `JqxList string` | populate the quickfix window with string values | | `JqxQuery` | executes a generic `jq` query in the current file | | `` | go to key location in file | | X | query values of key under cursor | | `` | close floating window | Try it out directly with `nvim examples/test.json -c JqxList`. For more in-depth description and explanations check the documentation `:h nvim-jqx` and links therein. ### Yaml files `nvim-jqx` works on `yaml` files too. It requires, however, to install [yq](https://github.com/kislyuk/yq). Try it out directly with `nvim examples/test.yaml -c JqxList`, or execute `JqxQuery` on a `yaml` file. > ⚠️ this plugin works with the Python implementation of yq by @kislyuk, not to be confused > with the Go implementation of yq by @mikefarah. ## Customisation If you prefer key-mappings rather than commands simply bind ``` nmap ... JqxList ``` The configurable options are exposed in [nvim-jqx/config.lua](https://github.com/gennaro-tedesco/nvim-jqx/blob/master/lua/nvim-jqx/config.lua) and can be overridden at will. For example, with `lazy.nvim` you can configure them as ```lua { "gennaro-tedesco/nvim-jqx", ... init = function() local jqx = require("nvim-jqx.config") jqx.geometry.border = "single" jqx.geometry.width = 0.7 ... jqx.query_key = "X" -- keypress to query jq on keys jqx.sort = false -- show the json keys as they appear instead of sorting them alphabetically jqx.show_legend = true -- show key queried as first line in the jqx floating window jqx.use_quickfix = false -- if you prefer the location list end, } ``` Why not automatically formatting your `json` files as you open them? Set up the autogroup ```lua local jqx = vim.api.nvim_create_augroup("Jqx", {}) vim.api.nvim_clear_autocmds({ group = jqx }) vim.api.nvim_create_autocmd("BufWinEnter", { pattern = { "*.json", "*.yaml" }, desc = "preview json and yaml files on open", group = jqx, callback = function() vim.cmd.JqxList() end, }) ``` ## Feedback If you find this plugin useful consider awarding it a ⭐, it is a great way to give feedback! Otherwise, any additional suggestions or merge request is warmly welcome! ================================================ FILE: doc/jqx.txt ================================================ *jqx.txt* For Neovim >= 0.8.0 Last change: 2024 May 31 ============================================================================== Table of Contents *jqx-table-of-contents* - Installation |jqx-installation| - Usage |jqx-usage| - Customisation |jqx-customisation| - Feedback |jqx-feedback| 1. Links |jqx-links| nvim-jqx Populate the quickfix with json entriesInstallation • Usage • Customisation • FeedbackIf only one could easily browse and preview json files in neovim. Oh wait, `nvim-jqx` does just that! INSTALLATION *jqx-installation* Install it using your favourite plugin manager: for instance - with lazy.nvim >lua { "gennaro-tedesco/nvim-jqx", event = {"BufReadPost"}, ft = { "json", "yaml" }, }, < Notice that `jq` is a prerequisite, as this plugin executes `jq` queries internally. USAGE *jqx-usage* `nvim-jqx` exposes two commands: `JqxList` and `JqxQuery`. Open a json file and issue `JqxList`the json is prettified and the quickfix window is populated with the first level keys. Press `X` on a key to query its values and show the results in a floating window; alternatively `` takes you to its location in the file. `JqxList` also accepts an optional argument representing the json type you want to subselect: for example `JqxList number` populates the quickfix with entries of type number only, so do `JqxList string`, `JqxList boolean` and so forth, respectively: this is quite useful for big files where you want to have a quick peek at, say, some numerical values only or similar. For a full list of available types see `h: jqx-usage` or simply hit `` to show the autocomplete for available types. To execute more complicated and generic `jq` commands use `JqxQuery` instead; the prompt helps autocomplete with the file keys for easy typing. Open a json file `test.json` and issue `JqxQuery `this translates into `jq "." test.json` as shown below > # JqxQuery grammar JqxQuery friends[2].name "Michael Marquez" # jq equivalent jq '.friends[2].name' test.json "Michael Marquez" < Default commands command description ---------------- ------------------------------------------------- JqxList populate the quickfix window with json keys JqxList string populate the quickfix window with string values JqxQuery executes a generic jq query in the current file go to key location in file X query values of key under cursor close floating window Try it out directly with `nvim examples/test.json -c JqxList`. For more in-depth description and explanations check the documentation |nvim-jqx| and links therein. YAML FILES ~ `nvim-jqx` works on `yaml` files too. It requires, however, to install yq . Try it out directly with `nvim examples/test.yaml -c JqxList`, or execute `JqxQuery` on a `yaml` file. this plugin works with the Python implementation of yq by @kislyuk, not to be confused with the Go implementation of yq by @mikefarah. CUSTOMISATION *jqx-customisation* If you prefer key-mappings rather than commands simply bind > nmap ... JqxList < The configurable options are exposed in nvim-jqx/config.lua and can be overridden at will. For example, with `lazy.nvim` you can configure them as >lua { "gennaro-tedesco/nvim-jqx", ... init = function() local jqx = require("nvim-jqx.config") jqx.geometry.border = "single" jqx.geometry.width = 0.7 ... jqx.query_key = "X" -- keypress to query jq on keys jqx.sort = false -- show the json keys as they appear instead of sorting them alphabetically jqx.show_legend = true -- show key queried as first line in the jqx floating window jqx.use_quickfix = false -- if you prefer the location list end, } < Why not automatically formatting your `json` files as you open them? Set up the autogroup >lua local jqx = vim.api.nvim_create_augroup("Jqx", {}) vim.api.nvim_clear_autocmds({ group = jqx }) vim.api.nvim_create_autocmd("BufWinEnter", { pattern = { "*.json", "*.yaml" }, desc = "preview json and yaml files on open", group = jqx, callback = function() vim.cmd.JqxList() end, }) < FEEDBACK *jqx-feedback* If you find this plugin useful consider awarding it a , it is a great way to give feedback! Otherwise, any additional suggestions or merge request is warmly welcome! ============================================================================== 1. Links *jqx-links* 1. *JqxListdemo*: https://user-images.githubusercontent.com/15387611/113495463-4bd24500-94f2-11eb-88b5-64c1ee965886.gif 2. *JqxQuerydemo*: https://user-images.githubusercontent.com/15387611/113495732-ab7d2000-94f3-11eb-8781-0497771b60a1.gif 3. *@kislyuk*: 4. *@mikefarah*: Generated by panvimdoc vim:tw=78:ts=8:noet:ft=help:norl: ================================================ FILE: doc/tags ================================================ JqxList jqx.txt /*JqxList* JqxQuery jqx.txt /*JqxQuery* jqx-commands jqx.txt /*jqx-commands* jqx-contents jqx.txt /*jqx-contents* jqx-customisation jqx.txt /*jqx-customisation* jqx-introduction jqx.txt /*jqx-introduction* jqx-usage jqx.txt /*jqx-usage* nvim-jqx jqx.txt /*nvim-jqx* ================================================ FILE: examples/test.json ================================================ { "_id": "60411184f69184d7cbdbe207", "index": 0, "guid": "ac11be49-d7e5-4716-b95b-08bd7f04c631", "is active": true, "balance": "$1,620.45", "picture": "http://placehold.it/32x32", "age": 32, "eyeColor": "brown", "name": "Dianna Rowland", "gender": "female", "company": "MEGALL", "email": "diannarowland@megall.com", "phone": "+1 (989) 506-3197", "address": "587 Thatford Avenue, Brookfield, Idaho, 8295", "about": "Commodo laborum tempor et laborum sint. Id ut labore labore do ad duis fugiat sint. Id ut laborum ullamco reprehenderit Lorem fugiat nostrud aliqua aute non magna aliquip.\r\n", "registered": "2019-06-20T06:41:43 -02:00", "latitude": 82.560783, "longitude": 147.725325, "tags": [ "laboris", "cillum", "ullamco", "consectetur", "labore", "sunt", "occaecat" ], "friends": [ { "id": 0, "name": "Black Schroeder" }, { "id": 1, "name": "Sellers Garza" }, { "id": 2, "name": "Michael Marquez" } ], "morning greeting": "Hello, Dianna Rowland! You have 6 unread messages.", "favoriteFruit": "strawberry" } ================================================ FILE: examples/test.yaml ================================================ apiVersion: apps/v1 kind: Deployment metadata: name: octopus-deployment labels: app: web spec: selector: matchLabels: octopusexport: OctopusExport replicas: 1 strategy: type: RollingUpdate template: metadata: labels: app: web octopusexport: OctopusExport spec: containers: - name: nginx image: nginx ports: - containerPort: 80 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - web topologyKey: kubernetes.io/hostname ================================================ FILE: lua/nvim-jqx/config.lua ================================================ local geometry = { width = 0.4, height = 0.3, wrap = true, border = "rounded", } local query_key = "X" local sort = true local close_window_key = "" local use_quickfix = true local show_legend = false return { geometry = geometry, query_key = query_key, sort = sort, close_window_key = close_window_key, use_quickfix = use_quickfix, show_legend = show_legend, } ================================================ FILE: lua/nvim-jqx/floating.lua ================================================ local config = require("nvim-jqx.config") local function centre_string(s) local shift = math.floor((vim.api.nvim_win_get_width(0) - #s) / 2) return string.rep(" ", shift) .. s end local function floating_window(geometry) local total_width = vim.api.nvim_get_option_value("columns", {}) local total_height = vim.api.nvim_get_option_value("lines", {}) local win_width = geometry.width <= 1 and math.ceil(total_width * geometry.width) or total_width local win_height = geometry.height <= 1 and math.ceil(total_height * geometry.height) or total_height local win_opts = { relative = "editor", width = win_width, height = win_height, row = math.ceil((total_height - win_height) / 2 - 1), col = math.ceil(total_width - win_width) / 2, focusable = true, style = "minimal", border = config.geometry.border, } local buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_open_win(buf, true, win_opts) vim.api.nvim_set_option_value("wrap", config.geometry.wrap, { win = 0 }) return buf end local function set_fw_opts(buf) vim.api.nvim_set_option_value("filetype", "jqx", { buf = buf }) vim.api.nvim_set_option_value("bufhidden", "wipe", { buf = buf }) vim.api.nvim_set_option_value("modifiable", false, { buf = buf }) vim.api.nvim_set_option_value("readonly", true, { buf = buf }) vim.api.nvim_buf_set_keymap( buf, "n", config.close_window_key, ":q j", { nowait = true, noremap = true, silent = true } ) vim.treesitter.start(buf, "json") end return { floating_window = floating_window, set_fw_opts = set_fw_opts, centre_string = centre_string, } ================================================ FILE: lua/nvim-jqx/init.lua ================================================ --[[ this module exposes the main interface and user commands that are defined in /plugin/nvim-jqx.vim ]] local jqx = require("nvim-jqx.jqx") local config = require("nvim-jqx.config") local fw = require("nvim-jqx.floating") ---@returns boolean local function is_valid_ft(ft) if not (ft == "json" or ft == "yaml") then print("only json or yaml files") return false end if ft == "json" then if vim.fn.executable("jq") == 0 then print("please install jq") return false end end if ft == "yaml" then if vim.fn.executable("yq") == 0 then print("please install yq") return false end end return true end ---set keymaps in the qf to query entry on keypress local function set_qf_maps(ft) vim.api.nvim_exec2( [[autocmd FileType qf nnoremap ]] .. config.query_key .. [[ :lua require("nvim-jqx.jqx").on_keystroke("]] .. ft .. [[") ]], { output = false } ) end ---main function interface that populates the quickfix list on invocation ---invoke set_qf_maps and jqx.populate_qf ---@param type string variable type to fetch if given local function jqx_open(type) local ft = vim.bo.filetype if not is_valid_ft(ft) then return nil end if ft == "json" then vim.cmd("%! jq .") end set_qf_maps(ft) jqx.populate_qf(ft, type, config.sort) end ---execute jq query from user input ---@param q string user query local function query_jq(q) local ft = vim.bo.filetype if not is_valid_ft(ft) then return nil end -- reads the query from user input vim.fn.inputsave() local input_query = q == "" and vim.fn.input("enter query: ") or q if input_query == "" then vim.cmd("redraw") print(" ") return nil end local cur_file = vim.fn.getreg("%") local user_query = ft == "json" and "jq '." .. input_query .. "' " .. cur_file or "yq '." .. input_query .. "' " .. cur_file vim.fn.inputrestore() -- parsing query results local query_results = {} for s in vim.fn.system(user_query):gmatch("[^\r\n]+") do table.insert(query_results, s) end vim.cmd("redraw") print(" ") local floating_buf = fw.floating_window(config.geometry) table.insert(query_results, 1, fw.centre_string(user_query)) table.insert(query_results, 2, "") vim.api.nvim_buf_set_lines(floating_buf, 0, -1, true, query_results) fw.set_fw_opts(floating_buf) vim.cmd('execute "normal! gg"') end return { jqx_open = jqx_open, query_jq = query_jq, } ================================================ FILE: lua/nvim-jqx/jqx.lua ================================================ local fw = require("nvim-jqx.floating") local config = require("nvim-jqx.config") local function has_value(tab, val) for _, value in ipairs(tab) do if value == val then return true end end return false end ---remove vim special characters from json keys ---@param key string ---@return string "parsed key" local function parse_key(key) return (key:gsub("/", "\\/")) end ---return location of key in buffer ---@param key string ---@param ft string ---@return table local function get_key_location(key, ft) if ft == "json" then return { row = vim.api.nvim_exec2([[g/^\s*"]] .. parse_key(key) .. [["/echo line('.')]], { output = true }).output, col = vim.api.nvim_exec2( [[g/^\s*"]] .. parse_key(key) .. [["/execute "normal! ^" | echo col('.')-1]], { output = true } ).output, } elseif ft == "yaml" then return { row = vim.api.nvim_exec2([[g/^]] .. parse_key(key) .. [[/echo line('.')]], { output = true }).output, col = vim.api.nvim_exec2( [[g/^]] .. parse_key(key) .. [[/execute "normal! ^" | echo col('.')]], { output = true } ).output, } else return {} end end ---fetch json keys for cur buf and populate qf list ---@param ft string ---@param type string variable type to fetch if given ---@param sort boolean sort list alphabetically local function populate_qf(ft, type, sort) local cmd_lines = {} local cur_file = vim.fn.getreg("%") if ft == "json" then local json_types = { "string", "number", "boolean", "array", "object", "null" } if has_value(json_types, type) then for s in vim.fn .system( "jq -c 'to_entries[] | if (.value|type == \"" .. type .. "\") then .key else empty end' " .. cur_file ) :gmatch("[^\r\n]+") do local key = s:gsub('%"', ""):gsub("^%s*(.-)%s*$", "%1"):gsub(",", "") table.insert(cmd_lines, key) end else local get_keys = sort and "jq 'keys[]' " .. cur_file or "jq 'keys_unsorted[]' " .. cur_file for s in vim.fn.system(get_keys):gmatch("[^\r\n]+") do local key = s:gsub('%"', ""):gsub("^%s*(.-)%s*$", "%1"):gsub(",", "") table.insert(cmd_lines, key) end end elseif ft == "yaml" then for s in vim.fn.system("yq 'keys[]' " .. cur_file):gmatch("[^\r\n]+") do local key = s:gsub("^-%s+", ""):gsub('"', "") table.insert(cmd_lines, key) end end local qf_list = {} for _, v in pairs(cmd_lines) do table.insert( qf_list, { filename = cur_file, lnum = get_key_location(v, ft).row, col = get_key_location(v, ft).col, text = v } ) end if config.use_quickfix then vim.fn.setqflist(qf_list, " ") vim.cmd("copen") else vim.fn.setloclist(0, qf_list, " ") vim.cmd("lopen") end end local function parse_jq_query(key, cur_file, ft) local parsed_lines = {} if ft == "json" then local jq_query = tonumber(key) ~= nil and "jq '.[" .. key .. "]' " .. cur_file or "jq '.\"" .. key .. "\"' " .. cur_file for s in vim.fn.system(jq_query):gmatch("[^\r\n]+") do table.insert(parsed_lines, s) end elseif ft == "yaml" then local yq_query = "yq '.\"" .. key .. "\"' " .. cur_file for s in vim.fn.system(yq_query):gmatch("[^\r\n]+") do table.insert(parsed_lines, s) end end return parsed_lines end local function on_keystroke(ft) local line = vim.api.nvim_get_current_line() local words = {} for word in line:gmatch("[^|]+") do table.insert(words, word:match("^%s*(.+)")) end local key, cur_file = words[#words], words[1] local results = parse_jq_query(key, cur_file, ft) local floating_buf = fw.floating_window(config.geometry) if config.show_legend then table.insert(results, 1, fw.centre_string(key)) table.insert(results, 2, "") end vim.api.nvim_buf_set_lines(floating_buf, 0, -1, true, results) fw.set_fw_opts(floating_buf) vim.cmd('execute "normal! gg"') end return { populate_qf = populate_qf, on_keystroke = on_keystroke, } ================================================ FILE: plugin/nvim-jqx.vim ================================================ if exists("g:loaded_jqx") finish endif nnoremap JqxList :lua require('nvim-jqx').jqx_open() command! -complete=customlist,TypeKeys -nargs=? JqxList execute 'lua require("nvim-jqx").jqx_open("'....'")' command! -complete=customlist,FileKeys -nargs=? JqxQuery execute 'lua require("nvim-jqx").query_jq("'....'")' function! TypeKeys(A, L, P) abort if &filetype ==# 'json' return ['string', 'number', 'boolean', 'array', 'object', 'null'] endif endfunction function! FileKeys(A, L, P) abort if &filetype ==# 'json' let a = split(system("jq 'keys' " . getreg("%") . " | sed 's/,*$//g' | sed '1d;$d' "), "\n") call map(a, {idx, val -> substitute(trim(val), '\"', '', 'g')}) elseif &filetype == 'yaml' let a = split(system("yq 'keys[]' " . getreg("%")), "\n") call map(a, {idx, val -> substitute(trim(val), '\"', '', 'g')}) endif return filter(a, 'v:val =~ ''\V\^''.a:A') endfunction augroup JqxAutoClose autocmd! autocmd WinLeave * call s:JqxClose() augroup END function s:JqxClose() abort for i in range(1, winnr('$')) if getbufvar(winbufnr(i), '&filetype') ==? 'jqx' close endif endfor endfunction let g:loaded_jqx = 1