github-search-cli 9.4.3 → 9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -21
- package/README.md +35 -10
- package/dist/cli.js +425 -86
- package/package.json +1 -1
- package/release-notes/9.5.0.md +30 -0
- package/src/cli.ts +55 -2
- package/src/help.ts +4 -0
- package/src/tui.ts +108 -28
- package/src/user.ts +356 -0
package/dist/cli.js
CHANGED
|
@@ -1058,7 +1058,7 @@ async function launchPackageBrowser() {
|
|
|
1058
1058
|
const p = packages[selectedIdx];
|
|
1059
1059
|
openUrl(p.url);
|
|
1060
1060
|
}
|
|
1061
|
-
function
|
|
1061
|
+
function moveSelection2(delta) {
|
|
1062
1062
|
const oldIdx = selectedIdx;
|
|
1063
1063
|
const newIdx = Math.max(0, Math.min(packages.length - 1, oldIdx + delta));
|
|
1064
1064
|
if (newIdx === oldIdx) return;
|
|
@@ -1101,11 +1101,11 @@ async function launchPackageBrowser() {
|
|
|
1101
1101
|
return;
|
|
1102
1102
|
}
|
|
1103
1103
|
if (name === "up" || name === "k") {
|
|
1104
|
-
|
|
1104
|
+
moveSelection2(-1);
|
|
1105
1105
|
return;
|
|
1106
1106
|
}
|
|
1107
1107
|
if (name === "down" || name === "j") {
|
|
1108
|
-
|
|
1108
|
+
moveSelection2(1);
|
|
1109
1109
|
return;
|
|
1110
1110
|
}
|
|
1111
1111
|
if (name === "enter" || name === "return") {
|
|
@@ -1376,7 +1376,7 @@ var cached = null;
|
|
|
1376
1376
|
function getVersion() {
|
|
1377
1377
|
if (cached) return cached;
|
|
1378
1378
|
if (true) {
|
|
1379
|
-
cached = "9.
|
|
1379
|
+
cached = "9.5.0";
|
|
1380
1380
|
return cached;
|
|
1381
1381
|
}
|
|
1382
1382
|
try {
|
|
@@ -1827,6 +1827,234 @@ function formatOrgMarkdown(p) {
|
|
|
1827
1827
|
return lines.join("\n");
|
|
1828
1828
|
}
|
|
1829
1829
|
|
|
1830
|
+
// src/user.ts
|
|
1831
|
+
function apiHeaders2(token) {
|
|
1832
|
+
return {
|
|
1833
|
+
Accept: "application/vnd.github+json",
|
|
1834
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
1835
|
+
"User-Agent": "ghfind",
|
|
1836
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
function userKind(type) {
|
|
1840
|
+
switch (type) {
|
|
1841
|
+
case "Bot":
|
|
1842
|
+
return "Bot";
|
|
1843
|
+
case "Organization":
|
|
1844
|
+
return "Organization";
|
|
1845
|
+
case "User":
|
|
1846
|
+
return "User";
|
|
1847
|
+
default:
|
|
1848
|
+
return type || "Unknown";
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
function normalizeUserRepo(item) {
|
|
1852
|
+
return {
|
|
1853
|
+
fullName: item.full_name ?? "",
|
|
1854
|
+
url: item.html_url ?? "",
|
|
1855
|
+
description: item.description ?? null,
|
|
1856
|
+
language: item.language ?? null,
|
|
1857
|
+
stars: item.stargazers_count ?? 0,
|
|
1858
|
+
forks: item.forks_count ?? 0,
|
|
1859
|
+
pushedAt: item.pushed_at ?? ""
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
function normalizeUser(payload, repos) {
|
|
1863
|
+
const userRepos = (repos ?? []).map(normalizeUserRepo);
|
|
1864
|
+
const langCounts = /* @__PURE__ */ new Map();
|
|
1865
|
+
for (const r of userRepos) {
|
|
1866
|
+
if (!r.language) continue;
|
|
1867
|
+
langCounts.set(r.language, (langCounts.get(r.language) ?? 0) + 1);
|
|
1868
|
+
}
|
|
1869
|
+
const topLanguages = [...langCounts.entries()].map(([language, count]) => ({ language, repos: count })).sort((a, b) => b.repos - a.repos || a.language.localeCompare(b.language)).slice(0, 5);
|
|
1870
|
+
const byStars = [...userRepos].sort(
|
|
1871
|
+
(a, b) => b.stars - a.stars || a.fullName.localeCompare(b.fullName)
|
|
1872
|
+
);
|
|
1873
|
+
const byPushed = [...userRepos].filter((r) => r.pushedAt).sort((a, b) => Date.parse(b.pushedAt) - Date.parse(a.pushedAt));
|
|
1874
|
+
const type = payload.type || "";
|
|
1875
|
+
return {
|
|
1876
|
+
login: payload.login ?? "",
|
|
1877
|
+
name: payload.name ?? null,
|
|
1878
|
+
type,
|
|
1879
|
+
siteAdmin: payload.site_admin ?? false,
|
|
1880
|
+
kind: userKind(type),
|
|
1881
|
+
bio: payload.bio ?? null,
|
|
1882
|
+
url: payload.html_url ?? "",
|
|
1883
|
+
blog: nullIfEmpty(payload.blog),
|
|
1884
|
+
location: nullIfEmpty(payload.location),
|
|
1885
|
+
twitter: nullIfEmpty(payload.twitter_username),
|
|
1886
|
+
company: nullIfEmpty(payload.company),
|
|
1887
|
+
createdAt: payload.created_at ?? "",
|
|
1888
|
+
followers: payload.followers ?? 0,
|
|
1889
|
+
following: payload.following ?? 0,
|
|
1890
|
+
publicRepoCount: payload.public_repos ?? 0,
|
|
1891
|
+
fetchedRepoCount: userRepos.length,
|
|
1892
|
+
totalStars: userRepos.reduce((sum, r) => sum + r.stars, 0),
|
|
1893
|
+
totalForks: userRepos.reduce((sum, r) => sum + r.forks, 0),
|
|
1894
|
+
topLanguages,
|
|
1895
|
+
topRepos: byStars.slice(0, 5),
|
|
1896
|
+
activeRepos: byPushed.slice(0, 5)
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
function nullIfEmpty(v) {
|
|
1900
|
+
return v == null || v === "" ? null : v;
|
|
1901
|
+
}
|
|
1902
|
+
async function fetchUserProfile(user, options = {}) {
|
|
1903
|
+
const name = user.trim().replace(/^@/, "");
|
|
1904
|
+
if (!name) throw new Error("Usage: ghfind user <username>");
|
|
1905
|
+
const token = options.token;
|
|
1906
|
+
const limit = Math.min(Math.max(options.limit ?? 100, 1), 500);
|
|
1907
|
+
let userPayload;
|
|
1908
|
+
try {
|
|
1909
|
+
const res = await fetch(
|
|
1910
|
+
`https://api.github.com/users/${encodeURIComponent(name)}`,
|
|
1911
|
+
{
|
|
1912
|
+
headers: apiHeaders2(token)
|
|
1913
|
+
}
|
|
1914
|
+
);
|
|
1915
|
+
if (res.status === 404) {
|
|
1916
|
+
throw new Error(`User "${name}" not found.`);
|
|
1917
|
+
}
|
|
1918
|
+
if (!res.ok) {
|
|
1919
|
+
const body = await res.text().catch(() => "");
|
|
1920
|
+
throw new Error(`GitHub API error ${res.status}: ${body.slice(0, 200)}`);
|
|
1921
|
+
}
|
|
1922
|
+
userPayload = await res.json();
|
|
1923
|
+
} catch (err) {
|
|
1924
|
+
if (err instanceof Error && err.message.includes(`User "${name}"`))
|
|
1925
|
+
throw err;
|
|
1926
|
+
throw new Error(
|
|
1927
|
+
`Failed to fetch user "${name}": ${err instanceof Error ? err.message : String(err)}`
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1930
|
+
const repos = [];
|
|
1931
|
+
if (userPayload.public_repos > 0) {
|
|
1932
|
+
const perPage = Math.min(limit, 100);
|
|
1933
|
+
const maxPages = Math.ceil(limit / perPage);
|
|
1934
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
1935
|
+
const url = `https://api.github.com/users/${encodeURIComponent(name)}/repos?per_page=${perPage}&sort=pushed&page=${page}`;
|
|
1936
|
+
const res = await fetch(url, { headers: apiHeaders2(token) });
|
|
1937
|
+
if (!res.ok) {
|
|
1938
|
+
break;
|
|
1939
|
+
}
|
|
1940
|
+
const items = await res.json();
|
|
1941
|
+
if (!Array.isArray(items)) break;
|
|
1942
|
+
repos.push(...items);
|
|
1943
|
+
if (repos.length >= limit || items.length < perPage) break;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
return normalizeUser(userPayload, repos.slice(0, limit));
|
|
1947
|
+
}
|
|
1948
|
+
function formatUserText(p) {
|
|
1949
|
+
const lines = [];
|
|
1950
|
+
const badges = [];
|
|
1951
|
+
if (p.kind === "Organization") badges.push("org");
|
|
1952
|
+
if (p.kind === "Bot") badges.push("bot");
|
|
1953
|
+
if (p.siteAdmin) badges.push("staff");
|
|
1954
|
+
const badge = badges.length > 0 ? ` [${badges.join(", ")}]` : "";
|
|
1955
|
+
const title = p.name ? `${p.login} \u2014 ${p.name}${badge}` : `${p.login}${badge}`;
|
|
1956
|
+
lines.push(title);
|
|
1957
|
+
if (p.bio) lines.push(p.bio);
|
|
1958
|
+
const meta = [];
|
|
1959
|
+
if (p.company) meta.push(`Company ${p.company}`);
|
|
1960
|
+
if (p.location) meta.push(`Location ${p.location}`);
|
|
1961
|
+
if (p.blog) meta.push(`Web ${p.blog}`);
|
|
1962
|
+
if (p.twitter) meta.push(`Twitter @${p.twitter}`);
|
|
1963
|
+
if (p.createdAt) meta.push(`Joined ${p.createdAt.slice(0, 10)}`);
|
|
1964
|
+
if (meta.length > 0) lines.push(meta.join("\n"));
|
|
1965
|
+
lines.push(
|
|
1966
|
+
`Repos ${p.publicRepoCount.toLocaleString()} public${p.fetchedRepoCount < p.publicRepoCount ? ` (aggregated ${p.fetchedRepoCount})` : ""}`
|
|
1967
|
+
);
|
|
1968
|
+
lines.push(
|
|
1969
|
+
`Stars ${p.totalStars.toLocaleString()} (sum of aggregated repos)`
|
|
1970
|
+
);
|
|
1971
|
+
lines.push(
|
|
1972
|
+
`Forks ${p.totalForks.toLocaleString()} (sum of aggregated repos)`
|
|
1973
|
+
);
|
|
1974
|
+
lines.push(
|
|
1975
|
+
`Followers ${p.followers.toLocaleString()} \xB7 following ${p.following.toLocaleString()}`
|
|
1976
|
+
);
|
|
1977
|
+
lines.push(`URL ${p.url}`);
|
|
1978
|
+
if (p.topLanguages.length > 0) {
|
|
1979
|
+
const langs = p.topLanguages.map((l) => `${l.language} (${l.repos})`).join(", ");
|
|
1980
|
+
lines.push(`Languages ${langs}`);
|
|
1981
|
+
}
|
|
1982
|
+
if (p.topRepos.length > 0) {
|
|
1983
|
+
lines.push("");
|
|
1984
|
+
lines.push("Top repos by stars:");
|
|
1985
|
+
for (const r of p.topRepos) {
|
|
1986
|
+
lines.push(
|
|
1987
|
+
` ${r.fullName} \u2605 ${r.stars.toLocaleString()} ${r.language ?? ""}`
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
if (p.activeRepos.length > 0) {
|
|
1992
|
+
lines.push("");
|
|
1993
|
+
lines.push("Recently active:");
|
|
1994
|
+
for (const r of p.activeRepos) {
|
|
1995
|
+
lines.push(` ${r.fullName} pushed ${r.pushedAt.slice(0, 10)}`);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
return lines.join("\n");
|
|
1999
|
+
}
|
|
2000
|
+
function formatUserJson(p) {
|
|
2001
|
+
return JSON.stringify(p, null, 2);
|
|
2002
|
+
}
|
|
2003
|
+
function formatUserCsv(p) {
|
|
2004
|
+
const esc = (v) => /[",\n]/.test(v) ? `"${v.replace(/"/g, '""')}"` : v;
|
|
2005
|
+
const row = [
|
|
2006
|
+
p.login,
|
|
2007
|
+
p.name ?? "",
|
|
2008
|
+
p.type,
|
|
2009
|
+
p.url,
|
|
2010
|
+
String(p.publicRepoCount),
|
|
2011
|
+
String(p.totalStars),
|
|
2012
|
+
String(p.totalForks),
|
|
2013
|
+
String(p.followers),
|
|
2014
|
+
p.topLanguages.map((l) => l.language).join(";"),
|
|
2015
|
+
p.createdAt
|
|
2016
|
+
].map(esc);
|
|
2017
|
+
return [
|
|
2018
|
+
"login,name,type,url,public_repos,total_stars,total_forks,followers,top_languages,created_at",
|
|
2019
|
+
row.join(",")
|
|
2020
|
+
].join("\n");
|
|
2021
|
+
}
|
|
2022
|
+
function formatUserMarkdown(p) {
|
|
2023
|
+
const lines = [];
|
|
2024
|
+
lines.push(`# ${p.login}${p.name ? ` \u2014 ${p.name}` : ""}`);
|
|
2025
|
+
if (p.bio) lines.push("", p.bio);
|
|
2026
|
+
lines.push(
|
|
2027
|
+
"",
|
|
2028
|
+
"| Metric | Value |",
|
|
2029
|
+
"| --- | --- |",
|
|
2030
|
+
`| Type | ${p.kind}${p.siteAdmin ? " \xB7 staff" : ""} |`,
|
|
2031
|
+
`| Public repos | ${p.publicRepoCount} |`,
|
|
2032
|
+
`| Total stars (aggregated) | ${p.totalStars.toLocaleString()} |`,
|
|
2033
|
+
`| Total forks (aggregated) | ${p.totalForks.toLocaleString()} |`,
|
|
2034
|
+
`| Followers | ${p.followers.toLocaleString()} |`
|
|
2035
|
+
);
|
|
2036
|
+
if (p.topLanguages.length > 0) {
|
|
2037
|
+
lines.push(
|
|
2038
|
+
`| Top languages | ${p.topLanguages.map((l) => `${l.language} (${l.repos})`).join(", ")} |`
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
if (p.topRepos.length > 0) {
|
|
2042
|
+
lines.push(
|
|
2043
|
+
"",
|
|
2044
|
+
"## Top repos by stars",
|
|
2045
|
+
"",
|
|
2046
|
+
"| Repo | Stars | Language |",
|
|
2047
|
+
"| --- | --- | --- |"
|
|
2048
|
+
);
|
|
2049
|
+
for (const r of p.topRepos) {
|
|
2050
|
+
lines.push(
|
|
2051
|
+
`| [${r.fullName}](${r.url}) | ${r.stars.toLocaleString()} | ${r.language ?? "\u2014"} |`
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
return lines.join("\n");
|
|
2056
|
+
}
|
|
2057
|
+
|
|
1830
2058
|
// src/storage.ts
|
|
1831
2059
|
import {
|
|
1832
2060
|
existsSync as existsSync2,
|
|
@@ -2317,8 +2545,8 @@ import { fileURLToPath as fileURLToPath4 } from "url";
|
|
|
2317
2545
|
// src/tui.ts
|
|
2318
2546
|
import {
|
|
2319
2547
|
createCliRenderer as createCliRenderer3,
|
|
2320
|
-
BoxRenderable as
|
|
2321
|
-
TextRenderable as
|
|
2548
|
+
BoxRenderable as BoxRenderable4,
|
|
2549
|
+
TextRenderable as TextRenderable4,
|
|
2322
2550
|
InputRenderable,
|
|
2323
2551
|
SelectRenderable,
|
|
2324
2552
|
ScrollBoxRenderable as ScrollBoxRenderable3
|
|
@@ -2458,7 +2686,11 @@ function buildHelpSections() {
|
|
|
2458
2686
|
{ keys: "Enter", action: "Confirm selection / run action" },
|
|
2459
2687
|
{ keys: "d", action: "Delete entry (history, saved)" },
|
|
2460
2688
|
{ keys: "\u2191 \u2193 / j k", action: "Navigate overlay list" },
|
|
2461
|
-
{ keys: "\u2190 \u2192 / h l", action: "Navigate tabs / panels" }
|
|
2689
|
+
{ keys: "\u2190 \u2192 / h l", action: "Navigate tabs / panels" },
|
|
2690
|
+
{
|
|
2691
|
+
keys: "PgUp/PgDn",
|
|
2692
|
+
action: "Scroll update notes; Home/End jump to ends"
|
|
2693
|
+
}
|
|
2462
2694
|
]
|
|
2463
2695
|
},
|
|
2464
2696
|
{
|
|
@@ -3166,6 +3398,31 @@ function fetchReleaseNotes(version) {
|
|
|
3166
3398
|
return null;
|
|
3167
3399
|
}
|
|
3168
3400
|
|
|
3401
|
+
// src/landing.ts
|
|
3402
|
+
import { BoxRenderable as BoxRenderable3, TextRenderable as TextRenderable3 } from "@opentui/core";
|
|
3403
|
+
function landingKeysActive(mode, overlay) {
|
|
3404
|
+
return mode === "landing" && overlay === "none";
|
|
3405
|
+
}
|
|
3406
|
+
var LANDING_KEYS = /* @__PURE__ */ new Set([
|
|
3407
|
+
"up",
|
|
3408
|
+
"k",
|
|
3409
|
+
"down",
|
|
3410
|
+
"j",
|
|
3411
|
+
"enter",
|
|
3412
|
+
"return",
|
|
3413
|
+
"b",
|
|
3414
|
+
"?",
|
|
3415
|
+
"h",
|
|
3416
|
+
"q"
|
|
3417
|
+
]);
|
|
3418
|
+
function landingConsumesKey(name) {
|
|
3419
|
+
return LANDING_KEYS.has(name);
|
|
3420
|
+
}
|
|
3421
|
+
function moveSelection(current, delta, total) {
|
|
3422
|
+
if (total <= 0) return 0;
|
|
3423
|
+
return Math.min(total - 1, Math.max(0, current + delta));
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3169
3426
|
// src/tui.ts
|
|
3170
3427
|
var cachedVersion = null;
|
|
3171
3428
|
var colors = {
|
|
@@ -3274,13 +3531,13 @@ async function launchBrowser(theme_override) {
|
|
|
3274
3531
|
let deepDiveActive = false;
|
|
3275
3532
|
let compareList = [];
|
|
3276
3533
|
let quitArmed = false;
|
|
3277
|
-
const header = new
|
|
3534
|
+
const header = new TextRenderable4(renderer, {
|
|
3278
3535
|
content: " ghfind \u2014 GitHub repo browser [/]search [Space]menu [\u2192]open [?]help [q]uit",
|
|
3279
3536
|
bg: colors.bg,
|
|
3280
3537
|
fg: colors.muted,
|
|
3281
3538
|
height: 1
|
|
3282
3539
|
});
|
|
3283
|
-
const trendingTabBox = new
|
|
3540
|
+
const trendingTabBox = new BoxRenderable4(renderer, {
|
|
3284
3541
|
flexDirection: "row",
|
|
3285
3542
|
height: 1,
|
|
3286
3543
|
backgroundColor: colors.surface,
|
|
@@ -3295,7 +3552,7 @@ async function launchBrowser(theme_override) {
|
|
|
3295
3552
|
TAB_NAMES.forEach((name, i) => {
|
|
3296
3553
|
const isActive = name === trendingTab;
|
|
3297
3554
|
const label = ` ${name} `;
|
|
3298
|
-
const tt = new
|
|
3555
|
+
const tt = new TextRenderable4(renderer, {
|
|
3299
3556
|
content: label,
|
|
3300
3557
|
fg: isActive ? colors.bg : colors.muted,
|
|
3301
3558
|
bg: isActive ? colors.blue : colors.bg,
|
|
@@ -3304,7 +3561,7 @@ async function launchBrowser(theme_override) {
|
|
|
3304
3561
|
trendingTabTexts.push(tt);
|
|
3305
3562
|
trendingTabBox.add(tt);
|
|
3306
3563
|
if (i < TAB_NAMES.length - 1) {
|
|
3307
|
-
const sp = new
|
|
3564
|
+
const sp = new TextRenderable4(renderer, {
|
|
3308
3565
|
content: " ",
|
|
3309
3566
|
fg: colors.muted,
|
|
3310
3567
|
bg: colors.bg,
|
|
@@ -3317,7 +3574,7 @@ async function launchBrowser(theme_override) {
|
|
|
3317
3574
|
}
|
|
3318
3575
|
root.add(header);
|
|
3319
3576
|
root.add(trendingTabBox);
|
|
3320
|
-
const searchBox = new
|
|
3577
|
+
const searchBox = new BoxRenderable4(renderer, {
|
|
3321
3578
|
visible: true,
|
|
3322
3579
|
width: "100%",
|
|
3323
3580
|
flexDirection: "row",
|
|
@@ -3336,7 +3593,7 @@ async function launchBrowser(theme_override) {
|
|
|
3336
3593
|
});
|
|
3337
3594
|
searchBox.add(searchInput);
|
|
3338
3595
|
root.add(searchBox);
|
|
3339
|
-
const toolbarText = new
|
|
3596
|
+
const toolbarText = new TextRenderable4(renderer, {
|
|
3340
3597
|
content: formatToolbar(currentSort, currentLimit, totalCount),
|
|
3341
3598
|
visible: true,
|
|
3342
3599
|
// hidden in trending mode
|
|
@@ -3345,14 +3602,14 @@ async function launchBrowser(theme_override) {
|
|
|
3345
3602
|
paddingX: 1
|
|
3346
3603
|
});
|
|
3347
3604
|
root.add(toolbarText);
|
|
3348
|
-
const body = new
|
|
3605
|
+
const body = new BoxRenderable4(renderer, {
|
|
3349
3606
|
flexDirection: "row",
|
|
3350
3607
|
flexGrow: 1,
|
|
3351
3608
|
gap: 1,
|
|
3352
3609
|
paddingY: 1,
|
|
3353
3610
|
paddingX: 1
|
|
3354
3611
|
});
|
|
3355
|
-
const resultsBox = new
|
|
3612
|
+
const resultsBox = new BoxRenderable4(renderer, {
|
|
3356
3613
|
border: true,
|
|
3357
3614
|
borderColor: colors.border,
|
|
3358
3615
|
title: " Results ",
|
|
@@ -3381,7 +3638,7 @@ async function launchBrowser(theme_override) {
|
|
|
3381
3638
|
itemSpacing: 0
|
|
3382
3639
|
});
|
|
3383
3640
|
resultsBox.add(resultsSelect);
|
|
3384
|
-
const detailBox = new
|
|
3641
|
+
const detailBox = new BoxRenderable4(renderer, {
|
|
3385
3642
|
width: "50%",
|
|
3386
3643
|
flexDirection: "column",
|
|
3387
3644
|
paddingX: 1,
|
|
@@ -3389,7 +3646,7 @@ async function launchBrowser(theme_override) {
|
|
|
3389
3646
|
focusable: false,
|
|
3390
3647
|
backgroundColor: colors.surface
|
|
3391
3648
|
});
|
|
3392
|
-
const detailText = new
|
|
3649
|
+
const detailText = new TextRenderable4(renderer, {
|
|
3393
3650
|
content: "",
|
|
3394
3651
|
fg: colors.text,
|
|
3395
3652
|
wrapMode: "none"
|
|
@@ -3398,7 +3655,7 @@ async function launchBrowser(theme_override) {
|
|
|
3398
3655
|
body.add(resultsBox);
|
|
3399
3656
|
body.add(detailBox);
|
|
3400
3657
|
root.add(body);
|
|
3401
|
-
const landingBox = new
|
|
3658
|
+
const landingBox = new BoxRenderable4(renderer, {
|
|
3402
3659
|
visible: false,
|
|
3403
3660
|
flexGrow: 1,
|
|
3404
3661
|
flexDirection: "column",
|
|
@@ -3406,7 +3663,7 @@ async function launchBrowser(theme_override) {
|
|
|
3406
3663
|
justifyContent: "center"
|
|
3407
3664
|
});
|
|
3408
3665
|
root.add(landingBox);
|
|
3409
|
-
const landingBanner = new
|
|
3666
|
+
const landingBanner = new TextRenderable4(renderer, {
|
|
3410
3667
|
content: [
|
|
3411
3668
|
" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
|
|
3412
3669
|
"\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557",
|
|
@@ -3456,7 +3713,7 @@ async function launchBrowser(theme_override) {
|
|
|
3456
3713
|
const landingCards = [];
|
|
3457
3714
|
for (let i = 0; i < landingOptions.length; i++) {
|
|
3458
3715
|
const opt = landingOptions[i];
|
|
3459
|
-
const card = new
|
|
3716
|
+
const card = new BoxRenderable4(renderer, {
|
|
3460
3717
|
flexDirection: "column",
|
|
3461
3718
|
height: 5,
|
|
3462
3719
|
width: "60%",
|
|
@@ -3468,19 +3725,19 @@ async function launchBrowser(theme_override) {
|
|
|
3468
3725
|
});
|
|
3469
3726
|
landingCards.push(card);
|
|
3470
3727
|
landingBox.add(card);
|
|
3471
|
-
const spacerTop = new
|
|
3472
|
-
const titleLine = new
|
|
3728
|
+
const spacerTop = new TextRenderable4(renderer, { content: "", height: 1 });
|
|
3729
|
+
const titleLine = new TextRenderable4(renderer, {
|
|
3473
3730
|
content: opt.title,
|
|
3474
3731
|
fg: i === 0 ? colors.accent : colors.text,
|
|
3475
3732
|
height: 1
|
|
3476
3733
|
});
|
|
3477
|
-
const spacerBot = new
|
|
3734
|
+
const spacerBot = new TextRenderable4(renderer, { content: "", height: 1 });
|
|
3478
3735
|
card.add(spacerTop);
|
|
3479
3736
|
card.add(titleLine);
|
|
3480
3737
|
card.add(spacerBot);
|
|
3481
3738
|
}
|
|
3482
|
-
const landingHint = new
|
|
3483
|
-
content: " \u2191\u2193 Navigate \u21E9 Select [?]help [q]uit",
|
|
3739
|
+
const landingHint = new TextRenderable4(renderer, {
|
|
3740
|
+
content: " \u2191\u2193 Navigate \u21E9 Select [b]ookmarks [?]help [q]uit",
|
|
3484
3741
|
fg: colors.muted,
|
|
3485
3742
|
bg: colors.bg,
|
|
3486
3743
|
height: 1,
|
|
@@ -3509,27 +3766,36 @@ async function launchBrowser(theme_override) {
|
|
|
3509
3766
|
}
|
|
3510
3767
|
}
|
|
3511
3768
|
renderer.keyInput.on("keypress", (key) => {
|
|
3512
|
-
if (currentMode
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
landingOptions
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3769
|
+
if (!landingKeysActive(currentMode, currentOverlay)) return;
|
|
3770
|
+
if (key.name === "up" || key.name === "k") {
|
|
3771
|
+
landingSelected = moveSelection(
|
|
3772
|
+
landingSelected,
|
|
3773
|
+
-1,
|
|
3774
|
+
landingOptions.length
|
|
3775
|
+
);
|
|
3776
|
+
updateLandingCards();
|
|
3777
|
+
renderer.requestRender();
|
|
3778
|
+
} else if (key.name === "down" || key.name === "j") {
|
|
3779
|
+
landingSelected = moveSelection(
|
|
3780
|
+
landingSelected,
|
|
3781
|
+
1,
|
|
3782
|
+
landingOptions.length
|
|
3783
|
+
);
|
|
3784
|
+
updateLandingCards();
|
|
3785
|
+
renderer.requestRender();
|
|
3786
|
+
} else if (key.name === "enter" || key.name === "return") {
|
|
3787
|
+
landingOptions[landingSelected].action();
|
|
3788
|
+
} else if (key.name === "b") {
|
|
3789
|
+
refreshBookmarks();
|
|
3790
|
+
showOverlay("bookmarks");
|
|
3791
|
+
} else if (key.name === "?" || key.name === "h") {
|
|
3792
|
+
showOverlay(currentOverlay === "help" ? "none" : "help");
|
|
3793
|
+
} else if (key.name === "q") {
|
|
3794
|
+
cleanup();
|
|
3795
|
+
} else {
|
|
3531
3796
|
return;
|
|
3532
3797
|
}
|
|
3798
|
+
if (landingConsumesKey(key.name)) key.stopPropagation();
|
|
3533
3799
|
});
|
|
3534
3800
|
function hideMainContent() {
|
|
3535
3801
|
trendingTabBox.visible = false;
|
|
@@ -3576,6 +3842,7 @@ async function launchBrowser(theme_override) {
|
|
|
3576
3842
|
return;
|
|
3577
3843
|
}
|
|
3578
3844
|
currentOverlay = type;
|
|
3845
|
+
landingBox.visible = false;
|
|
3579
3846
|
if (type !== "leader") {
|
|
3580
3847
|
hideMainContent();
|
|
3581
3848
|
}
|
|
@@ -3607,11 +3874,12 @@ async function launchBrowser(theme_override) {
|
|
|
3607
3874
|
} else if (type === "update") {
|
|
3608
3875
|
updateDim.visible = true;
|
|
3609
3876
|
updateBox.visible = true;
|
|
3877
|
+
updateScroll.scrollTop = 0;
|
|
3610
3878
|
}
|
|
3611
3879
|
renderer.requestRender();
|
|
3612
3880
|
}
|
|
3613
3881
|
const helpSections = buildHelpSections();
|
|
3614
|
-
const helpBox = new
|
|
3882
|
+
const helpBox = new BoxRenderable4(renderer, {
|
|
3615
3883
|
visible: false,
|
|
3616
3884
|
flexGrow: 1,
|
|
3617
3885
|
backgroundColor: colors.bg
|
|
@@ -3633,7 +3901,7 @@ async function launchBrowser(theme_override) {
|
|
|
3633
3901
|
}
|
|
3634
3902
|
});
|
|
3635
3903
|
for (const section of helpSections) {
|
|
3636
|
-
const sectionBox = new
|
|
3904
|
+
const sectionBox = new BoxRenderable4(renderer, {
|
|
3637
3905
|
title: section.title,
|
|
3638
3906
|
titleColor: colors[section.titleColor] ?? section.titleColor,
|
|
3639
3907
|
flexDirection: "column",
|
|
@@ -3645,7 +3913,7 @@ async function launchBrowser(theme_override) {
|
|
|
3645
3913
|
for (const row of section.rows) {
|
|
3646
3914
|
const keys = row.keys.padEnd(HELP_KEYS_COLUMN);
|
|
3647
3915
|
sectionBox.add(
|
|
3648
|
-
new
|
|
3916
|
+
new TextRenderable4(renderer, {
|
|
3649
3917
|
content: ` ${keys} ${row.action}`,
|
|
3650
3918
|
fg: colors.text
|
|
3651
3919
|
})
|
|
@@ -3653,7 +3921,7 @@ async function launchBrowser(theme_override) {
|
|
|
3653
3921
|
}
|
|
3654
3922
|
if (section.note) {
|
|
3655
3923
|
sectionBox.add(
|
|
3656
|
-
new
|
|
3924
|
+
new TextRenderable4(renderer, {
|
|
3657
3925
|
content: ` ${section.note}`,
|
|
3658
3926
|
fg: colors.muted
|
|
3659
3927
|
})
|
|
@@ -3663,7 +3931,7 @@ async function launchBrowser(theme_override) {
|
|
|
3663
3931
|
}
|
|
3664
3932
|
helpBox.add(helpScroll);
|
|
3665
3933
|
root.add(helpBox);
|
|
3666
|
-
const historyBox = new
|
|
3934
|
+
const historyBox = new BoxRenderable4(renderer, {
|
|
3667
3935
|
visible: false,
|
|
3668
3936
|
flexGrow: 1,
|
|
3669
3937
|
backgroundColor: colors.bg,
|
|
@@ -3698,7 +3966,7 @@ async function launchBrowser(theme_override) {
|
|
|
3698
3966
|
}
|
|
3699
3967
|
historySelect.setSelectedIndex(0);
|
|
3700
3968
|
}
|
|
3701
|
-
const bookmarksBox = new
|
|
3969
|
+
const bookmarksBox = new BoxRenderable4(renderer, {
|
|
3702
3970
|
visible: false,
|
|
3703
3971
|
flexGrow: 1,
|
|
3704
3972
|
backgroundColor: colors.bg,
|
|
@@ -3733,7 +4001,7 @@ async function launchBrowser(theme_override) {
|
|
|
3733
4001
|
}
|
|
3734
4002
|
bookmarksSelect.setSelectedIndex(0);
|
|
3735
4003
|
}
|
|
3736
|
-
const savedBox = new
|
|
4004
|
+
const savedBox = new BoxRenderable4(renderer, {
|
|
3737
4005
|
visible: false,
|
|
3738
4006
|
flexGrow: 1,
|
|
3739
4007
|
backgroundColor: colors.bg,
|
|
@@ -3753,7 +4021,7 @@ async function launchBrowser(theme_override) {
|
|
|
3753
4021
|
});
|
|
3754
4022
|
savedBox.add(savedSelect);
|
|
3755
4023
|
root.add(savedBox);
|
|
3756
|
-
const topicsBox = new
|
|
4024
|
+
const topicsBox = new BoxRenderable4(renderer, {
|
|
3757
4025
|
visible: false,
|
|
3758
4026
|
flexGrow: 1,
|
|
3759
4027
|
backgroundColor: colors.bg,
|
|
@@ -3788,7 +4056,7 @@ async function launchBrowser(theme_override) {
|
|
|
3788
4056
|
}
|
|
3789
4057
|
topicsSelect.setSelectedIndex(0);
|
|
3790
4058
|
}
|
|
3791
|
-
const exportBox = new
|
|
4059
|
+
const exportBox = new BoxRenderable4(renderer, {
|
|
3792
4060
|
visible: false,
|
|
3793
4061
|
flexGrow: 1,
|
|
3794
4062
|
backgroundColor: colors.bg,
|
|
@@ -3825,28 +4093,28 @@ async function launchBrowser(theme_override) {
|
|
|
3825
4093
|
});
|
|
3826
4094
|
exportBox.add(exportSelect);
|
|
3827
4095
|
root.add(exportBox);
|
|
3828
|
-
const compareBox = new
|
|
4096
|
+
const compareBox = new BoxRenderable4(renderer, {
|
|
3829
4097
|
visible: false,
|
|
3830
4098
|
flexGrow: 1,
|
|
3831
4099
|
backgroundColor: colors.bg,
|
|
3832
4100
|
title: " Comparison ",
|
|
3833
4101
|
titleColor: colors.yellow
|
|
3834
4102
|
});
|
|
3835
|
-
const compareText = new
|
|
4103
|
+
const compareText = new TextRenderable4(renderer, {
|
|
3836
4104
|
content: "",
|
|
3837
4105
|
fg: colors.text,
|
|
3838
4106
|
bg: colors.bg
|
|
3839
4107
|
});
|
|
3840
4108
|
compareBox.add(compareText);
|
|
3841
4109
|
root.add(compareBox);
|
|
3842
|
-
const notifsBox = new
|
|
4110
|
+
const notifsBox = new BoxRenderable4(renderer, {
|
|
3843
4111
|
visible: false,
|
|
3844
4112
|
flexGrow: 1,
|
|
3845
4113
|
backgroundColor: colors.bg,
|
|
3846
4114
|
title: " Notifications ",
|
|
3847
4115
|
titleColor: colors.yellow
|
|
3848
4116
|
});
|
|
3849
|
-
const notifsText = new
|
|
4117
|
+
const notifsText = new TextRenderable4(renderer, {
|
|
3850
4118
|
content: "(no notifications)",
|
|
3851
4119
|
fg: colors.text,
|
|
3852
4120
|
bg: colors.bg
|
|
@@ -3861,7 +4129,7 @@ async function launchBrowser(theme_override) {
|
|
|
3861
4129
|
notifsText.content = notifs2.map((n) => ` ${n.icon} ${n.message}`).join("\n");
|
|
3862
4130
|
}
|
|
3863
4131
|
}
|
|
3864
|
-
const shareBox = new
|
|
4132
|
+
const shareBox = new BoxRenderable4(renderer, {
|
|
3865
4133
|
visible: false,
|
|
3866
4134
|
flexGrow: 1,
|
|
3867
4135
|
backgroundColor: colors.bg,
|
|
@@ -3920,7 +4188,7 @@ async function launchBrowser(theme_override) {
|
|
|
3920
4188
|
}
|
|
3921
4189
|
savedSelect.setSelectedIndex(0);
|
|
3922
4190
|
}
|
|
3923
|
-
const leaderDim = new
|
|
4191
|
+
const leaderDim = new BoxRenderable4(renderer, {
|
|
3924
4192
|
visible: false,
|
|
3925
4193
|
position: "absolute",
|
|
3926
4194
|
top: 0,
|
|
@@ -3931,7 +4199,7 @@ async function launchBrowser(theme_override) {
|
|
|
3931
4199
|
// 60% opacity black (hex alpha: 0x99 ≈ 153/255)
|
|
3932
4200
|
});
|
|
3933
4201
|
root.add(leaderDim);
|
|
3934
|
-
const leaderBox = new
|
|
4202
|
+
const leaderBox = new BoxRenderable4(renderer, {
|
|
3935
4203
|
visible: false,
|
|
3936
4204
|
position: "absolute",
|
|
3937
4205
|
width: "80%",
|
|
@@ -3963,7 +4231,7 @@ async function launchBrowser(theme_override) {
|
|
|
3963
4231
|
selectedDescriptionColor: colors.selectionText,
|
|
3964
4232
|
itemSpacing: 0
|
|
3965
4233
|
});
|
|
3966
|
-
const leaderFooter = new
|
|
4234
|
+
const leaderFooter = new TextRenderable4(renderer, {
|
|
3967
4235
|
content: " \u2191\u2193 select Enter run Esc/q close ",
|
|
3968
4236
|
fg: colors.muted,
|
|
3969
4237
|
bg: colors.surfaceDim,
|
|
@@ -3974,7 +4242,7 @@ async function launchBrowser(theme_override) {
|
|
|
3974
4242
|
leaderBox.add(leaderFooter);
|
|
3975
4243
|
root.add(leaderDim);
|
|
3976
4244
|
root.add(leaderBox);
|
|
3977
|
-
const updateDim = new
|
|
4245
|
+
const updateDim = new BoxRenderable4(renderer, {
|
|
3978
4246
|
visible: false,
|
|
3979
4247
|
position: "absolute",
|
|
3980
4248
|
top: 0,
|
|
@@ -3984,13 +4252,13 @@ async function launchBrowser(theme_override) {
|
|
|
3984
4252
|
backgroundColor: "#00000088"
|
|
3985
4253
|
});
|
|
3986
4254
|
root.add(updateDim);
|
|
3987
|
-
const updateBox = new
|
|
4255
|
+
const updateBox = new BoxRenderable4(renderer, {
|
|
3988
4256
|
visible: false,
|
|
3989
4257
|
position: "absolute",
|
|
3990
4258
|
width: "55%",
|
|
3991
|
-
height:
|
|
4259
|
+
height: 24,
|
|
3992
4260
|
left: "22.5%",
|
|
3993
|
-
top: "
|
|
4261
|
+
top: "20%",
|
|
3994
4262
|
backgroundColor: colors.surfaceDim,
|
|
3995
4263
|
border: true,
|
|
3996
4264
|
borderStyle: "rounded",
|
|
@@ -4003,20 +4271,38 @@ async function launchBrowser(theme_override) {
|
|
|
4003
4271
|
paddingLeft: 2,
|
|
4004
4272
|
paddingRight: 2
|
|
4005
4273
|
});
|
|
4006
|
-
const updateText = new
|
|
4274
|
+
const updateText = new TextRenderable4(renderer, {
|
|
4007
4275
|
content: "",
|
|
4008
4276
|
fg: colors.accent,
|
|
4009
4277
|
bg: colors.surfaceDim
|
|
4010
4278
|
});
|
|
4279
|
+
const updateScroll = new ScrollBoxRenderable3(renderer, {
|
|
4280
|
+
flexGrow: 1,
|
|
4281
|
+
backgroundColor: colors.surfaceDim,
|
|
4282
|
+
scrollY: true,
|
|
4283
|
+
scrollX: false,
|
|
4284
|
+
viewportOptions: { backgroundColor: colors.surfaceDim },
|
|
4285
|
+
contentOptions: {
|
|
4286
|
+
backgroundColor: colors.surfaceDim,
|
|
4287
|
+
flexDirection: "column"
|
|
4288
|
+
},
|
|
4289
|
+
scrollbarOptions: {
|
|
4290
|
+
width: 1,
|
|
4291
|
+
trackOptions: {
|
|
4292
|
+
backgroundColor: colors.surfaceDim,
|
|
4293
|
+
foregroundColor: colors.muted
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
});
|
|
4011
4297
|
let updateSelectedOption = 0;
|
|
4012
|
-
const updateOptionsRow = new
|
|
4298
|
+
const updateOptionsRow = new BoxRenderable4(renderer, {
|
|
4013
4299
|
flexDirection: "row",
|
|
4014
4300
|
gap: 1,
|
|
4015
4301
|
backgroundColor: colors.surfaceDim,
|
|
4016
4302
|
height: 3,
|
|
4017
4303
|
width: "100%"
|
|
4018
4304
|
});
|
|
4019
|
-
const updateNowBox = new
|
|
4305
|
+
const updateNowBox = new BoxRenderable4(renderer, {
|
|
4020
4306
|
border: true,
|
|
4021
4307
|
borderColor: updateSelectedOption === 0 ? colors.yellow : colors.border,
|
|
4022
4308
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4025,13 +4311,13 @@ async function launchBrowser(theme_override) {
|
|
|
4025
4311
|
paddingLeft: 1,
|
|
4026
4312
|
paddingRight: 1
|
|
4027
4313
|
});
|
|
4028
|
-
const updateNowText = new
|
|
4314
|
+
const updateNowText = new TextRenderable4(renderer, {
|
|
4029
4315
|
content: " Update Now ",
|
|
4030
4316
|
fg: updateSelectedOption === 0 ? colors.yellow : colors.text,
|
|
4031
4317
|
bg: colors.surfaceDim
|
|
4032
4318
|
});
|
|
4033
4319
|
updateNowBox.add(updateNowText);
|
|
4034
|
-
const laterBox = new
|
|
4320
|
+
const laterBox = new BoxRenderable4(renderer, {
|
|
4035
4321
|
border: true,
|
|
4036
4322
|
borderColor: updateSelectedOption === 1 ? colors.yellow : colors.border,
|
|
4037
4323
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4040,13 +4326,13 @@ async function launchBrowser(theme_override) {
|
|
|
4040
4326
|
paddingLeft: 1,
|
|
4041
4327
|
paddingRight: 1
|
|
4042
4328
|
});
|
|
4043
|
-
const laterText = new
|
|
4329
|
+
const laterText = new TextRenderable4(renderer, {
|
|
4044
4330
|
content: " Later",
|
|
4045
4331
|
fg: updateSelectedOption === 1 ? colors.yellow : colors.text,
|
|
4046
4332
|
bg: colors.surfaceDim
|
|
4047
4333
|
});
|
|
4048
4334
|
laterBox.add(laterText);
|
|
4049
|
-
const neverBox = new
|
|
4335
|
+
const neverBox = new BoxRenderable4(renderer, {
|
|
4050
4336
|
border: true,
|
|
4051
4337
|
borderColor: updateSelectedOption === 2 ? colors.yellow : colors.border,
|
|
4052
4338
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4055,7 +4341,7 @@ async function launchBrowser(theme_override) {
|
|
|
4055
4341
|
paddingLeft: 1,
|
|
4056
4342
|
paddingRight: 1
|
|
4057
4343
|
});
|
|
4058
|
-
const neverText = new
|
|
4344
|
+
const neverText = new TextRenderable4(renderer, {
|
|
4059
4345
|
content: " Don't show again",
|
|
4060
4346
|
fg: updateSelectedOption === 2 ? colors.yellow : colors.text,
|
|
4061
4347
|
bg: colors.surfaceDim
|
|
@@ -4072,14 +4358,15 @@ async function launchBrowser(theme_override) {
|
|
|
4072
4358
|
}
|
|
4073
4359
|
updateOptionsRow.add(updateNowBox);
|
|
4074
4360
|
updateOptionsRow.add(laterBox);
|
|
4075
|
-
const updateFooter = new
|
|
4076
|
-
content: " \u2190\u2192 select Enter Esc/q close",
|
|
4361
|
+
const updateFooter = new TextRenderable4(renderer, {
|
|
4362
|
+
content: " \u2191\u2193/jk/PgUp/PgDn scroll \u2190\u2192 select Enter Esc/q close",
|
|
4077
4363
|
fg: colors.muted,
|
|
4078
4364
|
bg: colors.surfaceDim,
|
|
4079
4365
|
height: 1,
|
|
4080
4366
|
paddingX: 1
|
|
4081
4367
|
});
|
|
4082
|
-
updateBox.add(
|
|
4368
|
+
updateBox.add(updateScroll);
|
|
4369
|
+
updateScroll.add(updateText);
|
|
4083
4370
|
updateBox.add(updateOptionsRow);
|
|
4084
4371
|
updateBox.add(updateFooter);
|
|
4085
4372
|
root.add(updateDim);
|
|
@@ -4426,7 +4713,11 @@ async function launchBrowser(theme_override) {
|
|
|
4426
4713
|
if (!state.lastInstalledVersion) return;
|
|
4427
4714
|
if (state.lastInstalledVersion === currentVersion2) return;
|
|
4428
4715
|
const notes = fetchReleaseNotes(currentVersion2);
|
|
4429
|
-
const
|
|
4716
|
+
const notesWidth = Math.max(
|
|
4717
|
+
30,
|
|
4718
|
+
Math.floor((process.stdout.columns || 80) * 0.55) - 8
|
|
4719
|
+
);
|
|
4720
|
+
const notesBlock = notes ? renderMarkdown(notes, { width: notesWidth }) : " No release notes found for this version.";
|
|
4430
4721
|
updateSelectedOption = 0;
|
|
4431
4722
|
updateText.content = ` Updated ghfind ${state.lastInstalledVersion} \u2192 ${currentVersion2}
|
|
4432
4723
|
|
|
@@ -4445,7 +4736,11 @@ ${notesBlock}`;
|
|
|
4445
4736
|
if (latest) {
|
|
4446
4737
|
updateSelectedOption = 0;
|
|
4447
4738
|
const notes = fetchReleaseNotes(latest);
|
|
4448
|
-
const
|
|
4739
|
+
const notesWidth = Math.max(
|
|
4740
|
+
30,
|
|
4741
|
+
Math.floor((process.stdout.columns || 80) * 0.55) - 8
|
|
4742
|
+
);
|
|
4743
|
+
const notesBlock = notes ? renderMarkdown(notes, { width: notesWidth }) : ` A new version is available
|
|
4449
4744
|
|
|
4450
4745
|
Current: ${currentVersion2}
|
|
4451
4746
|
Latest: ${latest}
|
|
@@ -4539,7 +4834,7 @@ ${notesBlock}`;
|
|
|
4539
4834
|
renderer.requestRender();
|
|
4540
4835
|
}
|
|
4541
4836
|
}
|
|
4542
|
-
const orgBox = new
|
|
4837
|
+
const orgBox = new BoxRenderable4(renderer, {
|
|
4543
4838
|
visible: false,
|
|
4544
4839
|
flexGrow: 1,
|
|
4545
4840
|
backgroundColor: colors.surface,
|
|
@@ -4562,14 +4857,14 @@ ${notesBlock}`;
|
|
|
4562
4857
|
}
|
|
4563
4858
|
}
|
|
4564
4859
|
});
|
|
4565
|
-
const orgText = new
|
|
4860
|
+
const orgText = new TextRenderable4(renderer, {
|
|
4566
4861
|
content: "",
|
|
4567
4862
|
fg: colors.text,
|
|
4568
4863
|
bg: colors.bg
|
|
4569
4864
|
});
|
|
4570
4865
|
orgScroll.add(orgText);
|
|
4571
4866
|
orgBox.add(orgScroll);
|
|
4572
|
-
const orgFooter = new
|
|
4867
|
+
const orgFooter = new TextRenderable4(renderer, {
|
|
4573
4868
|
content: " \u2191\u2193/jk scroll Esc/q close",
|
|
4574
4869
|
fg: colors.muted,
|
|
4575
4870
|
bg: colors.bg,
|
|
@@ -4635,7 +4930,7 @@ ${notesBlock}`;
|
|
|
4635
4930
|
}
|
|
4636
4931
|
renderer.requestRender();
|
|
4637
4932
|
}
|
|
4638
|
-
const readmeBox = new
|
|
4933
|
+
const readmeBox = new BoxRenderable4(renderer, {
|
|
4639
4934
|
visible: false,
|
|
4640
4935
|
flexGrow: 1,
|
|
4641
4936
|
backgroundColor: colors.surface,
|
|
@@ -4658,14 +4953,14 @@ ${notesBlock}`;
|
|
|
4658
4953
|
}
|
|
4659
4954
|
}
|
|
4660
4955
|
});
|
|
4661
|
-
const readmeText = new
|
|
4956
|
+
const readmeText = new TextRenderable4(renderer, {
|
|
4662
4957
|
content: "",
|
|
4663
4958
|
fg: colors.text,
|
|
4664
4959
|
bg: colors.bg
|
|
4665
4960
|
});
|
|
4666
4961
|
readmeScroll.add(readmeText);
|
|
4667
4962
|
readmeBox.add(readmeScroll);
|
|
4668
|
-
const readmeFooter = new
|
|
4963
|
+
const readmeFooter = new TextRenderable4(renderer, {
|
|
4669
4964
|
content: " \u2191\u2193/jk scroll Esc/q close",
|
|
4670
4965
|
fg: colors.muted,
|
|
4671
4966
|
bg: colors.bg,
|
|
@@ -4711,7 +5006,7 @@ ${notesBlock}`;
|
|
|
4711
5006
|
}
|
|
4712
5007
|
renderer.requestRender();
|
|
4713
5008
|
}
|
|
4714
|
-
const statusBar = new
|
|
5009
|
+
const statusBar = new TextRenderable4(renderer, {
|
|
4715
5010
|
content: " Ready. Press Enter to search.",
|
|
4716
5011
|
fg: colors.muted,
|
|
4717
5012
|
height: 1,
|
|
@@ -5449,6 +5744,11 @@ ${pack.description ?? ""}`;
|
|
|
5449
5744
|
renderer.requestRender();
|
|
5450
5745
|
return;
|
|
5451
5746
|
}
|
|
5747
|
+
if (key.name === "pageup" || key.name === "pagedown" || key.name === "home" || key.name === "end" || key.name === "up" || key.name === "down" || key.name === "j" || key.name === "k") {
|
|
5748
|
+
updateScroll.handleKeyPress(key);
|
|
5749
|
+
renderer.requestRender();
|
|
5750
|
+
return;
|
|
5751
|
+
}
|
|
5452
5752
|
if (key.name === "left" || key.name === "h") {
|
|
5453
5753
|
updateSelectedOption = Math.max(0, updateSelectedOption - 1);
|
|
5454
5754
|
renderUpdateOptions();
|
|
@@ -5489,6 +5789,9 @@ ${pack.description ?? ""}`;
|
|
|
5489
5789
|
}
|
|
5490
5790
|
return;
|
|
5491
5791
|
}
|
|
5792
|
+
if (currentMode === "landing") {
|
|
5793
|
+
return;
|
|
5794
|
+
}
|
|
5492
5795
|
if (key.name === "q") {
|
|
5493
5796
|
if (graphFullscreen) {
|
|
5494
5797
|
toggleGraph();
|
|
@@ -5757,7 +6060,15 @@ function parseArgs(args) {
|
|
|
5757
6060
|
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
5758
6061
|
parts.push(args[++i]);
|
|
5759
6062
|
}
|
|
5760
|
-
flags.org = parts.join("
|
|
6063
|
+
flags.org = parts.join(" ");
|
|
6064
|
+
break;
|
|
6065
|
+
}
|
|
6066
|
+
case "user": {
|
|
6067
|
+
const userParts = [];
|
|
6068
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
6069
|
+
userParts.push(args[++i]);
|
|
6070
|
+
}
|
|
6071
|
+
flags.user = userParts.join(" ");
|
|
5761
6072
|
break;
|
|
5762
6073
|
}
|
|
5763
6074
|
case "--compare": {
|
|
@@ -5805,6 +6116,8 @@ Usage:
|
|
|
5805
6116
|
ghfind --releases Check bookmarks for new releases
|
|
5806
6117
|
ghfind --compare <repo1> <repo2> Compare two+ repos side-by-side
|
|
5807
6118
|
ghfind org <name> --json Org profile: repos, stars, top languages
|
|
6119
|
+
ghfind user <name> --json User profile: repos, stars, top languages
|
|
6120
|
+
ghfind user <name> --json User profile: repos, stars, top languages
|
|
5808
6121
|
ghfind pkg <query> --json Search npm packages, output JSON
|
|
5809
6122
|
ghfind pkg <query> Search npm packages, text list
|
|
5810
6123
|
ghfind --watch <query> Watch mode (poll every Ns)
|
|
@@ -5869,6 +6182,10 @@ Options:
|
|
|
5869
6182
|
await runOrgProfile(flags, outputFormat);
|
|
5870
6183
|
return;
|
|
5871
6184
|
}
|
|
6185
|
+
if (flags.user !== void 0) {
|
|
6186
|
+
await runUserProfile(flags, outputFormat);
|
|
6187
|
+
return;
|
|
6188
|
+
}
|
|
5872
6189
|
const isNonInteractive = outputFormat || flags.count || flags.format || flags.pipe || flags.watch || flags.releases;
|
|
5873
6190
|
if (isNonInteractive) {
|
|
5874
6191
|
if (flags.releases) {
|
|
@@ -5888,6 +6205,28 @@ function buildSearchContext(flags) {
|
|
|
5888
6205
|
provider: createGitHubSearch(void 0, flags.token ? [flags.token] : [])
|
|
5889
6206
|
};
|
|
5890
6207
|
}
|
|
6208
|
+
async function runUserProfile(flags, outputFormat) {
|
|
6209
|
+
try {
|
|
6210
|
+
const profile = await fetchUserProfile(flags.user, {
|
|
6211
|
+
token: flags.token,
|
|
6212
|
+
limit: flags.limit
|
|
6213
|
+
});
|
|
6214
|
+
if (outputFormat === "json") {
|
|
6215
|
+
console.log(formatUserJson(profile));
|
|
6216
|
+
} else if (outputFormat === "csv") {
|
|
6217
|
+
console.log(formatUserCsv(profile));
|
|
6218
|
+
} else if (outputFormat === "markdown") {
|
|
6219
|
+
console.log(formatUserMarkdown(profile));
|
|
6220
|
+
} else if (flags.count) {
|
|
6221
|
+
console.log(profile.publicRepoCount);
|
|
6222
|
+
} else {
|
|
6223
|
+
console.log(formatUserText(profile));
|
|
6224
|
+
}
|
|
6225
|
+
} catch (err) {
|
|
6226
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
6227
|
+
process.exit(1);
|
|
6228
|
+
}
|
|
6229
|
+
}
|
|
5891
6230
|
async function runOrgProfile(flags, outputFormat) {
|
|
5892
6231
|
try {
|
|
5893
6232
|
const profile = await fetchOrgProfile(flags.org, {
|