diff --git a/lua/jsonfly/utils.lua b/lua/jsonfly/utils.lua index 66f30bf..5caa893 100644 --- a/lua/jsonfly/utils.lua +++ b/lua/jsonfly/utils.lua @@ -1,3 +1,7 @@ +---@class KeyDescription +---@field key string +---@field type "object"|"array"|"string" + local M = {} function M:truncate_overflow(value, max_length, overflow_marker) @@ -54,4 +58,61 @@ function M:replace_previous_keys(key, replacement) return key end +---@param text string +---@param char string +---@return string[] +function M:split_by_char(text, char) + local parts = {} + local current = "" + + for i = 1, #text do + local c = text:sub(i, i) + + if c == char then + parts[#parts + 1] = current + current = "" + else + current = current .. c + end + end + + parts[#parts + 1] = current + + return parts +end + +---@param text string +---@return KeyDescription[] +function M:extract_key_description(text) + local keys = {} + + local splitted = M:split_by_char(text, ".") + for index=1, #splitted do + local token = splitted[index] + + if string.sub(token, 1, 1) == "[" then + keys[#keys + 1] = { + key = tonumber(string.sub(token, 2, -2)), + type = "array", + } + else + keys[#keys + 1] = { + key = token, + type = "object", + } + end + end + + if #keys == 0 then + return { + { + key = text, + type = "string", + } + } + end + + return keys +end + return M diff --git a/lua/telescope/_extensions/jsonfly.lua b/lua/telescope/_extensions/jsonfly.lua index cd0c19f..37ed070 100644 --- a/lua/telescope/_extensions/jsonfly.lua +++ b/lua/telescope/_extensions/jsonfly.lua @@ -31,6 +31,8 @@ local conf = require"telescope.config".values local make_entry = require "telescope.make_entry" local entry_display = require "telescope.pickers.entry_display" +local action_state = require "telescope.actions.state" + ---@type Options local opts = { key_max_length = 50, @@ -52,6 +54,118 @@ local opts = { use_cache = 500, } +-- https://stackoverflow.com/a/24823383/9878135 +function table.slice(tbl, first, last, step) + local sliced = {} + + for i = first or 1, last or #tbl, step or 1 do + sliced[#sliced+1] = tbl[i] + end + + return sliced +end + +---@param entry Entry +---@param key string +---@param index number +local function check_key_equal(entry, key, index) + local splitted = utils:split_by_char(entry.key, ".") + + return splitted[index] == key +end + +---@param entries Entry[] +---@param keys KeyDescription[] +---@return [Entry, string[]] +local function find_remaining_keys(entries, keys) + local start_index = 1 + local end_index = #keys + + local existing_keys_depth = nil + + for kk=1, #keys do + local found_result = false + local key = keys[kk].key + + for ii=start_index, #entries do + if check_key_equal(entries[ii], key, kk) then + found_result = true + start_index = ii + break + end + end + + for ii=start_index + 1, #entries do + if not check_key_equal(entries[ii], key, kk) then + found_result = true + end_index = ii - 1 + break + end + end + + if not found_result then + existing_keys_depth = kk - 1 + break + end + end + + if existing_keys_depth == nil then + existing_keys_depth = #keys + end + + local last_entry = entries[end_index] + local remaining_keys = table.slice(keys, existing_keys_depth, #keys) + + return { last_entry, remaining_keys } +end + +---@param keys KeyDescription +---@param index number - Index of the key +local function write_keys(keys, index) + local lines = {} + + if index >= #keys then + return {} + end + + lines[#lines + 1] = "," + lines[#lines + 1] = "\"" .. keys[index].key .. "\": {" + lines[#lines + 1] = write_keys(keys, index + 1) + lines[#lines + 1] = "}" + + return lines +end + +---@param entries Entry[] +---@param keys KeyDescription[] +---@param buffer number +local function insert_new_key(entries, keys, buffer) + local _result = find_remaining_keys(entries, keys) + local last_entry = _result[1] + local remaining_keys = _result[2] + + local writes = write_keys(remaining_keys, 1) + + print(vim.inspect(last_entry)) + print(vim.inspect(remaining_keys)) + print(vim.inspect(writes)) + + -- for parts=#keys, 1, -1 do + -- ---@type Entries[] + -- local sub_keys = table.slice(keys, 1, parts) + -- local path = "" + -- + -- for ii=1, #sub_keys do + -- path = path .. sub_keys[ii].key + -- if ii < #sub_keys then + -- path = path .. "." + -- end + -- end + -- + -- print(path) + -- end +end + ---@param entries Entry[] ---@param buffer number local function show_picker(entries, buffer) @@ -76,6 +190,18 @@ local function show_picker(entries, buffer) pickers.new(opts, { prompt_title = opts.prompt_title, + attach_mappings = function(_, map) + map("i", "", function(prompt_bufnr) + local current_picker = action_state.get_current_picker(prompt_bufnr) + local input = current_picker:_get_prompt() + + local key_descriptor = utils:extract_key_description(input) + + insert_new_key(entries, key_descriptor, buffer) + end) + + return true + end, finder = finders.new_table { results = entries, ---@param entry Entry