Skip to content

Commit 224be46

Browse files
author
zhangfuwen
committed
update
1 parent ac067d9 commit 224be46

File tree

4 files changed

+271
-20
lines changed

4 files changed

+271
-20
lines changed

lua/github_nvim/cache.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,10 @@ function M.save(cache_name, key, results, ttl)
110110
print("❌ Failed to write cache file:", file)
111111
return
112112
end
113+
print("file is: ", vim.inspect(file))
113114

114115
local content = vim.json.encode(data)
115-
print("content is " .. content)
116+
-- print("content is " .. content)
116117
local err = f:write(content)
117118
print(vim.inspect(err))
118119
if err then

lua/github_nvim/gh.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
M = {}
2+
3+
function M.get_github_username()
4+
local result = vim.fn.system("gh api user --jq '.login' 2>/dev/null")
5+
if vim.v.shell_error == 0 then
6+
return string.gsub(result, "\n$", "") -- remove newline
7+
else
8+
return nil
9+
end
10+
end
11+
12+
return M

lua/github_nvim/pickers/github_repos.lua

Lines changed: 201 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
cache = require("github_nvim.cache")
2+
local config = require("github_nvim.config")
3+
local util = require("github_nvim.util")
4+
local gh = require("github_nvim.gh")
25
-- Safely check if telescope is available
36
local function get_telescope()
47
local ok, telescope = pcall(require, 'telescope')
@@ -15,15 +18,22 @@ end
1518
local cache_ns = "github_nvim.pickers"
1619
local cache_key = "github_repos"
1720

18-
local function get_github_repos()
19-
cached_result = cache.load(cache_ns, cache_key)
20-
if cached_result then
21-
print("cache hit")
22-
return cached_result
23-
end
21+
-- Store clone status: key = repo_name, value = "pending" | "success" | "failed"
22+
local clone_status = {}
2423

24+
-- Helper: Get status for a repo
25+
local function get_status(repo)
26+
return clone_status[repo] or nil
27+
end
28+
29+
-- Helper: Set status
30+
local function set_status(repo, status)
31+
clone_status[repo] = status
32+
end
33+
34+
local function get_github_repos()
2535
local handle = io.popen(
26-
'gh repo list -L 200 --json nameWithOwner,description,isPrivate,isFork,isTemplate 2>/dev/null')
36+
'gh repo list -L 200 --json nameWithOwner,description,isPrivate,isFork,isTemplate 2>/dev/null')
2737
local result = handle:read('*a')
2838
handle:close()
2939

@@ -57,10 +67,24 @@ local function get_github_repos()
5767
})
5868
end
5969

70+
return items
71+
end
72+
73+
local function get_github_repos_cached()
74+
cached_result = cache.load(cache_ns, cache_key)
75+
if cached_result then
76+
print("cache hit")
77+
return cached_result
78+
end
79+
local items = get_github_repos()
6080
print("cache save")
6181
cache.save(cache_ns, cache_key, items)
82+
end
6283

63-
return items
84+
local my_picker = nil
85+
86+
local function get_current_picker()
87+
return my_picker
6488
end
6589

6690
return function()
@@ -77,19 +101,32 @@ return function()
77101
end
78102

