From bfffd4710d9a68773993445f7617093c8551cf98 Mon Sep 17 00:00:00 2001 From: kawre Date: Tue, 3 Dec 2024 05:51:52 +0100 Subject: [PATCH 1/6] feat: `ibhagwan/fzf-lua` support --- lua/leetcode-ui/question.lua | 3 +- lua/leetcode/command/init.lua | 9 +- lua/leetcode/picker/init.lua | 73 ++++++++++ lua/leetcode/picker/language/fzf.lua | 21 +++ lua/leetcode/picker/language/init.lua | 45 +++++++ lua/leetcode/picker/language/telescope.lua | 74 +++++++++++ lua/leetcode/picker/question/fzf.lua | 22 +++ lua/leetcode/picker/question/init.lua | 90 +++++++++++++ lua/leetcode/picker/question/telescope.lua | 76 +++++++++++ lua/leetcode/picker/tabs/fzf.lua | 17 +++ lua/leetcode/picker/tabs/init.lua | 57 ++++++++ lua/leetcode/picker/tabs/telescope.lua | 63 +++++++++ lua/leetcode/pickers/language.lua | 143 -------------------- lua/leetcode/pickers/question-tabs.lua | 122 ----------------- lua/leetcode/pickers/question.lua | 148 --------------------- 15 files changed, 546 insertions(+), 417 deletions(-) create mode 100644 lua/leetcode/picker/init.lua create mode 100644 lua/leetcode/picker/language/fzf.lua create mode 100644 lua/leetcode/picker/language/init.lua create mode 100644 lua/leetcode/picker/language/telescope.lua create mode 100644 lua/leetcode/picker/question/fzf.lua create mode 100644 lua/leetcode/picker/question/init.lua create mode 100644 lua/leetcode/picker/question/telescope.lua create mode 100644 lua/leetcode/picker/tabs/fzf.lua create mode 100644 lua/leetcode/picker/tabs/init.lua create mode 100644 lua/leetcode/picker/tabs/telescope.lua delete mode 100644 lua/leetcode/pickers/language.lua delete mode 100644 lua/leetcode/pickers/question-tabs.lua delete mode 100644 lua/leetcode/pickers/question.lua diff --git a/lua/leetcode-ui/question.lua b/lua/leetcode-ui/question.lua index df35892..06668f4 100644 --- a/lua/leetcode-ui/question.lua +++ b/lua/leetcode-ui/question.lua @@ -228,7 +228,8 @@ function Question:mount() local msg = ("Snippet for `%s` not found. Select a different language"):format(self.lang) log.warn(msg) - require("leetcode.pickers.language").pick_lang(self, function(snippet) + local picker = require("leetcode.picker") + picker.language(self, function(snippet) self.lang = snippet.t.slug self:handle_mount() end) diff --git a/lua/leetcode/command/init.lua b/lua/leetcode/command/init.lua index 8cfaae0..ae41554 100644 --- a/lua/leetcode/command/init.lua +++ b/lua/leetcode/command/init.lua @@ -26,7 +26,8 @@ function cmd.problems(options) require("leetcode.utils").auth_guard() local p = require("leetcode.cache.problemlist").get() - require("leetcode.pickers.question").pick(p, options) + local picker = require("leetcode.picker") + picker.question(p, options) end ---@param cb? function @@ -219,14 +220,16 @@ function cmd.start_user_session() -- end function cmd.question_tabs() - require("leetcode.pickers.question-tabs").pick() + local picker = require("leetcode.picker") + picker.tabs() end function cmd.change_lang() local utils = require("leetcode.utils") local q = utils.curr_question() if q then - require("leetcode.pickers.language").pick(q) + local picker = require("leetcode.picker") + picker.language(q) end end diff --git a/lua/leetcode/picker/init.lua b/lua/leetcode/picker/init.lua new file mode 100644 index 0000000..4e41aa6 --- /dev/null +++ b/lua/leetcode/picker/init.lua @@ -0,0 +1,73 @@ +local log = require("leetcode.logger") + +---@class leet.Picker +local P = {} + +function P.hl_to_ansi(hl_group) + local color = vim.api.nvim_get_hl(0, { name = hl_group }) + if color and color.fg then + return string.format( + "\x1b[38;2;%d;%d;%dm", + bit.rshift(color.fg, 16), + bit.band(bit.rshift(color.fg, 8), 0xFF), + bit.band(color.fg, 0xFF) + ) + end + return "" +end + +function P.apply_hl(text, hl_group) + if not hl_group then + return text + end + return P.hl_to_ansi(hl_group) .. text .. "\x1b[0m" +end + +function P.normalize(items) + return vim.tbl_map(function(item) + return table.concat( + vim.tbl_map(function(col) + if type(col) == "table" then + return P.apply_hl(col[1], col[2]) + else + return col + end + end, item.entry), + " " + ) + end, items) +end + +function P.pick(path, ...) + local type + + if pcall(require, "fzf-lua") then + type = "fzf" + elseif pcall(require, "telescope") then + type = "telescope" + end + assert(type, "picker not found") + + return require(table.concat({ "leetcode.picker", path, type }, "."))(...) +end + +function P.language(...) + P.pick("language", ...) +end + +function P.question(...) + P.pick("question", ...) +end + +function P.tabs() + local utils = require("leetcode.utils") + local tabs = utils.question_tabs() + + if vim.tbl_isempty(tabs) then + return log.warn("No questions opened") + end + + P.pick("tabs", tabs) +end + +return P diff --git a/lua/leetcode/picker/language/fzf.lua b/lua/leetcode/picker/language/fzf.lua new file mode 100644 index 0000000..3e82adc --- /dev/null +++ b/lua/leetcode/picker/language/fzf.lua @@ -0,0 +1,21 @@ +local fzf = require("fzf-lua") +local t = require("leetcode.translator") +local language_picker = require("leetcode.picker.language") +local Picker = require("leetcode.picker") + +return function(question, cb) + local items = Picker.normalize(language_picker.items(question.q.code_snippets)) + + fzf.fzf_exec(items, { + prompt = t("Available Languages") .. "> ", + winopts = { + win_height = language_picker.height, + win_width = language_picker.width, + }, + actions = { + ["default"] = function(selected) + print("You selected: " .. selected[1]) + end, + }, + }) +end diff --git a/lua/leetcode/picker/language/init.lua b/lua/leetcode/picker/language/init.lua new file mode 100644 index 0000000..608ba45 --- /dev/null +++ b/lua/leetcode/picker/language/init.lua @@ -0,0 +1,45 @@ +local log = require("leetcode.logger") +local utils = require("leetcode.utils") + +local L = {} + +L.width = 100 +L.height = 20 + +---@param snippet lc.QuestionCodeSnippet +local function dislay_icon(snippet) + local hl = "leetcode_lang_" .. snippet.t.slug + vim.api.nvim_set_hl(0, hl, { fg = snippet.t.color }) + + return { snippet.t.icon, hl } +end + +---@param snippet lc.QuestionCodeSnippet +local function display_lang(snippet) + return { snippet.lang } +end + +function L.entry(item) + return { + dislay_icon(item), + display_lang(item), + } +end + +---@param item lc.QuestionCodeSnippet +function L.ordinal(item) + return ("%s %s"):format(item.t.lang, item.t.slug) +end + +function L.items(content) + return vim.tbl_map(function(item) + ---@type lc.language + item.t = utils.get_lang(item.lang_slug) + if not item.t then + return + end + return { entry = L.entry(item), value = item } + end, content) +end + +return L diff --git a/lua/leetcode/picker/language/telescope.lua b/lua/leetcode/picker/language/telescope.lua new file mode 100644 index 0000000..892bcf2 --- /dev/null +++ b/lua/leetcode/picker/language/telescope.lua @@ -0,0 +1,74 @@ +local log = require("leetcode.logger") +local t = require("leetcode.translator") + +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values +local config = require("leetcode.config") + +local entry_display = require("telescope.pickers.entry_display") +local actions = require("telescope.actions") +local action_state = require("telescope.actions.state") +local language_picker = require("leetcode.picker.language") + +local displayer = entry_display.create({ + separator = " ", + items = { + { width = 1 }, + { remaining = true }, + }, +}) + +local function entry_maker(item) + return { + value = item.value, + display = function() + return displayer(item.entry) + end, + ordinal = language_picker.ordinal(item.value), + } +end + +local opts = require("telescope.themes").get_dropdown() + +---@param question lc.ui.Question +return function(question, cb) + local items = language_picker.items(question.q.code_snippets) + + pickers + .new(opts, { + prompt_title = t("Available Languages"), + finder = finders.new_table({ + results = items, + entry_maker = entry_maker, + }), + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + if not selection then + return + end + + local snippet = selection.value + if question.lang == snippet.t.slug then + return log.warn( + ("%s: %s"):format(t("Language already set to"), snippet.t.lang) + ) + end + + config.lang = snippet.t.slug + actions.close(prompt_bufnr) + + if cb then + cb(snippet) + else + question:change_lang(snippet.t.slug) + end + end) + + return true + end, + }) + :find() +end diff --git a/lua/leetcode/picker/question/fzf.lua b/lua/leetcode/picker/question/fzf.lua new file mode 100644 index 0000000..e3b8865 --- /dev/null +++ b/lua/leetcode/picker/question/fzf.lua @@ -0,0 +1,22 @@ +local fzf = require("fzf-lua") +local t = require("leetcode.translator") +local question_picker = require("leetcode.picker.question") +local Picker = require("leetcode.picker") +local log = require("leetcode.logger") + +return function(questions, opts) + local items = Picker.normalize(question_picker.items(questions, opts)) + + fzf.fzf_exec(items, { + prompt = t("Select a Question") .. "> ", + winopts = { + win_height = question_picker.height, + win_width = question_picker.width, + }, + actions = { + ["default"] = function(selected) + print("You selected: " .. selected[1]) + end, + }, + }) +end diff --git a/lua/leetcode/picker/question/init.lua b/lua/leetcode/picker/question/init.lua new file mode 100644 index 0000000..47e1eba --- /dev/null +++ b/lua/leetcode/picker/question/init.lua @@ -0,0 +1,90 @@ +local config = require("leetcode.config") +local ui_utils = require("leetcode-ui.utils") +local utils = require("leetcode.utils") +local Picker = require("leetcode.picker") + +---@class leet.Picker.Question: leet.Picker +local P = {} + +P.width = 100 +P.height = 20 + +---@param items lc.cache.Question[] +---@param opts table +--- +---@return lc.cache.Question[] +function P.filter(items, opts) + if vim.tbl_isempty(opts or {}) then + return items + end + + ---@param q lc.cache.Question + return vim.tbl_filter(function(q) + local diff_flag = true + if opts.difficulty and not vim.tbl_contains(opts.difficulty, q.difficulty:lower()) then + diff_flag = false + end + + local status_flag = true + if opts.status and not vim.tbl_contains(opts.status, q.status) then + status_flag = false + end + + return diff_flag and status_flag + end, items) +end + +---@param content lc.cache.Question[] +---@param opts table +--- +---@return { entry: any, value: lc.cache.Question }[] +function P.items(content, opts) + local filtered = P.filter(content, opts) + return vim.tbl_map(function(item) + return { entry = P.entry(item), value = item } + end, filtered) +end + +---@param question lc.cache.Question +local function display_user_status(question) + if question.paid_only then + return config.auth.is_premium and config.icons.hl.unlock or config.icons.hl.lock + end + + return config.icons.hl.status[question.status] or { " " } +end + +---@param question lc.cache.Question +local function display_difficulty(question) + local hl = ui_utils.diff_to_hl(question.difficulty) + return { config.icons.square, hl } +end + +---@param question lc.cache.Question +local function display_question(question) + local index = { question.frontend_id .. ".", "leetcode_normal" } + local title = { utils.translate(question.title, question.title_cn) } + local ac_rate = { ("(%.1f%%)"):format(question.ac_rate), "leetcode_ref" } + + return unpack({ index, title, ac_rate }) +end + +function P.entry(item) + return { + display_user_status(item), + display_difficulty(item), + display_question(item), + } +end + +---@param item lc.cache.Question +function P.ordinal(item) + return ("%s. %s %s %s"):format( + tostring(item.frontend_id), + item.title, + item.title_cn, + item.title_slug + ) +end + +return P diff --git a/lua/leetcode/picker/question/telescope.lua b/lua/leetcode/picker/question/telescope.lua new file mode 100644 index 0000000..c123841 --- /dev/null +++ b/lua/leetcode/picker/question/telescope.lua @@ -0,0 +1,76 @@ +local log = require("leetcode.logger") +local t = require("leetcode.translator") +local question_picker = require("leetcode.picker.question") + +local Question = require("leetcode-ui.question") + +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values +local config = require("leetcode.config") + +local entry_display = require("telescope.pickers.entry_display") +local actions = require("telescope.actions") +local action_state = require("telescope.actions.state") + +local displayer = entry_display.create({ + separator = " ", + items = { + { width = 1 }, + { width = 1 }, + { width = 5 }, + { remaining = true }, + { remaining = true }, + }, +}) + +local function entry_maker(item) + return { + value = item.value, + display = function() + return displayer(item.entry) + end, + ordinal = question_picker.ordinal(item.value), + } +end + +local theme = require("telescope.themes").get_dropdown({ + layout_config = { + width = question_picker.width, + height = question_picker.height, + }, +}) + +---@param questions lc.cache.Question[] +return function(questions, opts) + local items = question_picker.items(questions, opts) + + pickers + .new(theme, { + prompt_title = t("Select a Question"), + finder = finders.new_table({ + results = items, + entry_maker = entry_maker, + }), + sorter = conf.generic_sorter(theme), + attach_mappings = function(prompt_bufnr) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + if not selection then + return + end + + local q = selection.value + if q.paid_only and not config.auth.is_premium then + return log.warn("Question is for premium users only") + end + + actions.close(prompt_bufnr) + Question(q):mount() + end) + + return true + end, + }) + :find() +end diff --git a/lua/leetcode/picker/tabs/fzf.lua b/lua/leetcode/picker/tabs/fzf.lua new file mode 100644 index 0000000..68125c0 --- /dev/null +++ b/lua/leetcode/picker/tabs/fzf.lua @@ -0,0 +1,17 @@ +local fzf = require("fzf-lua") +local t = require("leetcode.translator") +local tabs_picker = require("leetcode.picker.tabs") +local Picker = require("leetcode.picker") + +return function(tabs) + local items = Picker.normalize(tabs_picker.items(tabs)) + + fzf.fzf_exec(items, { + prompt = t("Select a Question") .. "> ", + actions = { + ["default"] = function(selected) + print("You selected: " .. selected[1]) + end, + }, + }) +end diff --git a/lua/leetcode/picker/tabs/init.lua b/lua/leetcode/picker/tabs/init.lua new file mode 100644 index 0000000..cc7b257 --- /dev/null +++ b/lua/leetcode/picker/tabs/init.lua @@ -0,0 +1,57 @@ +local log = require("leetcode.logger") +local utils = require("leetcode.utils") +local ui_utils = require("leetcode-ui.utils") +local t = require("leetcode.translator") + +local config = require("leetcode.config") +local icons = config.icons + +local T = {} + +---@param q lc.QuestionResponse +function T.ordinal(q) + return ("%s. %s %s"):format(q.frontend_id, q.title, q.translated_title) +end + +local function display_current(entry) + local tabp = vim.api.nvim_get_current_tabpage() + if tabp ~= entry.tabpage then + return unpack({ "", "" }) + end + + return { icons.caret.right, "leetcode_ref" } +end + +local function display_difficulty(q) + local lang = utils.get_lang(q.lang) + if not lang then + return {} + end + return { lang.icon, "leetcode_lang_" .. lang.slug } +end + +---@param question lc.QuestionResponse +local function display_question(question) + local hl = ui_utils.diff_to_hl(question.difficulty) + + local index = { question.frontend_id .. ".", hl } + local title = { utils.translate(question.title, question.translated_title) } + + return unpack({ index, title }) +end + +function T.entry(item) + return { + display_current(item), + display_difficulty(item.question), + display_question(item.question.q), + } +end + +function T.items(content) + return vim.tbl_map(function(item) + return { entry = T.entry(item), value = item } + end, content) +end + +return T diff --git a/lua/leetcode/picker/tabs/telescope.lua b/lua/leetcode/picker/tabs/telescope.lua new file mode 100644 index 0000000..20be8ca --- /dev/null +++ b/lua/leetcode/picker/tabs/telescope.lua @@ -0,0 +1,63 @@ +local log = require("leetcode.logger") +local t = require("leetcode.translator") + +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values + +local entry_display = require("telescope.pickers.entry_display") +local actions = require("telescope.actions") +local tabs_picker = require("leetcode.picker.tabs") +local action_state = require("telescope.actions.state") + +local displayer = entry_display.create({ + separator = " ", + items = { + { width = 1 }, + { width = 1 }, + { width = 5 }, + { remaining = true }, + }, +}) + +local function entry_maker(item) + return { + value = item.value, + display = function() + return displayer(item.entry) + end, + ordinal = tabs_picker.ordinal(item.value.question.q), + } +end + +local opts = require("telescope.themes").get_dropdown() + +return function(tabs) + local items = tabs_picker.items(tabs) + + pickers + .new(opts, { + prompt_title = t("Select a Question"), + finder = finders.new_table({ + results = items, + entry_maker = entry_maker, + }), + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + + if not selection then + return + end + local ok, err = pcall(vim.api.nvim_set_current_tabpage, selection.value.tabpage) + if not ok then + log.error(err) + end + end) + return true + end, + }) + :find() +end diff --git a/lua/leetcode/pickers/language.lua b/lua/leetcode/pickers/language.lua deleted file mode 100644 index 7e9f346..0000000 --- a/lua/leetcode/pickers/language.lua +++ /dev/null @@ -1,143 +0,0 @@ -local log = require("leetcode.logger") -local Question = require("leetcode-ui.question") -local utils = require("leetcode.utils") -local t = require("leetcode.translator") - -local pickers = require("telescope.pickers") -local finders = require("telescope.finders") -local conf = require("telescope.config").values -local config = require("leetcode.config") - -local entry_display = require("telescope.pickers.entry_display") -local actions = require("telescope.actions") -local action_state = require("telescope.actions.state") - -local M = {} - ----@param snippet lc.QuestionCodeSnippet ---- ----@return string -local function lang_formatter(snippet) - return string.format("%s %s", snippet.t.lang, snippet.t.slug) -end - ----@param snippet lc.QuestionCodeSnippet -local function dislay_icon(snippet) - local hl = "leetcode_lang_" .. snippet.t.slug - vim.api.nvim_set_hl(0, hl, { fg = snippet.t.color }) - - return { snippet.t.icon, hl } -end - ----@param snippet lc.QuestionCodeSnippet -local function display_lang(snippet) - -- - return { snippet.lang } -end - -local displayer = entry_display.create({ - separator = " ", - items = { - { width = 1 }, - { remaining = true }, - }, -}) - -local function make_display(entry) - ---@type lc.QuestionCodeSnippet - local snippet = entry.value - - return displayer({ - dislay_icon(snippet), - display_lang(snippet), - }) -end - ----@param entry lc.QuestionCodeSnippet -local function entry_maker(entry) - ---@type lc.language - entry.t = utils.get_lang(entry.lang_slug) - if not entry.t then - return - end - - return { - value = entry, - display = make_display, - ordinal = lang_formatter(entry), - } -end - -local opts = require("telescope.themes").get_dropdown() - ----@param question lc.ui.Question -M.pick_lang = function(question, callback) - pickers - .new(opts, { - prompt_title = t("Available Languages"), - finder = finders.new_table({ - results = question.q.code_snippets, - entry_maker = entry_maker, - }), - sorter = conf.generic_sorter(opts), - attach_mappings = function(prompt_bufnr, map) - actions.select_default:replace(function() - local selection = action_state.get_selected_entry() - if not selection then - return - end - - local snippet = selection.value - if question.lang == snippet.t.slug then - return log.warn( - ("%s: %s"):format(t("Language already set to"), snippet.t.lang) - ) - end - - config.lang = snippet.t.slug - actions.close(prompt_bufnr) - callback(snippet) - end) - - return true - end, - }) - :find() -end - ----@param question lc.ui.Question -M.pick = function(question) - pickers - .new(opts, { - prompt_title = t("Available Languages"), - finder = finders.new_table({ - results = question.q.code_snippets, - entry_maker = entry_maker, - }), - sorter = conf.generic_sorter(opts), - attach_mappings = function(prompt_bufnr, map) - actions.select_default:replace(function() - local selection = action_state.get_selected_entry() - if not selection then - return - end - - local snippet = selection.value - if question.lang == snippet.t.slug then - return log.warn( - ("%s: %s"):format(t("Language already set to"), snippet.t.lang) - ) - end - - config.lang = snippet.t.slug - actions.close(prompt_bufnr) - question:change_lang(snippet.t.slug) - end) - - return true - end, - }) - :find() -end - -return M diff --git a/lua/leetcode/pickers/question-tabs.lua b/lua/leetcode/pickers/question-tabs.lua deleted file mode 100644 index e22426d..0000000 --- a/lua/leetcode/pickers/question-tabs.lua +++ /dev/null @@ -1,122 +0,0 @@ -local log = require("leetcode.logger") -local utils = require("leetcode.utils") -local ui_utils = require("leetcode-ui.utils") -local t = require("leetcode.translator") - -local pickers = require("telescope.pickers") -local finders = require("telescope.finders") -local conf = require("telescope.config").values -local config = require("leetcode.config") -local icons = config.icons - -local entry_display = require("telescope.pickers.entry_display") -local actions = require("telescope.actions") -local action_state = require("telescope.actions.state") - ----@param q lc.QuestionResponse ---- ----@return string -local function question_formatter(q) - return string.format("%s. %s %s", q.frontend_id, q.title, q.translated_title) -end - -local function display_current(entry) - local tabp = vim.api.nvim_get_current_tabpage() - if tabp ~= entry.tabpage then - return unpack({ "", "" }) - end - - return { icons.caret.right, "leetcode_ref" } -end - -local function display_difficulty(q) - local lang = utils.get_lang(q.lang) - if not lang then - return {} - end - return { lang.icon, "leetcode_lang_" .. lang.slug } -end - ----@param question lc.QuestionResponse -local function display_question(question) - local hl = ui_utils.diff_to_hl(question.difficulty) - - local index = { question.frontend_id .. ".", hl } - local title = { utils.translate(question.title, question.translated_title) } - - return unpack({ index, title }) -end - -local displayer = entry_display.create({ - separator = " ", - items = { - { width = 1 }, - { width = 1 }, - { width = 5 }, - { remaining = true }, - }, -}) - -local function make_display(entry) - ---@type lc.cache.Question - local q = entry.value.question.q - - return displayer({ - display_current(entry.value), - display_difficulty(entry.value.question), - display_question(q), - }) -end - -local function entry_maker(entry) - return { - value = entry, - display = make_display, - ordinal = question_formatter(entry.question.q), - } -end - -local opts = require("telescope.themes").get_dropdown() - -return { - pick = function() - local tabs = utils.question_tabs() - - if vim.tbl_isempty(tabs) then - return log.warn("No questions opened") - end - - -- table.sort(tabs, function(q1, q2) - -- local fid1, fid2 = - -- tonumber(q1.question.q.frontend_id), tonumber(q2.question.q.frontend_id) - -- return (fid1 and fid2) and fid1 < fid2 or fid1 ~= nil - -- end) - - pickers - .new(opts, { - prompt_title = t("Select a Question"), - finder = finders.new_table({ - results = tabs, - entry_maker = entry_maker, - }), - sorter = conf.generic_sorter(opts), - attach_mappings = function(prompt_bufnr) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - - if not selection then - return - end - local ok, err = - pcall(vim.api.nvim_set_current_tabpage, selection.value.tabpage) - if not ok then - log.error(err) - end - end) - return true - end, - }) - :find() - end, -} diff --git a/lua/leetcode/pickers/question.lua b/lua/leetcode/pickers/question.lua deleted file mode 100644 index d8fa117..0000000 --- a/lua/leetcode/pickers/question.lua +++ /dev/null @@ -1,148 +0,0 @@ -local log = require("leetcode.logger") -local t = require("leetcode.translator") -local utils = require("leetcode.utils") -local ui_utils = require("leetcode-ui.utils") - -local Question = require("leetcode-ui.question") - -local pickers = require("telescope.pickers") -local finders = require("telescope.finders") -local conf = require("telescope.config").values -local config = require("leetcode.config") - -local entry_display = require("telescope.pickers.entry_display") -local actions = require("telescope.actions") -local action_state = require("telescope.actions.state") - ----@param question lc.cache.Question ---- ----@return string -local function question_formatter(question) - return ("%s. %s %s %s"):format( - tostring(question.frontend_id), - question.title, - question.title_cn, - question.title_slug - ) -end - ----@param question lc.cache.Question -local function display_difficulty(question) - local hl = ui_utils.diff_to_hl(question.difficulty) - return { config.icons.square, hl } -end - ----@param question lc.cache.Question -local function display_user_status(question) - if question.paid_only then - return config.auth.is_premium and config.icons.hl.unlock or config.icons.hl.lock - end - - return config.icons.hl.status[question.status] or { "" } -end - ----@param question lc.cache.Question -local function display_question(question) - local ac_rate = { ("%.1f%%"):format(question.ac_rate), "leetcode_ref" } - local index = { question.frontend_id .. ".", "leetcode_normal" } - - local title = { utils.translate(question.title, question.title_cn) } - - return unpack({ index, title, ac_rate }) -end - -local displayer = entry_display.create({ - separator = " ", - items = { - { width = 1 }, - { width = 1 }, - { width = 5 }, - { width = 78 }, - { width = 5 }, - }, -}) - -local function make_display(entry) - ---@type lc.cache.Question - local q = entry.value - - return displayer({ - display_user_status(q), - display_difficulty(q), - display_question(q), - }) -end - -local function entry_maker(entry) - return { - value = entry, - display = make_display, - ordinal = question_formatter(entry), - } -end - -local theme = require("telescope.themes").get_dropdown({ - layout_config = { - width = 100, - height = 20, - }, -}) - ----@param questions lc.cache.Question[] ----@param opts table ---- ----@return lc.cache.Question[] -local function filter_questions(questions, opts) - if vim.tbl_isempty(opts or {}) then - return questions - end - - ---@param q lc.cache.Question - return vim.tbl_filter(function(q) - local diff_flag = true - if opts.difficulty and not vim.tbl_contains(opts.difficulty, q.difficulty:lower()) then - diff_flag = false - end - - local status_flag = true - if opts.status and not vim.tbl_contains(opts.status, q.status) then - status_flag = false - end - - return diff_flag and status_flag - end, questions) -end - -return { - ---@param questions lc.cache.Question[] - pick = function(questions, opts) - pickers - .new(theme, { - prompt_title = t("Select a Question"), - finder = finders.new_table({ - results = filter_questions(questions, opts), - entry_maker = entry_maker, - }), - sorter = conf.generic_sorter(theme), - attach_mappings = function(prompt_bufnr, map) - actions.select_default:replace(function() - local selection = action_state.get_selected_entry() - if not selection then - return - end - - local q = selection.value - if q.paid_only and not config.auth.is_premium then - return log.warn("Question is for premium users only") - end - - actions.close(prompt_bufnr) - Question(q):mount() - end) - - return true - end, - }) - :find() - end, -} From e39d4b87a8e90ed67eb5861c1b0064a059fc46ea Mon Sep 17 00:00:00 2001 From: kawre Date: Tue, 3 Dec 2024 07:28:52 +0100 Subject: [PATCH 2/6] feat(picker): close buffer --- lua/leetcode-ui/question.lua | 4 ++-- lua/leetcode/picker/language/fzf.lua | 18 +++++++++++++-- lua/leetcode/picker/language/init.lua | 19 ++++++++++++++++ lua/leetcode/picker/language/telescope.lua | 26 +++++++++------------- lua/leetcode/picker/question/fzf.lua | 19 ++++++++++++++-- lua/leetcode/picker/question/init.lua | 14 +++++++++++- lua/leetcode/picker/question/telescope.lua | 13 ++++------- lua/leetcode/picker/tabs/fzf.lua | 20 +++++++++++++++-- lua/leetcode/picker/tabs/init.lua | 14 +++++++++++- lua/leetcode/picker/tabs/telescope.lua | 17 ++++++++------ 10 files changed, 122 insertions(+), 42 deletions(-) diff --git a/lua/leetcode-ui/question.lua b/lua/leetcode-ui/question.lua index 06668f4..e820474 100644 --- a/lua/leetcode-ui/question.lua +++ b/lua/leetcode-ui/question.lua @@ -229,8 +229,8 @@ function Question:mount() log.warn(msg) local picker = require("leetcode.picker") - picker.language(self, function(snippet) - self.lang = snippet.t.slug + picker.language(self, function(slug) + self.lang = slug self:handle_mount() end) end diff --git a/lua/leetcode/picker/language/fzf.lua b/lua/leetcode/picker/language/fzf.lua index 3e82adc..6eee425 100644 --- a/lua/leetcode/picker/language/fzf.lua +++ b/lua/leetcode/picker/language/fzf.lua @@ -3,8 +3,16 @@ local t = require("leetcode.translator") local language_picker = require("leetcode.picker.language") local Picker = require("leetcode.picker") +local deli = "\t" + return function(question, cb) - local items = Picker.normalize(language_picker.items(question.q.code_snippets)) + local items = language_picker.items(question.q.code_snippets) + + for i, item in ipairs(items) do + local md = vim.inspect({ slug = item.value.t.slug, lang = item.value.t.lang }) + :gsub("\n", "") + items[i] = table.concat({ Picker.normalize({ item })[1], md }, deli) + end fzf.fzf_exec(items, { prompt = t("Available Languages") .. "> ", @@ -12,9 +20,15 @@ return function(question, cb) win_height = language_picker.height, win_width = language_picker.width, }, + fzf_opts = { + ["--delimiter"] = deli, + ["--nth"] = "1", + ["--with-nth"] = "1", + }, actions = { ["default"] = function(selected) - print("You selected: " .. selected[1]) + local md = string.match(selected[1], "([^\t]+)$") + language_picker.select(load("return " .. md)(), question, cb) end, }, }) diff --git a/lua/leetcode/picker/language/init.lua b/lua/leetcode/picker/language/init.lua index 608ba45..4fcc2b8 100644 --- a/lua/leetcode/picker/language/init.lua +++ b/lua/leetcode/picker/language/init.lua @@ -1,4 +1,6 @@ local log = require("leetcode.logger") +local t = require("leetcode.translator") +local config = require("leetcode.config") local utils = require("leetcode.utils") local L = {} @@ -42,4 +44,21 @@ function L.items(content) end, content) end +function L.select(selection, question, cb, close) + if question.lang == selection.slug then + return log.warn(("%s: %s"):format(t("Language already set to"), selection.lang)) + end + + config.lang = selection.slug + if close then + close() + end + + if cb then + cb(selection.slug) + else + question:change_lang(selection.slug) + end +end + return L diff --git a/lua/leetcode/picker/language/telescope.lua b/lua/leetcode/picker/language/telescope.lua index 892bcf2..3d55319 100644 --- a/lua/leetcode/picker/language/telescope.lua +++ b/lua/leetcode/picker/language/telescope.lua @@ -29,7 +29,12 @@ local function entry_maker(item) } end -local opts = require("telescope.themes").get_dropdown() +local opts = require("telescope.themes").get_dropdown({ + layout_config = { + width = language_picker.width, + height = language_picker.height, + }, +}) ---@param question lc.ui.Question return function(question, cb) @@ -47,24 +52,13 @@ return function(question, cb) actions.select_default:replace(function() local selection = action_state.get_selected_entry() if not selection then + log.warn("No selection") return end - local snippet = selection.value - if question.lang == snippet.t.slug then - return log.warn( - ("%s: %s"):format(t("Language already set to"), snippet.t.lang) - ) - end - - config.lang = snippet.t.slug - actions.close(prompt_bufnr) - - if cb then - cb(snippet) - else - question:change_lang(snippet.t.slug) - end + language_picker.select(selection.value, question, cb, function() + actions.close(prompt_bufnr) + end) end) return true diff --git a/lua/leetcode/picker/question/fzf.lua b/lua/leetcode/picker/question/fzf.lua index e3b8865..5f13c55 100644 --- a/lua/leetcode/picker/question/fzf.lua +++ b/lua/leetcode/picker/question/fzf.lua @@ -1,11 +1,20 @@ local fzf = require("fzf-lua") +local problemlist = require("leetcode.cache.problemlist") local t = require("leetcode.translator") local question_picker = require("leetcode.picker.question") local Picker = require("leetcode.picker") local log = require("leetcode.logger") +local deli = " " + return function(questions, opts) - local items = Picker.normalize(question_picker.items(questions, opts)) + local items = question_picker.items(questions, opts) + + for i, item in ipairs(items) do + items[i] = Picker.normalize({ item })[1] + .. deli + .. Picker.apply_hl(item.value.title_slug, "Comment") + end fzf.fzf_exec(items, { prompt = t("Select a Question") .. "> ", @@ -13,9 +22,15 @@ return function(questions, opts) win_height = question_picker.height, win_width = question_picker.width, }, + fzf_opts = { + ["--delimiter"] = deli, + ["--nth"] = "3..-3", + }, actions = { ["default"] = function(selected) - print("You selected: " .. selected[1]) + local slug = string.match(selected[1], "([^ ]+)$") + local question = problemlist.get_by_title_slug(slug) + question_picker.select(question) end, }, }) diff --git a/lua/leetcode/picker/question/init.lua b/lua/leetcode/picker/question/init.lua index 47e1eba..77866f2 100644 --- a/lua/leetcode/picker/question/init.lua +++ b/lua/leetcode/picker/question/init.lua @@ -1,6 +1,8 @@ local config = require("leetcode.config") +local log = require("leetcode.logger") local ui_utils = require("leetcode-ui.utils") local utils = require("leetcode.utils") +local Question = require("leetcode-ui.question") local Picker = require("leetcode.picker") ---@class leet.Picker.Question: leet.Picker @@ -51,7 +53,7 @@ local function display_user_status(question) return config.auth.is_premium and config.icons.hl.unlock or config.icons.hl.lock end - return config.icons.hl.status[question.status] or { " " } + return config.icons.hl.status[question.status] or { " " } end ---@param question lc.cache.Question @@ -87,4 +89,14 @@ function P.ordinal(item) ) end +function P.select(selection, close) + if selection.paid_only and not config.auth.is_premium then + return log.warn("Question is for premium users only") + end + if close then + close() + end + Question(selection):mount() +end + return P diff --git a/lua/leetcode/picker/question/telescope.lua b/lua/leetcode/picker/question/telescope.lua index c123841..b30137d 100644 --- a/lua/leetcode/picker/question/telescope.lua +++ b/lua/leetcode/picker/question/telescope.lua @@ -57,18 +57,13 @@ return function(questions, opts) actions.select_default:replace(function() local selection = action_state.get_selected_entry() if not selection then + log.warn("No selection") return end - - local q = selection.value - if q.paid_only and not config.auth.is_premium then - return log.warn("Question is for premium users only") - end - - actions.close(prompt_bufnr) - Question(q):mount() + question_picker.select(selection.value, function() + actions.close(prompt_bufnr) + end) end) - return true end, }) diff --git a/lua/leetcode/picker/tabs/fzf.lua b/lua/leetcode/picker/tabs/fzf.lua index 68125c0..14879e7 100644 --- a/lua/leetcode/picker/tabs/fzf.lua +++ b/lua/leetcode/picker/tabs/fzf.lua @@ -3,14 +3,30 @@ local t = require("leetcode.translator") local tabs_picker = require("leetcode.picker.tabs") local Picker = require("leetcode.picker") +local deli = "\t" + return function(tabs) - local items = Picker.normalize(tabs_picker.items(tabs)) + local items = tabs_picker.items(tabs) + + for i, item in ipairs(items) do + items[i] = Picker.normalize({ item })[1] .. deli .. item.value.tabpage + end fzf.fzf_exec(items, { prompt = t("Select a Question") .. "> ", + winopts = { + height = tabs_picker.height, + width = tabs_picker.width, + }, + fzf_opts = { + ["--delimiter"] = deli, + ["--nth"] = "1", + ["--with-nth"] = "1", + }, actions = { ["default"] = function(selected) - print("You selected: " .. selected[1]) + local tabpage = string.match(selected[1], "([^\t]+)$") + tabs_picker.select({ tabpage = tonumber(tabpage) }) end, }, }) diff --git a/lua/leetcode/picker/tabs/init.lua b/lua/leetcode/picker/tabs/init.lua index cc7b257..bff4f2c 100644 --- a/lua/leetcode/picker/tabs/init.lua +++ b/lua/leetcode/picker/tabs/init.lua @@ -8,6 +8,9 @@ local icons = config.icons local T = {} +T.width = 100 +T.height = 20 + ---@param q lc.QuestionResponse function T.ordinal(q) return ("%s. %s %s"):format(q.frontend_id, q.title, q.translated_title) @@ -16,7 +19,7 @@ end local function display_current(entry) local tabp = vim.api.nvim_get_current_tabpage() if tabp ~= entry.tabpage then - return unpack({ "", "" }) + return " " end return { icons.caret.right, "leetcode_ref" } @@ -54,4 +57,13 @@ function T.items(content) end, content) end +function T.select(selection, close) + local ok, err = pcall(vim.api.nvim_set_current_tabpage, selection.tabpage) + if not ok then + log.error(err) + elseif close then + close() + end +end + return T diff --git a/lua/leetcode/picker/tabs/telescope.lua b/lua/leetcode/picker/tabs/telescope.lua index 20be8ca..63d3253 100644 --- a/lua/leetcode/picker/tabs/telescope.lua +++ b/lua/leetcode/picker/tabs/telescope.lua @@ -30,7 +30,12 @@ local function entry_maker(item) } end -local opts = require("telescope.themes").get_dropdown() +local opts = require("telescope.themes").get_dropdown({ + layout_config = { + width = tabs_picker.width, + height = tabs_picker.height, + }, +}) return function(tabs) local items = tabs_picker.items(tabs) @@ -45,16 +50,14 @@ return function(tabs) sorter = conf.generic_sorter(opts), attach_mappings = function(prompt_bufnr) actions.select_default:replace(function() - actions.close(prompt_bufnr) local selection = action_state.get_selected_entry() - if not selection then + log.warn("No selection") return end - local ok, err = pcall(vim.api.nvim_set_current_tabpage, selection.value.tabpage) - if not ok then - log.error(err) - end + tabs_picker.select(selection.value, function() + actions.close(prompt_bufnr) + end) end) return true end, From eca23596574a17beb9ff21cc49bada515595dbd5 Mon Sep 17 00:00:00 2001 From: kawre Date: Tue, 3 Dec 2024 07:51:33 +0100 Subject: [PATCH 3/6] fix: telescope lang picker --- lua/leetcode/picker/language/telescope.lua | 3 +-- lua/leetcode/picker/tabs/init.lua | 4 +--- lua/leetcode/picker/tabs/telescope.lua | 5 ++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lua/leetcode/picker/language/telescope.lua b/lua/leetcode/picker/language/telescope.lua index 3d55319..c91061b 100644 --- a/lua/leetcode/picker/language/telescope.lua +++ b/lua/leetcode/picker/language/telescope.lua @@ -55,8 +55,7 @@ return function(question, cb) log.warn("No selection") return end - - language_picker.select(selection.value, question, cb, function() + language_picker.select(selection.value.t, question, cb, function() actions.close(prompt_bufnr) end) end) diff --git a/lua/leetcode/picker/tabs/init.lua b/lua/leetcode/picker/tabs/init.lua index bff4f2c..aee9204 100644 --- a/lua/leetcode/picker/tabs/init.lua +++ b/lua/leetcode/picker/tabs/init.lua @@ -57,12 +57,10 @@ function T.items(content) end, content) end -function T.select(selection, close) +function T.select(selection) local ok, err = pcall(vim.api.nvim_set_current_tabpage, selection.tabpage) if not ok then log.error(err) - elseif close then - close() end end diff --git a/lua/leetcode/picker/tabs/telescope.lua b/lua/leetcode/picker/tabs/telescope.lua index 63d3253..93998e0 100644 --- a/lua/leetcode/picker/tabs/telescope.lua +++ b/lua/leetcode/picker/tabs/telescope.lua @@ -55,9 +55,8 @@ return function(tabs) log.warn("No selection") return end - tabs_picker.select(selection.value, function() - actions.close(prompt_bufnr) - end) + actions.close(prompt_bufnr) + tabs_picker.select(selection.value) end) return true end, From 76e018f0ef20abd1d3582741181935e36408f309 Mon Sep 17 00:00:00 2001 From: kawre Date: Wed, 4 Dec 2024 01:38:33 +0100 Subject: [PATCH 4/6] feat: adjust picker sizes --- lua/leetcode/picker/init.lua | 4 ++++ lua/leetcode/picker/language/fzf.lua | 2 +- lua/leetcode/picker/language/init.lua | 4 ++-- lua/leetcode/picker/question/fzf.lua | 5 ++--- lua/leetcode/picker/tabs/fzf.lua | 2 +- lua/leetcode/picker/tabs/init.lua | 4 ++-- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lua/leetcode/picker/init.lua b/lua/leetcode/picker/init.lua index 4e41aa6..550a9d6 100644 --- a/lua/leetcode/picker/init.lua +++ b/lua/leetcode/picker/init.lua @@ -70,4 +70,8 @@ function P.tabs() P.pick("tabs", tabs) end +function P.hidden_field(text, deli) + return text:match(("([^%s]+)$"):format(deli)) +end + return P diff --git a/lua/leetcode/picker/language/fzf.lua b/lua/leetcode/picker/language/fzf.lua index 6eee425..013b28f 100644 --- a/lua/leetcode/picker/language/fzf.lua +++ b/lua/leetcode/picker/language/fzf.lua @@ -27,7 +27,7 @@ return function(question, cb) }, actions = { ["default"] = function(selected) - local md = string.match(selected[1], "([^\t]+)$") + local md = Picker.hidden_field(selected[1], deli) language_picker.select(load("return " .. md)(), question, cb) end, }, diff --git a/lua/leetcode/picker/language/init.lua b/lua/leetcode/picker/language/init.lua index 4fcc2b8..d7b7615 100644 --- a/lua/leetcode/picker/language/init.lua +++ b/lua/leetcode/picker/language/init.lua @@ -5,8 +5,8 @@ local utils = require("leetcode.utils") local L = {} -L.width = 100 -L.height = 20 +L.width = 80 +L.height = 15 ---@param snippet lc.QuestionCodeSnippet local function dislay_icon(snippet) diff --git a/lua/leetcode/picker/question/fzf.lua b/lua/leetcode/picker/question/fzf.lua index 5f13c55..1ffdaec 100644 --- a/lua/leetcode/picker/question/fzf.lua +++ b/lua/leetcode/picker/question/fzf.lua @@ -3,7 +3,6 @@ local problemlist = require("leetcode.cache.problemlist") local t = require("leetcode.translator") local question_picker = require("leetcode.picker.question") local Picker = require("leetcode.picker") -local log = require("leetcode.logger") local deli = " " @@ -13,7 +12,7 @@ return function(questions, opts) for i, item in ipairs(items) do items[i] = Picker.normalize({ item })[1] .. deli - .. Picker.apply_hl(item.value.title_slug, "Comment") + .. Picker.apply_hl(item.value.title_slug, "leetcode_alt") end fzf.fzf_exec(items, { @@ -28,7 +27,7 @@ return function(questions, opts) }, actions = { ["default"] = function(selected) - local slug = string.match(selected[1], "([^ ]+)$") + local slug = Picker.hidden_field(selected[1], deli) local question = problemlist.get_by_title_slug(slug) question_picker.select(question) end, diff --git a/lua/leetcode/picker/tabs/fzf.lua b/lua/leetcode/picker/tabs/fzf.lua index 14879e7..57e5dbd 100644 --- a/lua/leetcode/picker/tabs/fzf.lua +++ b/lua/leetcode/picker/tabs/fzf.lua @@ -25,7 +25,7 @@ return function(tabs) }, actions = { ["default"] = function(selected) - local tabpage = string.match(selected[1], "([^\t]+)$") + local tabpage = Picker.hidden_field(selected[1], deli) tabs_picker.select({ tabpage = tonumber(tabpage) }) end, }, diff --git a/lua/leetcode/picker/tabs/init.lua b/lua/leetcode/picker/tabs/init.lua index aee9204..8ea7049 100644 --- a/lua/leetcode/picker/tabs/init.lua +++ b/lua/leetcode/picker/tabs/init.lua @@ -8,8 +8,8 @@ local icons = config.icons local T = {} -T.width = 100 -T.height = 20 +T.width = 80 +T.height = 15 ---@param q lc.QuestionResponse function T.ordinal(q) From 9362606cc8224e5b17cc21429620c35e8e9d56c3 Mon Sep 17 00:00:00 2001 From: kawre Date: Thu, 12 Dec 2024 20:00:50 +0100 Subject: [PATCH 5/6] docs: `picker.provider` config --- README.md | 25 ++++++++++++++++++------- lua/leetcode/config/template.lua | 5 +++++ lua/leetcode/picker/init.lua | 19 +++++++++---------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ece23e2..938ac17 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ https://github.com/kawre/leetcode.nvim/assets/69250723/aee6584c-e099-4409-b114-1 - [Neovim] >= 0.9.0 -- [telescope.nvim] +- [telescope.nvim] or [fzf-lua] - [nui.nvim] @@ -43,15 +43,13 @@ https://github.com/kawre/leetcode.nvim/assets/69250723/aee6584c-e099-4409-b114-1 ```lua { "kawre/leetcode.nvim", - build = ":TSUpdate html", + build = ":TSUpdate html", -- if you have `nvim-treesitter` installed dependencies = { "nvim-telescope/telescope.nvim", - "nvim-lua/plenary.nvim", -- required by telescope - "MunifTanjim/nui.nvim", + -- "ibhagwan/fzf-lua", - -- optional - "nvim-treesitter/nvim-treesitter", - "nvim-tree/nvim-web-devicons", + "nvim-lua/plenary.nvim", + "MunifTanjim/nui.nvim", }, opts = { -- configuration goes here @@ -128,6 +126,9 @@ To see full configuration types see [template.lua](./lua/leetcode/config/templat show_stats = true, ---@type boolean }, + ---@type lc.picker + picker = { provider = "telescope" }, + hooks = { ---@type fun()[] ["enter"] = {}, @@ -275,6 +276,15 @@ injector = { ---@type table } ``` +### picker + +Supported picker providers are `telescope` and `fzf-lua` + +```lua +---@type lc.picker +picker = { provider = "telescope" }, +``` + ### hooks List of functions that get executed on specified event @@ -493,4 +503,5 @@ You can then exit [leetcode.nvim] using `:Leet exit` command [nvim-treesitter]: https://github.com/nvim-treesitter/nvim-treesitter [nvim-web-devicons]: https://github.com/nvim-tree/nvim-web-devicons [telescope.nvim]: https://github.com/nvim-telescope/telescope.nvim +[fzf-lua]: https://github.com/ibhagwan/fzf-lua [tree-sitter-html]: https://github.com/tree-sitter/tree-sitter-html diff --git a/lua/leetcode/config/template.lua b/lua/leetcode/config/template.lua index 27590e0..29d8b8a 100644 --- a/lua/leetcode/config/template.lua +++ b/lua/leetcode/config/template.lua @@ -38,6 +38,8 @@ ---@alias lc.storage table<"cache"|"home", string> +---@alias lc.picker { provider: "fzf-lua" | "telescope" } + ---@class lc.UserConfig local M = { ---@type string @@ -101,6 +103,9 @@ local M = { show_stats = true, ---@type boolean }, + ---@type lc.picker + picker = { provider = "telescope" }, + hooks = { ---@type fun()[] ["enter"] = {}, diff --git a/lua/leetcode/picker/init.lua b/lua/leetcode/picker/init.lua index 550a9d6..719df4b 100644 --- a/lua/leetcode/picker/init.lua +++ b/lua/leetcode/picker/init.lua @@ -1,4 +1,11 @@ local log = require("leetcode.logger") +local config = require("leetcode.config") + +---@type string +local provider = config.user.picker.provider +assert(pcall(require, provider), ("specified picker provider not found: `%s`"):format(provider)) +provider = provider == "fzf-lua" and "fzf" or provider +---@cast provider "fzf" | "telescope" ---@class leet.Picker local P = {} @@ -39,16 +46,8 @@ function P.normalize(items) end function P.pick(path, ...) - local type - - if pcall(require, "fzf-lua") then - type = "fzf" - elseif pcall(require, "telescope") then - type = "telescope" - end - assert(type, "picker not found") - - return require(table.concat({ "leetcode.picker", path, type }, "."))(...) + local rpath = table.concat({ "leetcode.picker", path, provider }, ".") + return require(rpath)(...) end function P.language(...) From e1f118ef05518564a9aee13f2972cdfbc97955ef Mon Sep 17 00:00:00 2001 From: kawre Date: Thu, 12 Dec 2024 20:18:10 +0100 Subject: [PATCH 6/6] feat: picker provider resolver --- README.md | 12 ++++++++---- lua/leetcode/config/template.lua | 4 ++-- lua/leetcode/picker/init.lua | 29 +++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 938ac17..57ed6f9 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ https://github.com/kawre/leetcode.nvim/assets/69250723/aee6584c-e099-4409-b114-1 - [telescope.nvim] or [fzf-lua] +- [plenary.nvim] + - [nui.nvim] - [tree-sitter-html] _**(optional, but highly recommended)**_ @@ -47,7 +49,6 @@ https://github.com/kawre/leetcode.nvim/assets/69250723/aee6584c-e099-4409-b114-1 dependencies = { "nvim-telescope/telescope.nvim", -- "ibhagwan/fzf-lua", - "nvim-lua/plenary.nvim", "MunifTanjim/nui.nvim", }, @@ -127,7 +128,7 @@ To see full configuration types see [template.lua](./lua/leetcode/config/templat }, ---@type lc.picker - picker = { provider = "telescope" }, + picker = { provider = nil }, hooks = { ---@type fun()[] @@ -278,11 +279,13 @@ injector = { ---@type table ### picker -Supported picker providers are `telescope` and `fzf-lua` +Supported picker providers are `telescope` and `fzf-lua`. +When provider is `nil`, [leetcode.nvim] will first try to use `fzf-lua`, +if not found it will fallback to `telescope`. ```lua ---@type lc.picker -picker = { provider = "telescope" }, +picker = { provider = nil }, ``` ### hooks @@ -505,3 +508,4 @@ You can then exit [leetcode.nvim] using `:Leet exit` command [telescope.nvim]: https://github.com/nvim-telescope/telescope.nvim [fzf-lua]: https://github.com/ibhagwan/fzf-lua [tree-sitter-html]: https://github.com/tree-sitter/tree-sitter-html +[plenary.nvim]: https://github.com/nvim-lua/plenary.nvim diff --git a/lua/leetcode/config/template.lua b/lua/leetcode/config/template.lua index 29d8b8a..40c5779 100644 --- a/lua/leetcode/config/template.lua +++ b/lua/leetcode/config/template.lua @@ -38,7 +38,7 @@ ---@alias lc.storage table<"cache"|"home", string> ----@alias lc.picker { provider: "fzf-lua" | "telescope" } +---@alias lc.picker { provider?: "fzf-lua" | "telescope" } ---@class lc.UserConfig local M = { @@ -104,7 +104,7 @@ local M = { }, ---@type lc.picker - picker = { provider = "telescope" }, + picker = { provider = nil }, hooks = { ---@type fun()[] diff --git a/lua/leetcode/picker/init.lua b/lua/leetcode/picker/init.lua index 719df4b..8fabd22 100644 --- a/lua/leetcode/picker/init.lua +++ b/lua/leetcode/picker/init.lua @@ -1,14 +1,31 @@ local log = require("leetcode.logger") local config = require("leetcode.config") ----@type string -local provider = config.user.picker.provider -assert(pcall(require, provider), ("specified picker provider not found: `%s`"):format(provider)) -provider = provider == "fzf-lua" and "fzf" or provider ----@cast provider "fzf" | "telescope" +---@return "fzf" | "telescope" +local function resolve_provider() + ---@type string + local provider = config.user.picker.provider + + if provider == nil then + local fzf_ok = pcall(require, "fzf-lua") + if fzf_ok then + return "fzf" + end + local telescope_ok = pcall(require, "telescope") + if telescope_ok then + return "telescope" + end + error("no supported picker provider found") + else + local provider_ok = pcall(require, provider) + assert(provider_ok, ("specified picker provider not found: `%s`"):format(provider)) + return provider == "fzf-lua" and "fzf" or provider + end +end ---@class leet.Picker local P = {} +P.provider = resolve_provider() function P.hl_to_ansi(hl_group) local color = vim.api.nvim_get_hl(0, { name = hl_group }) @@ -46,7 +63,7 @@ function P.normalize(items) end function P.pick(path, ...) - local rpath = table.concat({ "leetcode.picker", path, provider }, ".") + local rpath = table.concat({ "leetcode.picker", path, P.provider }, ".") return require(rpath)(...) end