github-search-cli 9.4.4 → 9.5.1
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 +102 -21
- package/README.md +43 -30
- package/dist/cli.js +431 -89
- package/package.json +1 -1
- package/release-notes/9.5.0.md +30 -0
- package/release-notes/9.5.1.md +36 -0
- package/src/cli.ts +57 -5
- package/src/help.ts +8 -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.1";
|
|
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
|
|
@@ -2431,6 +2659,10 @@ function buildHelpSections() {
|
|
|
2431
2659
|
{ keys: "Packages", action: "Switch to npm packages" },
|
|
2432
2660
|
{ keys: "Export", action: "Export results to file" },
|
|
2433
2661
|
{ keys: "Share", action: "Share repo as text" },
|
|
2662
|
+
{
|
|
2663
|
+
keys: "Org profile",
|
|
2664
|
+
action: "Org summary: repos, stars, top languages"
|
|
2665
|
+
},
|
|
2434
2666
|
{ keys: "Topics", action: "Browse GitHub topics" },
|
|
2435
2667
|
{ keys: "Saved", action: "View saved searches" },
|
|
2436
2668
|
{ keys: "Notifs", action: "Check GitHub notifications" },
|
|
@@ -2458,7 +2690,11 @@ function buildHelpSections() {
|
|
|
2458
2690
|
{ keys: "Enter", action: "Confirm selection / run action" },
|
|
2459
2691
|
{ keys: "d", action: "Delete entry (history, saved)" },
|
|
2460
2692
|
{ keys: "\u2191 \u2193 / j k", action: "Navigate overlay list" },
|
|
2461
|
-
{ keys: "\u2190 \u2192 / h l", action: "Navigate tabs / panels" }
|
|
2693
|
+
{ keys: "\u2190 \u2192 / h l", action: "Navigate tabs / panels" },
|
|
2694
|
+
{
|
|
2695
|
+
keys: "PgUp/PgDn",
|
|
2696
|
+
action: "Scroll update notes; Home/End jump to ends"
|
|
2697
|
+
}
|
|
2462
2698
|
]
|
|
2463
2699
|
},
|
|
2464
2700
|
{
|
|
@@ -3166,6 +3402,31 @@ function fetchReleaseNotes(version) {
|
|
|
3166
3402
|
return null;
|
|
3167
3403
|
}
|
|
3168
3404
|
|
|
3405
|
+
// src/landing.ts
|
|
3406
|
+
import { BoxRenderable as BoxRenderable3, TextRenderable as TextRenderable3 } from "@opentui/core";
|
|
3407
|
+
function landingKeysActive(mode, overlay) {
|
|
3408
|
+
return mode === "landing" && overlay === "none";
|
|
3409
|
+
}
|
|
3410
|
+
var LANDING_KEYS = /* @__PURE__ */ new Set([
|
|
3411
|
+
"up",
|
|
3412
|
+
"k",
|
|
3413
|
+
"down",
|
|
3414
|
+
"j",
|
|
3415
|
+
"enter",
|
|
3416
|
+
"return",
|
|
3417
|
+
"b",
|
|
3418
|
+
"?",
|
|
3419
|
+
"h",
|
|
3420
|
+
"q"
|
|
3421
|
+
]);
|
|
3422
|
+
function landingConsumesKey(name) {
|
|
3423
|
+
return LANDING_KEYS.has(name);
|
|
3424
|
+
}
|
|
3425
|
+
function moveSelection(current, delta, total) {
|
|
3426
|
+
if (total <= 0) return 0;
|
|
3427
|
+
return Math.min(total - 1, Math.max(0, current + delta));
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3169
3430
|
// src/tui.ts
|
|
3170
3431
|
var cachedVersion = null;
|
|
3171
3432
|
var colors = {
|
|
@@ -3274,13 +3535,13 @@ async function launchBrowser(theme_override) {
|
|
|
3274
3535
|
let deepDiveActive = false;
|
|
3275
3536
|
let compareList = [];
|
|
3276
3537
|
let quitArmed = false;
|
|
3277
|
-
const header = new
|
|
3538
|
+
const header = new TextRenderable4(renderer, {
|
|
3278
3539
|
content: " ghfind \u2014 GitHub repo browser [/]search [Space]menu [\u2192]open [?]help [q]uit",
|
|
3279
3540
|
bg: colors.bg,
|
|
3280
3541
|
fg: colors.muted,
|
|
3281
3542
|
height: 1
|
|
3282
3543
|
});
|
|
3283
|
-
const trendingTabBox = new
|
|
3544
|
+
const trendingTabBox = new BoxRenderable4(renderer, {
|
|
3284
3545
|
flexDirection: "row",
|
|
3285
3546
|
height: 1,
|
|
3286
3547
|
backgroundColor: colors.surface,
|
|
@@ -3295,7 +3556,7 @@ async function launchBrowser(theme_override) {
|
|
|
3295
3556
|
TAB_NAMES.forEach((name, i) => {
|
|
3296
3557
|
const isActive = name === trendingTab;
|
|
3297
3558
|
const label = ` ${name} `;
|
|
3298
|
-
const tt = new
|
|
3559
|
+
const tt = new TextRenderable4(renderer, {
|
|
3299
3560
|
content: label,
|
|
3300
3561
|
fg: isActive ? colors.bg : colors.muted,
|
|
3301
3562
|
bg: isActive ? colors.blue : colors.bg,
|
|
@@ -3304,7 +3565,7 @@ async function launchBrowser(theme_override) {
|
|
|
3304
3565
|
trendingTabTexts.push(tt);
|
|
3305
3566
|
trendingTabBox.add(tt);
|
|
3306
3567
|
if (i < TAB_NAMES.length - 1) {
|
|
3307
|
-
const sp = new
|
|
3568
|
+
const sp = new TextRenderable4(renderer, {
|
|
3308
3569
|
content: " ",
|
|
3309
3570
|
fg: colors.muted,
|
|
3310
3571
|
bg: colors.bg,
|
|
@@ -3317,7 +3578,7 @@ async function launchBrowser(theme_override) {
|
|
|
3317
3578
|
}
|
|
3318
3579
|
root.add(header);
|
|
3319
3580
|
root.add(trendingTabBox);
|
|
3320
|
-
const searchBox = new
|
|
3581
|
+
const searchBox = new BoxRenderable4(renderer, {
|
|
3321
3582
|
visible: true,
|
|
3322
3583
|
width: "100%",
|
|
3323
3584
|
flexDirection: "row",
|
|
@@ -3336,7 +3597,7 @@ async function launchBrowser(theme_override) {
|
|
|
3336
3597
|
});
|
|
3337
3598
|
searchBox.add(searchInput);
|
|
3338
3599
|
root.add(searchBox);
|
|
3339
|
-
const toolbarText = new
|
|
3600
|
+
const toolbarText = new TextRenderable4(renderer, {
|
|
3340
3601
|
content: formatToolbar(currentSort, currentLimit, totalCount),
|
|
3341
3602
|
visible: true,
|
|
3342
3603
|
// hidden in trending mode
|
|
@@ -3345,14 +3606,14 @@ async function launchBrowser(theme_override) {
|
|
|
3345
3606
|
paddingX: 1
|
|
3346
3607
|
});
|
|
3347
3608
|
root.add(toolbarText);
|
|
3348
|
-
const body = new
|
|
3609
|
+
const body = new BoxRenderable4(renderer, {
|
|
3349
3610
|
flexDirection: "row",
|
|
3350
3611
|
flexGrow: 1,
|
|
3351
3612
|
gap: 1,
|
|
3352
3613
|
paddingY: 1,
|
|
3353
3614
|
paddingX: 1
|
|
3354
3615
|
});
|
|
3355
|
-
const resultsBox = new
|
|
3616
|
+
const resultsBox = new BoxRenderable4(renderer, {
|
|
3356
3617
|
border: true,
|
|
3357
3618
|
borderColor: colors.border,
|
|
3358
3619
|
title: " Results ",
|
|
@@ -3381,7 +3642,7 @@ async function launchBrowser(theme_override) {
|
|
|
3381
3642
|
itemSpacing: 0
|
|
3382
3643
|
});
|
|
3383
3644
|
resultsBox.add(resultsSelect);
|
|
3384
|
-
const detailBox = new
|
|
3645
|
+
const detailBox = new BoxRenderable4(renderer, {
|
|
3385
3646
|
width: "50%",
|
|
3386
3647
|
flexDirection: "column",
|
|
3387
3648
|
paddingX: 1,
|
|
@@ -3389,7 +3650,7 @@ async function launchBrowser(theme_override) {
|
|
|
3389
3650
|
focusable: false,
|
|
3390
3651
|
backgroundColor: colors.surface
|
|
3391
3652
|
});
|
|
3392
|
-
const detailText = new
|
|
3653
|
+
const detailText = new TextRenderable4(renderer, {
|
|
3393
3654
|
content: "",
|
|
3394
3655
|
fg: colors.text,
|
|
3395
3656
|
wrapMode: "none"
|
|
@@ -3398,7 +3659,7 @@ async function launchBrowser(theme_override) {
|
|
|
3398
3659
|
body.add(resultsBox);
|
|
3399
3660
|
body.add(detailBox);
|
|
3400
3661
|
root.add(body);
|
|
3401
|
-
const landingBox = new
|
|
3662
|
+
const landingBox = new BoxRenderable4(renderer, {
|
|
3402
3663
|
visible: false,
|
|
3403
3664
|
flexGrow: 1,
|
|
3404
3665
|
flexDirection: "column",
|
|
@@ -3406,7 +3667,7 @@ async function launchBrowser(theme_override) {
|
|
|
3406
3667
|
justifyContent: "center"
|
|
3407
3668
|
});
|
|
3408
3669
|
root.add(landingBox);
|
|
3409
|
-
const landingBanner = new
|
|
3670
|
+
const landingBanner = new TextRenderable4(renderer, {
|
|
3410
3671
|
content: [
|
|
3411
3672
|
" \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
3673
|
"\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 +3717,7 @@ async function launchBrowser(theme_override) {
|
|
|
3456
3717
|
const landingCards = [];
|
|
3457
3718
|
for (let i = 0; i < landingOptions.length; i++) {
|
|
3458
3719
|
const opt = landingOptions[i];
|
|
3459
|
-
const card = new
|
|
3720
|
+
const card = new BoxRenderable4(renderer, {
|
|
3460
3721
|
flexDirection: "column",
|
|
3461
3722
|
height: 5,
|
|
3462
3723
|
width: "60%",
|
|
@@ -3468,19 +3729,19 @@ async function launchBrowser(theme_override) {
|
|
|
3468
3729
|
});
|
|
3469
3730
|
landingCards.push(card);
|
|
3470
3731
|
landingBox.add(card);
|
|
3471
|
-
const spacerTop = new
|
|
3472
|
-
const titleLine = new
|
|
3732
|
+
const spacerTop = new TextRenderable4(renderer, { content: "", height: 1 });
|
|
3733
|
+
const titleLine = new TextRenderable4(renderer, {
|
|
3473
3734
|
content: opt.title,
|
|
3474
3735
|
fg: i === 0 ? colors.accent : colors.text,
|
|
3475
3736
|
height: 1
|
|
3476
3737
|
});
|
|
3477
|
-
const spacerBot = new
|
|
3738
|
+
const spacerBot = new TextRenderable4(renderer, { content: "", height: 1 });
|
|
3478
3739
|
card.add(spacerTop);
|
|
3479
3740
|
card.add(titleLine);
|
|
3480
3741
|
card.add(spacerBot);
|
|
3481
3742
|
}
|
|
3482
|
-
const landingHint = new
|
|
3483
|
-
content: " \u2191\u2193 Navigate \u21E9 Select [?]help [q]uit",
|
|
3743
|
+
const landingHint = new TextRenderable4(renderer, {
|
|
3744
|
+
content: " \u2191\u2193 Navigate \u21E9 Select [b]ookmarks [?]help [q]uit",
|
|
3484
3745
|
fg: colors.muted,
|
|
3485
3746
|
bg: colors.bg,
|
|
3486
3747
|
height: 1,
|
|
@@ -3509,27 +3770,36 @@ async function launchBrowser(theme_override) {
|
|
|
3509
3770
|
}
|
|
3510
3771
|
}
|
|
3511
3772
|
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
|
-
|
|
3773
|
+
if (!landingKeysActive(currentMode, currentOverlay)) return;
|
|
3774
|
+
if (key.name === "up" || key.name === "k") {
|
|
3775
|
+
landingSelected = moveSelection(
|
|
3776
|
+
landingSelected,
|
|
3777
|
+
-1,
|
|
3778
|
+
landingOptions.length
|
|
3779
|
+
);
|
|
3780
|
+
updateLandingCards();
|
|
3781
|
+
renderer.requestRender();
|
|
3782
|
+
} else if (key.name === "down" || key.name === "j") {
|
|
3783
|
+
landingSelected = moveSelection(
|
|
3784
|
+
landingSelected,
|
|
3785
|
+
1,
|
|
3786
|
+
landingOptions.length
|
|
3787
|
+
);
|
|
3788
|
+
updateLandingCards();
|
|
3789
|
+
renderer.requestRender();
|
|
3790
|
+
} else if (key.name === "enter" || key.name === "return") {
|
|
3791
|
+
landingOptions[landingSelected].action();
|
|
3792
|
+
} else if (key.name === "b") {
|
|
3793
|
+
refreshBookmarks();
|
|
3794
|
+
showOverlay("bookmarks");
|
|
3795
|
+
} else if (key.name === "?" || key.name === "h") {
|
|
3796
|
+
showOverlay(currentOverlay === "help" ? "none" : "help");
|
|
3797
|
+
} else if (key.name === "q") {
|
|
3798
|
+
cleanup();
|
|
3799
|
+
} else {
|
|
3531
3800
|
return;
|
|
3532
3801
|
}
|
|
3802
|
+
if (landingConsumesKey(key.name)) key.stopPropagation();
|
|
3533
3803
|
});
|
|
3534
3804
|
function hideMainContent() {
|
|
3535
3805
|
trendingTabBox.visible = false;
|
|
@@ -3576,6 +3846,7 @@ async function launchBrowser(theme_override) {
|
|
|
3576
3846
|
return;
|
|
3577
3847
|
}
|
|
3578
3848
|
currentOverlay = type;
|
|
3849
|
+
landingBox.visible = false;
|
|
3579
3850
|
if (type !== "leader") {
|
|
3580
3851
|
hideMainContent();
|
|
3581
3852
|
}
|
|
@@ -3607,11 +3878,12 @@ async function launchBrowser(theme_override) {
|
|
|
3607
3878
|
} else if (type === "update") {
|
|
3608
3879
|
updateDim.visible = true;
|
|
3609
3880
|
updateBox.visible = true;
|
|
3881
|
+
updateScroll.scrollTop = 0;
|
|
3610
3882
|
}
|
|
3611
3883
|
renderer.requestRender();
|
|
3612
3884
|
}
|
|
3613
3885
|
const helpSections = buildHelpSections();
|
|
3614
|
-
const helpBox = new
|
|
3886
|
+
const helpBox = new BoxRenderable4(renderer, {
|
|
3615
3887
|
visible: false,
|
|
3616
3888
|
flexGrow: 1,
|
|
3617
3889
|
backgroundColor: colors.bg
|
|
@@ -3633,7 +3905,7 @@ async function launchBrowser(theme_override) {
|
|
|
3633
3905
|
}
|
|
3634
3906
|
});
|
|
3635
3907
|
for (const section of helpSections) {
|
|
3636
|
-
const sectionBox = new
|
|
3908
|
+
const sectionBox = new BoxRenderable4(renderer, {
|
|
3637
3909
|
title: section.title,
|
|
3638
3910
|
titleColor: colors[section.titleColor] ?? section.titleColor,
|
|
3639
3911
|
flexDirection: "column",
|
|
@@ -3645,7 +3917,7 @@ async function launchBrowser(theme_override) {
|
|
|
3645
3917
|
for (const row of section.rows) {
|
|
3646
3918
|
const keys = row.keys.padEnd(HELP_KEYS_COLUMN);
|
|
3647
3919
|
sectionBox.add(
|
|
3648
|
-
new
|
|
3920
|
+
new TextRenderable4(renderer, {
|
|
3649
3921
|
content: ` ${keys} ${row.action}`,
|
|
3650
3922
|
fg: colors.text
|
|
3651
3923
|
})
|
|
@@ -3653,7 +3925,7 @@ async function launchBrowser(theme_override) {
|
|
|
3653
3925
|
}
|
|
3654
3926
|
if (section.note) {
|
|
3655
3927
|
sectionBox.add(
|
|
3656
|
-
new
|
|
3928
|
+
new TextRenderable4(renderer, {
|
|
3657
3929
|
content: ` ${section.note}`,
|
|
3658
3930
|
fg: colors.muted
|
|
3659
3931
|
})
|
|
@@ -3663,7 +3935,7 @@ async function launchBrowser(theme_override) {
|
|
|
3663
3935
|
}
|
|
3664
3936
|
helpBox.add(helpScroll);
|
|
3665
3937
|
root.add(helpBox);
|
|
3666
|
-
const historyBox = new
|
|
3938
|
+
const historyBox = new BoxRenderable4(renderer, {
|
|
3667
3939
|
visible: false,
|
|
3668
3940
|
flexGrow: 1,
|
|
3669
3941
|
backgroundColor: colors.bg,
|
|
@@ -3698,7 +3970,7 @@ async function launchBrowser(theme_override) {
|
|
|
3698
3970
|
}
|
|
3699
3971
|
historySelect.setSelectedIndex(0);
|
|
3700
3972
|
}
|
|
3701
|
-
const bookmarksBox = new
|
|
3973
|
+
const bookmarksBox = new BoxRenderable4(renderer, {
|
|
3702
3974
|
visible: false,
|
|
3703
3975
|
flexGrow: 1,
|
|
3704
3976
|
backgroundColor: colors.bg,
|
|
@@ -3733,7 +4005,7 @@ async function launchBrowser(theme_override) {
|
|
|
3733
4005
|
}
|
|
3734
4006
|
bookmarksSelect.setSelectedIndex(0);
|
|
3735
4007
|
}
|
|
3736
|
-
const savedBox = new
|
|
4008
|
+
const savedBox = new BoxRenderable4(renderer, {
|
|
3737
4009
|
visible: false,
|
|
3738
4010
|
flexGrow: 1,
|
|
3739
4011
|
backgroundColor: colors.bg,
|
|
@@ -3753,7 +4025,7 @@ async function launchBrowser(theme_override) {
|
|
|
3753
4025
|
});
|
|
3754
4026
|
savedBox.add(savedSelect);
|
|
3755
4027
|
root.add(savedBox);
|
|
3756
|
-
const topicsBox = new
|
|
4028
|
+
const topicsBox = new BoxRenderable4(renderer, {
|
|
3757
4029
|
visible: false,
|
|
3758
4030
|
flexGrow: 1,
|
|
3759
4031
|
backgroundColor: colors.bg,
|
|
@@ -3788,7 +4060,7 @@ async function launchBrowser(theme_override) {
|
|
|
3788
4060
|
}
|
|
3789
4061
|
topicsSelect.setSelectedIndex(0);
|
|
3790
4062
|
}
|
|
3791
|
-
const exportBox = new
|
|
4063
|
+
const exportBox = new BoxRenderable4(renderer, {
|
|
3792
4064
|
visible: false,
|
|
3793
4065
|
flexGrow: 1,
|
|
3794
4066
|
backgroundColor: colors.bg,
|
|
@@ -3825,28 +4097,28 @@ async function launchBrowser(theme_override) {
|
|
|
3825
4097
|
});
|
|
3826
4098
|
exportBox.add(exportSelect);
|
|
3827
4099
|
root.add(exportBox);
|
|
3828
|
-
const compareBox = new
|
|
4100
|
+
const compareBox = new BoxRenderable4(renderer, {
|
|
3829
4101
|
visible: false,
|
|
3830
4102
|
flexGrow: 1,
|
|
3831
4103
|
backgroundColor: colors.bg,
|
|
3832
4104
|
title: " Comparison ",
|
|
3833
4105
|
titleColor: colors.yellow
|
|
3834
4106
|
});
|
|
3835
|
-
const compareText = new
|
|
4107
|
+
const compareText = new TextRenderable4(renderer, {
|
|
3836
4108
|
content: "",
|
|
3837
4109
|
fg: colors.text,
|
|
3838
4110
|
bg: colors.bg
|
|
3839
4111
|
});
|
|
3840
4112
|
compareBox.add(compareText);
|
|
3841
4113
|
root.add(compareBox);
|
|
3842
|
-
const notifsBox = new
|
|
4114
|
+
const notifsBox = new BoxRenderable4(renderer, {
|
|
3843
4115
|
visible: false,
|
|
3844
4116
|
flexGrow: 1,
|
|
3845
4117
|
backgroundColor: colors.bg,
|
|
3846
4118
|
title: " Notifications ",
|
|
3847
4119
|
titleColor: colors.yellow
|
|
3848
4120
|
});
|
|
3849
|
-
const notifsText = new
|
|
4121
|
+
const notifsText = new TextRenderable4(renderer, {
|
|
3850
4122
|
content: "(no notifications)",
|
|
3851
4123
|
fg: colors.text,
|
|
3852
4124
|
bg: colors.bg
|
|
@@ -3861,7 +4133,7 @@ async function launchBrowser(theme_override) {
|
|
|
3861
4133
|
notifsText.content = notifs2.map((n) => ` ${n.icon} ${n.message}`).join("\n");
|
|
3862
4134
|
}
|
|
3863
4135
|
}
|
|
3864
|
-
const shareBox = new
|
|
4136
|
+
const shareBox = new BoxRenderable4(renderer, {
|
|
3865
4137
|
visible: false,
|
|
3866
4138
|
flexGrow: 1,
|
|
3867
4139
|
backgroundColor: colors.bg,
|
|
@@ -3920,7 +4192,7 @@ async function launchBrowser(theme_override) {
|
|
|
3920
4192
|
}
|
|
3921
4193
|
savedSelect.setSelectedIndex(0);
|
|
3922
4194
|
}
|
|
3923
|
-
const leaderDim = new
|
|
4195
|
+
const leaderDim = new BoxRenderable4(renderer, {
|
|
3924
4196
|
visible: false,
|
|
3925
4197
|
position: "absolute",
|
|
3926
4198
|
top: 0,
|
|
@@ -3931,7 +4203,7 @@ async function launchBrowser(theme_override) {
|
|
|
3931
4203
|
// 60% opacity black (hex alpha: 0x99 ≈ 153/255)
|
|
3932
4204
|
});
|
|
3933
4205
|
root.add(leaderDim);
|
|
3934
|
-
const leaderBox = new
|
|
4206
|
+
const leaderBox = new BoxRenderable4(renderer, {
|
|
3935
4207
|
visible: false,
|
|
3936
4208
|
position: "absolute",
|
|
3937
4209
|
width: "80%",
|
|
@@ -3963,7 +4235,7 @@ async function launchBrowser(theme_override) {
|
|
|
3963
4235
|
selectedDescriptionColor: colors.selectionText,
|
|
3964
4236
|
itemSpacing: 0
|
|
3965
4237
|
});
|
|
3966
|
-
const leaderFooter = new
|
|
4238
|
+
const leaderFooter = new TextRenderable4(renderer, {
|
|
3967
4239
|
content: " \u2191\u2193 select Enter run Esc/q close ",
|
|
3968
4240
|
fg: colors.muted,
|
|
3969
4241
|
bg: colors.surfaceDim,
|
|
@@ -3974,7 +4246,7 @@ async function launchBrowser(theme_override) {
|
|
|
3974
4246
|
leaderBox.add(leaderFooter);
|
|
3975
4247
|
root.add(leaderDim);
|
|
3976
4248
|
root.add(leaderBox);
|
|
3977
|
-
const updateDim = new
|
|
4249
|
+
const updateDim = new BoxRenderable4(renderer, {
|
|
3978
4250
|
visible: false,
|
|
3979
4251
|
position: "absolute",
|
|
3980
4252
|
top: 0,
|
|
@@ -3984,13 +4256,13 @@ async function launchBrowser(theme_override) {
|
|
|
3984
4256
|
backgroundColor: "#00000088"
|
|
3985
4257
|
});
|
|
3986
4258
|
root.add(updateDim);
|
|
3987
|
-
const updateBox = new
|
|
4259
|
+
const updateBox = new BoxRenderable4(renderer, {
|
|
3988
4260
|
visible: false,
|
|
3989
4261
|
position: "absolute",
|
|
3990
4262
|
width: "55%",
|
|
3991
|
-
height:
|
|
4263
|
+
height: 24,
|
|
3992
4264
|
left: "22.5%",
|
|
3993
|
-
top: "
|
|
4265
|
+
top: "20%",
|
|
3994
4266
|
backgroundColor: colors.surfaceDim,
|
|
3995
4267
|
border: true,
|
|
3996
4268
|
borderStyle: "rounded",
|
|
@@ -4003,20 +4275,38 @@ async function launchBrowser(theme_override) {
|
|
|
4003
4275
|
paddingLeft: 2,
|
|
4004
4276
|
paddingRight: 2
|
|
4005
4277
|
});
|
|
4006
|
-
const updateText = new
|
|
4278
|
+
const updateText = new TextRenderable4(renderer, {
|
|
4007
4279
|
content: "",
|
|
4008
4280
|
fg: colors.accent,
|
|
4009
4281
|
bg: colors.surfaceDim
|
|
4010
4282
|
});
|
|
4283
|
+
const updateScroll = new ScrollBoxRenderable3(renderer, {
|
|
4284
|
+
flexGrow: 1,
|
|
4285
|
+
backgroundColor: colors.surfaceDim,
|
|
4286
|
+
scrollY: true,
|
|
4287
|
+
scrollX: false,
|
|
4288
|
+
viewportOptions: { backgroundColor: colors.surfaceDim },
|
|
4289
|
+
contentOptions: {
|
|
4290
|
+
backgroundColor: colors.surfaceDim,
|
|
4291
|
+
flexDirection: "column"
|
|
4292
|
+
},
|
|
4293
|
+
scrollbarOptions: {
|
|
4294
|
+
width: 1,
|
|
4295
|
+
trackOptions: {
|
|
4296
|
+
backgroundColor: colors.surfaceDim,
|
|
4297
|
+
foregroundColor: colors.muted
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
});
|
|
4011
4301
|
let updateSelectedOption = 0;
|
|
4012
|
-
const updateOptionsRow = new
|
|
4302
|
+
const updateOptionsRow = new BoxRenderable4(renderer, {
|
|
4013
4303
|
flexDirection: "row",
|
|
4014
4304
|
gap: 1,
|
|
4015
4305
|
backgroundColor: colors.surfaceDim,
|
|
4016
4306
|
height: 3,
|
|
4017
4307
|
width: "100%"
|
|
4018
4308
|
});
|
|
4019
|
-
const updateNowBox = new
|
|
4309
|
+
const updateNowBox = new BoxRenderable4(renderer, {
|
|
4020
4310
|
border: true,
|
|
4021
4311
|
borderColor: updateSelectedOption === 0 ? colors.yellow : colors.border,
|
|
4022
4312
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4025,13 +4315,13 @@ async function launchBrowser(theme_override) {
|
|
|
4025
4315
|
paddingLeft: 1,
|
|
4026
4316
|
paddingRight: 1
|
|
4027
4317
|
});
|
|
4028
|
-
const updateNowText = new
|
|
4318
|
+
const updateNowText = new TextRenderable4(renderer, {
|
|
4029
4319
|
content: " Update Now ",
|
|
4030
4320
|
fg: updateSelectedOption === 0 ? colors.yellow : colors.text,
|
|
4031
4321
|
bg: colors.surfaceDim
|
|
4032
4322
|
});
|
|
4033
4323
|
updateNowBox.add(updateNowText);
|
|
4034
|
-
const laterBox = new
|
|
4324
|
+
const laterBox = new BoxRenderable4(renderer, {
|
|
4035
4325
|
border: true,
|
|
4036
4326
|
borderColor: updateSelectedOption === 1 ? colors.yellow : colors.border,
|
|
4037
4327
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4040,13 +4330,13 @@ async function launchBrowser(theme_override) {
|
|
|
4040
4330
|
paddingLeft: 1,
|
|
4041
4331
|
paddingRight: 1
|
|
4042
4332
|
});
|
|
4043
|
-
const laterText = new
|
|
4333
|
+
const laterText = new TextRenderable4(renderer, {
|
|
4044
4334
|
content: " Later",
|
|
4045
4335
|
fg: updateSelectedOption === 1 ? colors.yellow : colors.text,
|
|
4046
4336
|
bg: colors.surfaceDim
|
|
4047
4337
|
});
|
|
4048
4338
|
laterBox.add(laterText);
|
|
4049
|
-
const neverBox = new
|
|
4339
|
+
const neverBox = new BoxRenderable4(renderer, {
|
|
4050
4340
|
border: true,
|
|
4051
4341
|
borderColor: updateSelectedOption === 2 ? colors.yellow : colors.border,
|
|
4052
4342
|
backgroundColor: colors.surfaceDim,
|
|
@@ -4055,7 +4345,7 @@ async function launchBrowser(theme_override) {
|
|
|
4055
4345
|
paddingLeft: 1,
|
|
4056
4346
|
paddingRight: 1
|
|
4057
4347
|
});
|
|
4058
|
-
const neverText = new
|
|
4348
|
+
const neverText = new TextRenderable4(renderer, {
|
|
4059
4349
|
content: " Don't show again",
|
|
4060
4350
|
fg: updateSelectedOption === 2 ? colors.yellow : colors.text,
|
|
4061
4351
|
bg: colors.surfaceDim
|
|
@@ -4072,14 +4362,15 @@ async function launchBrowser(theme_override) {
|
|
|
4072
4362
|
}
|
|
4073
4363
|
updateOptionsRow.add(updateNowBox);
|
|
4074
4364
|
updateOptionsRow.add(laterBox);
|
|
4075
|
-
const updateFooter = new
|
|
4076
|
-
content: " \u2190\u2192 select Enter Esc/q close",
|
|
4365
|
+
const updateFooter = new TextRenderable4(renderer, {
|
|
4366
|
+
content: " \u2191\u2193/jk/PgUp/PgDn scroll \u2190\u2192 select Enter Esc/q close",
|
|
4077
4367
|
fg: colors.muted,
|
|
4078
4368
|
bg: colors.surfaceDim,
|
|
4079
4369
|
height: 1,
|
|
4080
4370
|
paddingX: 1
|
|
4081
4371
|
});
|
|
4082
|
-
updateBox.add(
|
|
4372
|
+
updateBox.add(updateScroll);
|
|
4373
|
+
updateScroll.add(updateText);
|
|
4083
4374
|
updateBox.add(updateOptionsRow);
|
|
4084
4375
|
updateBox.add(updateFooter);
|
|
4085
4376
|
root.add(updateDim);
|
|
@@ -4426,7 +4717,11 @@ async function launchBrowser(theme_override) {
|
|
|
4426
4717
|
if (!state.lastInstalledVersion) return;
|
|
4427
4718
|
if (state.lastInstalledVersion === currentVersion2) return;
|
|
4428
4719
|
const notes = fetchReleaseNotes(currentVersion2);
|
|
4429
|
-
const
|
|
4720
|
+
const notesWidth = Math.max(
|
|
4721
|
+
30,
|
|
4722
|
+
Math.floor((process.stdout.columns || 80) * 0.55) - 8
|
|
4723
|
+
);
|
|
4724
|
+
const notesBlock = notes ? renderMarkdown(notes, { width: notesWidth }) : " No release notes found for this version.";
|
|
4430
4725
|
updateSelectedOption = 0;
|
|
4431
4726
|
updateText.content = ` Updated ghfind ${state.lastInstalledVersion} \u2192 ${currentVersion2}
|
|
4432
4727
|
|
|
@@ -4445,7 +4740,11 @@ ${notesBlock}`;
|
|
|
4445
4740
|
if (latest) {
|
|
4446
4741
|
updateSelectedOption = 0;
|
|
4447
4742
|
const notes = fetchReleaseNotes(latest);
|
|
4448
|
-
const
|
|
4743
|
+
const notesWidth = Math.max(
|
|
4744
|
+
30,
|
|
4745
|
+
Math.floor((process.stdout.columns || 80) * 0.55) - 8
|
|
4746
|
+
);
|
|
4747
|
+
const notesBlock = notes ? renderMarkdown(notes, { width: notesWidth }) : ` A new version is available
|
|
4449
4748
|
|
|
4450
4749
|
Current: ${currentVersion2}
|
|
4451
4750
|
Latest: ${latest}
|
|
@@ -4539,7 +4838,7 @@ ${notesBlock}`;
|
|
|
4539
4838
|
renderer.requestRender();
|
|
4540
4839
|
}
|
|
4541
4840
|
}
|
|
4542
|
-
const orgBox = new
|
|
4841
|
+
const orgBox = new BoxRenderable4(renderer, {
|
|
4543
4842
|
visible: false,
|
|
4544
4843
|
flexGrow: 1,
|
|
4545
4844
|
backgroundColor: colors.surface,
|
|
@@ -4562,14 +4861,14 @@ ${notesBlock}`;
|
|
|
4562
4861
|
}
|
|
4563
4862
|
}
|
|
4564
4863
|
});
|
|
4565
|
-
const orgText = new
|
|
4864
|
+
const orgText = new TextRenderable4(renderer, {
|
|
4566
4865
|
content: "",
|
|
4567
4866
|
fg: colors.text,
|
|
4568
4867
|
bg: colors.bg
|
|
4569
4868
|
});
|
|
4570
4869
|
orgScroll.add(orgText);
|
|
4571
4870
|
orgBox.add(orgScroll);
|
|
4572
|
-
const orgFooter = new
|
|
4871
|
+
const orgFooter = new TextRenderable4(renderer, {
|
|
4573
4872
|
content: " \u2191\u2193/jk scroll Esc/q close",
|
|
4574
4873
|
fg: colors.muted,
|
|
4575
4874
|
bg: colors.bg,
|
|
@@ -4635,7 +4934,7 @@ ${notesBlock}`;
|
|
|
4635
4934
|
}
|
|
4636
4935
|
renderer.requestRender();
|
|
4637
4936
|
}
|
|
4638
|
-
const readmeBox = new
|
|
4937
|
+
const readmeBox = new BoxRenderable4(renderer, {
|
|
4639
4938
|
visible: false,
|
|
4640
4939
|
flexGrow: 1,
|
|
4641
4940
|
backgroundColor: colors.surface,
|
|
@@ -4658,14 +4957,14 @@ ${notesBlock}`;
|
|
|
4658
4957
|
}
|
|
4659
4958
|
}
|
|
4660
4959
|
});
|
|
4661
|
-
const readmeText = new
|
|
4960
|
+
const readmeText = new TextRenderable4(renderer, {
|
|
4662
4961
|
content: "",
|
|
4663
4962
|
fg: colors.text,
|
|
4664
4963
|
bg: colors.bg
|
|
4665
4964
|
});
|
|
4666
4965
|
readmeScroll.add(readmeText);
|
|
4667
4966
|
readmeBox.add(readmeScroll);
|
|
4668
|
-
const readmeFooter = new
|
|
4967
|
+
const readmeFooter = new TextRenderable4(renderer, {
|
|
4669
4968
|
content: " \u2191\u2193/jk scroll Esc/q close",
|
|
4670
4969
|
fg: colors.muted,
|
|
4671
4970
|
bg: colors.bg,
|
|
@@ -4711,7 +5010,7 @@ ${notesBlock}`;
|
|
|
4711
5010
|
}
|
|
4712
5011
|
renderer.requestRender();
|
|
4713
5012
|
}
|
|
4714
|
-
const statusBar = new
|
|
5013
|
+
const statusBar = new TextRenderable4(renderer, {
|
|
4715
5014
|
content: " Ready. Press Enter to search.",
|
|
4716
5015
|
fg: colors.muted,
|
|
4717
5016
|
height: 1,
|
|
@@ -5449,6 +5748,11 @@ ${pack.description ?? ""}`;
|
|
|
5449
5748
|
renderer.requestRender();
|
|
5450
5749
|
return;
|
|
5451
5750
|
}
|
|
5751
|
+
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") {
|
|
5752
|
+
updateScroll.handleKeyPress(key);
|
|
5753
|
+
renderer.requestRender();
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5452
5756
|
if (key.name === "left" || key.name === "h") {
|
|
5453
5757
|
updateSelectedOption = Math.max(0, updateSelectedOption - 1);
|
|
5454
5758
|
renderUpdateOptions();
|
|
@@ -5489,6 +5793,9 @@ ${pack.description ?? ""}`;
|
|
|
5489
5793
|
}
|
|
5490
5794
|
return;
|
|
5491
5795
|
}
|
|
5796
|
+
if (currentMode === "landing") {
|
|
5797
|
+
return;
|
|
5798
|
+
}
|
|
5492
5799
|
if (key.name === "q") {
|
|
5493
5800
|
if (graphFullscreen) {
|
|
5494
5801
|
toggleGraph();
|
|
@@ -5757,7 +6064,15 @@ function parseArgs(args) {
|
|
|
5757
6064
|
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
5758
6065
|
parts.push(args[++i]);
|
|
5759
6066
|
}
|
|
5760
|
-
flags.org = parts.join("
|
|
6067
|
+
flags.org = parts.join(" ");
|
|
6068
|
+
break;
|
|
6069
|
+
}
|
|
6070
|
+
case "user": {
|
|
6071
|
+
const userParts = [];
|
|
6072
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
6073
|
+
userParts.push(args[++i]);
|
|
6074
|
+
}
|
|
6075
|
+
flags.user = userParts.join(" ");
|
|
5761
6076
|
break;
|
|
5762
6077
|
}
|
|
5763
6078
|
case "--compare": {
|
|
@@ -5803,10 +6118,11 @@ Usage:
|
|
|
5803
6118
|
ghfind <query> --pipe <target> Pipe to clone/open
|
|
5804
6119
|
ghfind --trending --json Trending repos as JSON
|
|
5805
6120
|
ghfind --releases Check bookmarks for new releases
|
|
5806
|
-
ghfind --compare <
|
|
6121
|
+
ghfind --compare <r1> <r2> Compare two+ repos side-by-side
|
|
5807
6122
|
ghfind org <name> --json Org profile: repos, stars, top languages
|
|
5808
|
-
ghfind
|
|
5809
|
-
ghfind pkg <query>
|
|
6123
|
+
ghfind user <name> --json User profile: repos, stars, top languages
|
|
6124
|
+
ghfind pkg <query> --json Search npm packages, output JSON
|
|
6125
|
+
ghfind pkg <query> Search npm packages, text list
|
|
5810
6126
|
ghfind --watch <query> Watch mode (poll every Ns)
|
|
5811
6127
|
ghfind init Run setup wizard
|
|
5812
6128
|
ghfind login Import the gh CLI token or paste one
|
|
@@ -5869,6 +6185,10 @@ Options:
|
|
|
5869
6185
|
await runOrgProfile(flags, outputFormat);
|
|
5870
6186
|
return;
|
|
5871
6187
|
}
|
|
6188
|
+
if (flags.user !== void 0) {
|
|
6189
|
+
await runUserProfile(flags, outputFormat);
|
|
6190
|
+
return;
|
|
6191
|
+
}
|
|
5872
6192
|
const isNonInteractive = outputFormat || flags.count || flags.format || flags.pipe || flags.watch || flags.releases;
|
|
5873
6193
|
if (isNonInteractive) {
|
|
5874
6194
|
if (flags.releases) {
|
|
@@ -5888,6 +6208,28 @@ function buildSearchContext(flags) {
|
|
|
5888
6208
|
provider: createGitHubSearch(void 0, flags.token ? [flags.token] : [])
|
|
5889
6209
|
};
|
|
5890
6210
|
}
|
|
6211
|
+
async function runUserProfile(flags, outputFormat) {
|
|
6212
|
+
try {
|
|
6213
|
+
const profile = await fetchUserProfile(flags.user, {
|
|
6214
|
+
token: flags.token,
|
|
6215
|
+
limit: flags.limit
|
|
6216
|
+
});
|
|
6217
|
+
if (outputFormat === "json") {
|
|
6218
|
+
console.log(formatUserJson(profile));
|
|
6219
|
+
} else if (outputFormat === "csv") {
|
|
6220
|
+
console.log(formatUserCsv(profile));
|
|
6221
|
+
} else if (outputFormat === "markdown") {
|
|
6222
|
+
console.log(formatUserMarkdown(profile));
|
|
6223
|
+
} else if (flags.count) {
|
|
6224
|
+
console.log(profile.publicRepoCount);
|
|
6225
|
+
} else {
|
|
6226
|
+
console.log(formatUserText(profile));
|
|
6227
|
+
}
|
|
6228
|
+
} catch (err) {
|
|
6229
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
6230
|
+
process.exit(1);
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
5891
6233
|
async function runOrgProfile(flags, outputFormat) {
|
|
5892
6234
|
try {
|
|
5893
6235
|
const profile = await fetchOrgProfile(flags.org, {
|