79103
local finder = require('telescope.finders').new_table({
80-
results = get_github_repos(),
104+
results = get_github_repos_cached(),
81105
entry_maker = function(entry)
106+
print("find...")
107+
local github_dir = config.defaults.github_dir
108+
local sep = config.defaults.sep
109+
local name = entry.value
110+
local local_path = github_dir .. sep .. name
111+
local local_exists = util.path_exists(local_path) and true or false
112+
local local_icon = local_exists and "local" or "remote"
113+
local status = get_status(name)
82114
return {
83115
value = entry.value,
84-
display = entry.display,
116+
display = entry.display .. " " .. local_icon .. (status and "... "..status or ""),
85117
ordinal = entry.value,
118+
is_private = entry.isPrivate,
119+
is_fork = entry.isFork,
120+
is_template = entry.isTemplate,
121+
local_path = entry.local_path,
122+
local_exists = entry.local_exists,
86123
}
87124
end,
88-
-- searcher = conf.fuzzy_finder.new_searcher({}),
125+
-- searcher = conf.fuzzy_finder.new_searcher({}),
89126
searcher = searcher,
90127
})
91128
local pickers = require("telescope.pickers")
92-
pickers.new({}, {
129+
my_picker = pickers.new({}, {
93130
prompt_title = "Your github repos",
94131
finder = finder,
95132
sorter = conf.generic_sorter(opts),
@@ -111,15 +148,163 @@ return function()
111148
--
112149
-- return true
113150
-- end,
151+
114152
attach_mappings = function(prompt_bufnr, map)
115153
-- Add mappings
116-
map('i', '<CR>', function()
117-
local selection = require('telescope.actions.state').get_selected_entry()
118-
print("Selected:", selection.value)
154+
map('i', '<C-g>', function()
155+
local actions = require('telescope.actions.state')
156+
local selection = actions.get_selected_entry()
157+
local local_path = selection.local_path
158+
local local_exists = selection.local_exists
159+
160+
if local_exists then
161+
vim.cmd("Telescope find_files cwd=" .. local_path)
162+
else
163+
print("Selected:", selection.value, " local_path: ", local_path)
164+
end
119165
end)
166+
-- Open in browser
167+
map("i", "<C-o>", function()
168+
local actions = require('telescope.actions.state')
169+
local selection = actions.get_selected_entry()
170+
local url = "https://github.com/" .. selection.value
171+
util.open_url(url)
172+
end, { desc = "Open in browser" })
173+
174+
-- Copy URL to clipboard
175+
map("i", "<C-s>", function()
176+
local actions = require('telescope.actions.state')
177+
local selection = actions.get_selected_entry()
178+
local url = "https://github.com/" .. selection.value
179+
vim.fn.setreg("+", url) -- Copy to system clipboard
180+
vim.notify("Copied: " .. url, vim.log.levels.INFO)
181+
end, { desc = "Copy URL to clipboard" })
182+
183+
-- Clone repo
184+
map("i", "<C-p>", function()
185+
local actions = require('telescope.actions.state')
186+
local selection = actions.get_selected_entry()
187+
local repo_name = selection.value
188+
-- gh_username = gh.get_github_username()
189+
local dir = vim.fn.input("Clone to directory: ",
190+
config.defaults.github_dir .. config.defaults.sep .. repo_name)
191+
set_status(repo_name, "cloning")
192+
193+
194+
-- Refresh immediately
195+
vim.schedule(function()
196+
local actions = require('telescope.actions.state')
197+
local picker = actions.get_current_picker(prompt_bufnr)
198+
-- print("picker ", vim.inspect(picker))
199+
-- print("picker ", vim.inspect(picker))
200+
if picker and picker.finder.results then
201+
picker.finder.results = vim.tbl_map(function(item)
202+
if item.value == repo_name then
203+
item._status = "cloning"
204+
item.display = item.display:gsub("%(.*%)", "(🔄 Cloning...)")
205+
end
206+
return item
207+
end, picker.finder.results)
208+
set_status(repo_name, "downloaded")
209+
picker:refresh()
210+
end
211+
end)
212+
213+
-- Run async clone
214+
local url = "https://github.com/" .. repo_name
215+
vim.system({ "git", "clone", url, dir }, {
216+
text = true, cwd = user_dir, }, function(result)
217+
vim.schedule(function()
218+
local actions = require('telescope.actions.state')
219+
local picker = actions.get_current_picker(prompt_bufnr)
220+
-- print("picker ", vim.inspect(picker))
221+
if not picker then return end
222+
223+
local updated_results = vim.tbl_map(function(item)
224+
if item.value == repo_name then
225+
if result.code == 0 then
226+
item._status = "success"
227+
item.display = item.display:gsub("%(.*%)", "(✅ Cloned)")
228+
vim.notify("✅ Cloned: " .. dir, vim.log.levels.INFO)
229+
else
230+
item._status = "failed"
231+
item.display = item.display:gsub("%(.*%)", "(❌ Failed)")
232+
vim.notify("❌ Failed to clone: " .. vim.inspect(result), vim.log.levels.ERROR)
233+
end
234+
end
235+
return item
236+
end, picker.finder.results)
237+
238+
picker.finder.results = updated_results
239+
picker:refresh()
240+
end)
241+
end)
242+
243+
244+
-- local cmd = "git clone https://github.com/" .. selection.value .. " " .. dir
245+
-- vim.cmd(":silent !" .. cmd)
246+
-- vim.notify("Cloned to: " .. dir)
247+
end, { desc = "Clone repo locally" })
248+
249+
-- Preview README (simple version)
250+
map("i", "<C- >", function()
251+
local actions = require('telescope.actions.state')
252+
local selection = actions.get_selected_entry()
253+
local url = "https://github.com/" .. selection.value .. "/blob/main/README.md"
254+
util.open_url(url)
255+
end, { desc = "Open README" })
256+
257+
map("i", "<C-r>", function()
258+
local actions = require('telescope.actions.state')
259+
local picker = actions.get_current_picker(prompt_bufnr)
260+
if not picker then return end
261+
262+
-- print("picker ", vim.inspect(picker))
263+
264+
-- Get current query from prompt
265+
local query = vim.api.nvim_buf_get_name(picker.prompt_bufnr) or ""
266+
267+
-- Set loading prompt
268+
-- picker.set_prompt("🔄 Refreshing...", false)
269+
270+
-- Use your existing get_github_repos() function
271+
vim.defer_fn(function()
272+
local results = get_github_repos()
273+
274+
if not results or #results == 0 then
275+
vim.schedule(function()
276+
local actions = require('telescope.actions.state')
277+
vim.notify("⚠️ No results returned from GitHub API", vim.log.levels.WARN)
278+
-- picker.set_prompt("GitHub Repositories")
279+
end)
280+
return
281+
end
282+
283+
-- Save to cache
284+
local cache = require("github_nvim.cache")
285+
cache.save(cache_ns, cache_key, results, 60 * 60 * 24)
286+
287+
-- Update picker UI
288+
vim.schedule(function()
289+
-- local actions = require('telescope.actions.state')
290+
picker.results = results
291+
picker:refresh()
292+
-- picker.set_prompt("GitHub Repositories")
293+
vim.notify("✅ Refreshed from internet", vim.log.levels.INFO)
294+
end)
295+
end, 100) -- Small delay to avoid flicker
296+
end, { desc = "force refresh repos" })
297+
298+
-- Optional: Add 'select' as default
299+
-- actions.select_default:replace(function()
300+
-- local selection = actions.get_selected_entry()
301+
-- print("Selected:", selection.value)
302+
-- actions.close(prompt_bufnr)
303+
-- end)
120304
return true
121305
end,
122-
}):find()
306+
})
307+
my_picker:find()
123308
end
124309

125310
-- Main picker function

lua/github_nvim/util.lua

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function M.mkdir_p(path)
77
-- print("Error:", err)
88
-- end
99
-- else
10-
-- Neovim < 0.9:用 shell 命令
10+
-- Neovim < 0.9:用 shell 命令
1111
local cmd = "mkdir -p " .. path
1212
vim.system({ "bash", "-c", cmd })
1313
-- end
@@ -36,15 +36,14 @@ function M.mysplit(inputstr, sep)
3636
return t
3737
end
3838

39-
4039
function M.path_exists(path)
4140
local stat = vim.loop.fs_stat(path)
4241
return stat ~= nil
4342
end
4443

4544
function M.promptYesNo(message, on_yes, on_no, on_cancel)
4645
local Menu = require("nui.menu")
47-
-- local event = require("nui.utils.autocmd").event
46+
-- local event = require("nui.utils.autocmd").event
4847
on_no = on_no or function() end
4948
on_cancel = on_cancel or function() end
5049
local menu = Menu({
@@ -93,5 +92,59 @@ function M.promptYesNo(message, on_yes, on_no, on_cancel)
9392
menu:mount()
9493
end
9594

95+
function M.get_os()
96+
if vim.fn.has("win32") == 1 then
97+
return "windows"
98+
elseif vim.fn.has("mac") == 1 then
99+
return "macos"
100+
elseif vim.fn.has("unix") == 1 then
101+
if vim.env.WSL_DISTRO_NAME then
102+
return "wsl"
103+
elseif vim.env.SHELL and vim.env.SHELL:match("wsl") then
104+
return "wsl"
105+
elseif vim.env.MSYSTEM and vim.env.MSYSTEM:match("MINGW") then
106+
return "msys2"
107+
else
108+
return "linux"
109+
end
110+
else
111+
return "unknown"
112+
end
113+
end
114+
115+
-- Optional: Get OS name as string
116+
function M.is_windows() return M.get_os() == "windows" end
117+
118+
function M.is_macos() return M.get_os() == "macos" end
119+
120+
function M.is_linux() return M.get_os() == "linux" end
121+
122+
function M.is_wsl() return M.get_os() == "wsl" end
123+
124+
function M.is_msys2() return M.get_os() == "msys2" end
125+
126+
function M.open_url(url)
127+
local os = M.get_os()
128+
129+
if os == "macos" then
130+
vim.fn.system("open " .. vim.fn.shellescape(url))
131+
elseif os == "windows" or os == "msys2" then
132+
vim.fn.system("start " .. vim.fn.shellescape(url))
133+
elseif os == "wsl" then
134+
-- Try wslview first (opens in Windows browser)
135+
local success, _ = pcall(vim.fn.system, "wslview --version")
136+
if success then
137+
vim.fn.system("wslview " .. vim.fn.shellescape(url))
138+
else
139+
-- Fallback: try 'start' via Windows host
140+
-- This requires 'wsl.exe' to be able to run Windows commands
141+
vim.fn.system("wsl.exe cmd.exe /c start " .. vim.fn.shellescape(url))
142+
end
143+
elseif os == "linux" then
144+
vim.fn.system("xdg-open " .. vim.fn.shellescape(url))
145+
else
146+
print("Unsupported OS:", os)
147+
end
148+
end
96149

97150
return M

0 commit comments

Comments
 (0)