Skip to content

Commit 46c627c

Browse files
authored
feat: folke/snacks.nvim picker support (#177)
feat: `folke/snacks.nvim` picker support
2 parents db7e1cd + 4598846 commit 46c627c

File tree

7 files changed

+256
-22
lines changed

7 files changed

+256
-22
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,14 @@ injector = { ---@type table<lc.lang, lc.inject>
279279

280280
### picker
281281

282-
Supported picker providers are `telescope` and `fzf-lua`.
283-
When provider is `nil`, [leetcode.nvim] will first try to use `fzf-lua`,
284-
if not found it will fallback to `telescope`.
282+
Supported picker providers are:
283+
284+
- `snacks-picker`
285+
- `fzf-lua`
286+
- `telescope`
287+
288+
If `provider` is `nil`, [leetcode.nvim] will try to resolve the first
289+
available one in the order above.
285290

286291
```lua
287292
---@type lc.picker
@@ -377,26 +382,22 @@ image_support = false,
377382
- `inject` re-inject code for the current question
378383

379384
- `session`
380-
381385
- `create` create a new session
382386
- `change` change the current session
383387

384388
- `update` update the current session in case it went out of sync
385389

386390
- `desc` toggle question description
387-
388391
- `toggle` same as `Leet desc`
389392

390393
- `stats` toggle description stats visibility
391394

392395
- `cookie`
393-
394396
- `update` opens a prompt to enter a new cookie
395397

396398
- `delete` sign-out
397399

398400
- `cache`
399-
400401
- `update` updates cache
401402

402403
#### Some commands can take optional arguments. To stack argument values separate them by a `,`

lua/leetcode/config/template.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
---@alias lc.storage table<"cache"|"home", string>
4040

41-
---@alias lc.picker { provider?: "fzf-lua" | "telescope" }
41+
---@alias lc.picker { provider?: "fzf-lua" | "telescope" | "snacks-picker" }
4242

4343
---@class lc.UserConfig
4444
local M = {

lua/leetcode/picker/init.lua

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,65 @@
11
local log = require("leetcode.logger")
22
local config = require("leetcode.config")
33

4-
---@return "fzf" | "telescope"
4+
local provider_order = { "snacks-picker", "fzf-lua", "telescope" }
5+
local providers = {
6+
["fzf-lua"] = {
7+
name = "fzf",
8+
is_available = function()
9+
return pcall(require, "fzf-lua")
10+
end,
11+
},
12+
["snacks-picker"] = {
13+
name = "snacks",
14+
is_available = function()
15+
return pcall(function() ---@diagnostic disable-next-line: undefined-field
16+
assert(Snacks.config["picker"].enabled)
17+
end)
18+
end,
19+
},
20+
["telescope"] = {
21+
name = "telescope",
22+
is_available = function()
23+
return pcall(require, "telescope")
24+
end,
25+
},
26+
}
27+
28+
local available_pickers = table.concat(
29+
vim.tbl_map(function(p)
30+
return providers[p].name
31+
end, provider_order),
32+
", "
33+
)
34+
35+
---@return "fzf" | "telescope" | "snacks"
536
local function resolve_provider()
637
---@type string
738
local provider = config.user.picker.provider
839

940
if provider == nil then
10-
local fzf_ok = pcall(require, "fzf-lua")
11-
if fzf_ok then
12-
return "fzf"
13-
end
14-
local telescope_ok = pcall(require, "telescope")
15-
if telescope_ok then
16-
return "telescope"
41+
for _, key in ipairs(provider_order) do
42+
local picker = providers[key]
43+
44+
if picker.is_available() then
45+
return picker.name
46+
end
1747
end
18-
error("no supported picker provider found")
19-
else
20-
local provider_ok = pcall(require, provider)
21-
assert(provider_ok, ("specified picker provider not found: `%s`"):format(provider))
22-
return provider == "fzf-lua" and "fzf" or provider
48+
49+
error(("No picker is available. Please install one of the following: `%s`") --
50+
:format(available_pickers))
2351
end
52+
53+
local picker = providers[provider]
54+
assert(
55+
picker,
56+
("Picker `%s` is not supported. Available pickers: `%s`") --
57+
:format(provider, available_pickers)
58+
)
59+
60+
local ok = picker.is_available()
61+
assert(ok, ("Picker `%s` is not available. Make sure it is installed"):format(provider))
62+
return picker.name
2463
end
2564

2665
---@class leet.Picker
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
local log = require("leetcode.logger")
2+
local t = require("leetcode.translator")
3+
local picker = require("snacks.picker")
4+
5+
local language_picker = require("leetcode.picker.language")
6+
7+
---@param question lc.ui.Question
8+
return function(question, cb)
9+
local items = language_picker.items(question.q.code_snippets)
10+
local finder_items = {}
11+
local completed = false
12+
13+
for _, item in ipairs(items) do
14+
local text = language_picker.ordinal(item.value)
15+
table.insert(finder_items, {
16+
text = text,
17+
item = item,
18+
})
19+
end
20+
21+
picker.pick({
22+
items = finder_items,
23+
format = function(item)
24+
local ret = {}
25+
vim.tbl_map(function(col)
26+
if type(col) == "table" then
27+
ret[#ret + 1] = col
28+
else
29+
ret[#ret + 1] = { col }
30+
end
31+
ret[#ret + 1] = { " " }
32+
end, item.item.entry)
33+
return ret
34+
end,
35+
title = t("Available Languages"),
36+
layout = {
37+
preview = false,
38+
preset = "select",
39+
layout = {
40+
height = language_picker.height,
41+
width = language_picker.width,
42+
},
43+
},
44+
actions = {
45+
confirm = function(p, item)
46+
if completed then
47+
return
48+
end
49+
completed = true
50+
p:close()
51+
vim.schedule(function()
52+
language_picker.select(item.item.value.t, question, cb)
53+
end)
54+
end,
55+
},
56+
on_close = function()
57+
if completed then
58+
return
59+
end
60+
completed = true
61+
log.warn("No selection")
62+
end,
63+
})
64+
end

lua/leetcode/picker/question/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ local Picker = require("leetcode.picker")
99
local P = {}
1010

1111
P.width = 100
12-
P.height = 20
12+
P.height = 0.6
1313

1414
---@param items lc.cache.Question[]
1515
---@param opts table<string, string[]>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
local log = require("leetcode.logger")
2+
local t = require("leetcode.translator")
3+
local question_picker = require("leetcode.picker.question")
4+
5+
local picker = require("snacks.picker")
6+
7+
---@param questions lc.cache.Question[]
8+
return function(questions, opts)
9+
local items = question_picker.items(questions, opts)
10+
local finder_items = {}
11+
local completed = false
12+
13+
for _, item in ipairs(items) do
14+
local text = question_picker.ordinal(item.value)
15+
table.insert(finder_items, {
16+
text = text,
17+
item = item,
18+
})
19+
end
20+
21+
picker.pick({
22+
items = finder_items,
23+
format = function(item)
24+
local ret = {}
25+
vim.tbl_map(function(col)
26+
if type(col) == "table" then
27+
ret[#ret + 1] = col
28+
else
29+
ret[#ret + 1] = { col }
30+
end
31+
ret[#ret + 1] = { " " }
32+
end, item.item.entry)
33+
return ret
34+
end,
35+
title = t("Select a Question"),
36+
layout = {
37+
preset = "select",
38+
preview = false,
39+
layout = {
40+
height = question_picker.height,
41+
width = question_picker.width,
42+
},
43+
},
44+
actions = {
45+
confirm = function(p, item)
46+
if completed then
47+
return
48+
end
49+
completed = true
50+
p:close()
51+
vim.schedule(function()
52+
question_picker.select(item.item.value)
53+
end)
54+
end,
55+
},
56+
on_close = function()
57+
if completed then
58+
return
59+
end
60+
completed = true
61+
log.warn("No selection")
62+
end,
63+
})
64+
end
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
local log = require("leetcode.logger")
2+
local t = require("leetcode.translator")
3+
local tabs_picker = require("leetcode.picker.tabs")
4+
5+
local picker = require("snacks.picker")
6+
7+
return function(tabs)
8+
local items = tabs_picker.items(tabs)
9+
local finder_items = {}
10+
local completed = false
11+
local items_reflect = {}
12+
13+
for _, item in ipairs(items) do
14+
items_reflect[item.value.question.q.frontend_id] = item.value
15+
local text = tabs_picker.ordinal(item.value.question.q)
16+
table.insert(finder_items, {
17+
entry = item.entry,
18+
item = item.value.question.q.frontend_id,
19+
text = text,
20+
})
21+
end
22+
23+
picker.pick({
24+
items = finder_items,
25+
format = function(item)
26+
local ret = {}
27+
vim.tbl_map(function(col)
28+
if type(col) == "table" then
29+
ret[#ret + 1] = col
30+
else
31+
ret[#ret + 1] = { col }
32+
end
33+
ret[#ret + 1] = { " " }
34+
end, item.entry)
35+
return ret
36+
end,
37+
title = t("Select a Question"),
38+
layout = {
39+
preview = false,
40+
preset = "select",
41+
layout = {
42+
height = tabs_picker.height,
43+
width = tabs_picker.width,
44+
},
45+
},
46+
actions = {
47+
confirm = function(p, item)
48+
if completed then
49+
return
50+
end
51+
completed = true
52+
p:close()
53+
vim.schedule(function()
54+
tabs_picker.select(items_reflect[item.item])
55+
end)
56+
end,
57+
},
58+
on_close = function()
59+
if completed then
60+
return
61+
end
62+
completed = true
63+
log.warn("No selection")
64+
end,
65+
})
66+
end

0 commit comments

Comments
 (0)