github-search-cli 9.9.0 → 9.10.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 +94 -0
- package/README.md +49 -51
- package/dist/cli.js +562 -121
- package/docs/HOW-TO.md +3 -2
- package/package.json +2 -2
- package/release-notes/9.10.0.md +137 -0
- package/release-notes/9.10.1.md +59 -0
- package/src/cli.ts +77 -7
- package/src/help.ts +21 -4
- package/src/history.ts +4 -5
- package/src/mcp-server.ts +4 -2
- package/src/output.ts +11 -1
- package/src/package-browser.ts +2 -0
- package/src/status.ts +40 -0
- package/src/trending.ts +3 -1
- package/src/tui/mouse.ts +349 -0
- package/src/tui.ts +428 -114
- package/src/watch.ts +18 -6
- package/src/export.ts +0 -73
- package/src/pipe.ts +0 -60
- package/src/search-state.ts +0 -278
package/dist/cli.js
CHANGED
|
@@ -1569,6 +1569,7 @@ async function launchPackageBrowser() {
|
|
|
1569
1569
|
renderer.keyInput.on("keypress", (key) => {
|
|
1570
1570
|
const name = key.name || "";
|
|
1571
1571
|
if (name === "q" || name === "escape") {
|
|
1572
|
+
renderer.destroy();
|
|
1572
1573
|
process.exit(0);
|
|
1573
1574
|
return;
|
|
1574
1575
|
}
|
|
@@ -2153,7 +2154,7 @@ var cached = null;
|
|
|
2153
2154
|
function getVersion() {
|
|
2154
2155
|
if (cached) return cached;
|
|
2155
2156
|
if (true) {
|
|
2156
|
-
cached = "9.
|
|
2157
|
+
cached = "9.10.1";
|
|
2157
2158
|
return cached;
|
|
2158
2159
|
}
|
|
2159
2160
|
try {
|
|
@@ -2322,6 +2323,7 @@ function reportError(err, context = {
|
|
|
2322
2323
|
|
|
2323
2324
|
// src/output.ts
|
|
2324
2325
|
import { writeFileSync as writeFileSync2 } from "fs";
|
|
2326
|
+
var PIPE_TARGETS = ["open", "clone"];
|
|
2325
2327
|
var FORMATS = /* @__PURE__ */ new Map([
|
|
2326
2328
|
// Export formats
|
|
2327
2329
|
["json", formatJson],
|
|
@@ -2335,6 +2337,7 @@ var FORMATS = /* @__PURE__ */ new Map([
|
|
|
2335
2337
|
["clone-commands", formatCloneCommands],
|
|
2336
2338
|
["ids", formatIds]
|
|
2337
2339
|
]);
|
|
2340
|
+
var FORMAT_VALUES = [...FORMATS.keys()];
|
|
2338
2341
|
function formatJson(repos) {
|
|
2339
2342
|
return JSON.stringify(repos, null, 2);
|
|
2340
2343
|
}
|
|
@@ -2407,6 +2410,13 @@ async function pipeExec(repos, target) {
|
|
|
2407
2410
|
}
|
|
2408
2411
|
|
|
2409
2412
|
// src/watch.ts
|
|
2413
|
+
function resolveTrendingSince(opts) {
|
|
2414
|
+
if (opts.since === "weekly" || opts.since === "monthly") return opts.since;
|
|
2415
|
+
if (opts.since === "daily") return "daily";
|
|
2416
|
+
if (opts.query === "weekly") return "weekly";
|
|
2417
|
+
if (opts.query === "monthly") return "monthly";
|
|
2418
|
+
return "daily";
|
|
2419
|
+
}
|
|
2410
2420
|
var MAX_FAILS = 5;
|
|
2411
2421
|
async function runWatch(opts, onChange, onError) {
|
|
2412
2422
|
let previous = [];
|
|
@@ -2419,7 +2429,7 @@ async function runWatch(opts, onChange, onError) {
|
|
|
2419
2429
|
try {
|
|
2420
2430
|
let repos;
|
|
2421
2431
|
if (opts.trending) {
|
|
2422
|
-
const since = opts
|
|
2432
|
+
const since = resolveTrendingSince(opts);
|
|
2423
2433
|
const trendingSearch = createTrendingSearch();
|
|
2424
2434
|
const response = await trendingSearch.search(trendingQuery(), {
|
|
2425
2435
|
limit: opts.limit,
|
|
@@ -3874,6 +3884,135 @@ if (import.meta.main && false) {
|
|
|
3874
3884
|
launchTrending();
|
|
3875
3885
|
}
|
|
3876
3886
|
|
|
3887
|
+
// src/tui/mouse.ts
|
|
3888
|
+
var DOUBLE_CLICK_MS = 400;
|
|
3889
|
+
function hitIndexForY(geometry, screenY) {
|
|
3890
|
+
const pitch = geometry.linesPerItem;
|
|
3891
|
+
if (pitch <= 0) return -1;
|
|
3892
|
+
if (geometry.optionCount <= 0) return -1;
|
|
3893
|
+
const localY = screenY - geometry.screenY;
|
|
3894
|
+
if (localY < 0 || localY >= geometry.height) return -1;
|
|
3895
|
+
const row = Math.floor(localY / pitch);
|
|
3896
|
+
const index = geometry.scrollOffset + row;
|
|
3897
|
+
const last = geometry.optionCount - 1;
|
|
3898
|
+
if (index < 0) return 0;
|
|
3899
|
+
return index > last ? last : index;
|
|
3900
|
+
}
|
|
3901
|
+
function selectRowGeometry(select) {
|
|
3902
|
+
const internal = select;
|
|
3903
|
+
return {
|
|
3904
|
+
screenY: select.screenY,
|
|
3905
|
+
height: select.height,
|
|
3906
|
+
optionCount: select.options.length,
|
|
3907
|
+
scrollOffset: internal.scrollOffset ?? 0,
|
|
3908
|
+
linesPerItem: internal.linesPerItem ?? 0
|
|
3909
|
+
};
|
|
3910
|
+
}
|
|
3911
|
+
function attachClickToSelect(renderer, select, options = {}) {
|
|
3912
|
+
const wheelStep = options.wheelStep ?? 3;
|
|
3913
|
+
let lastClickIndex = -1;
|
|
3914
|
+
let lastClickAt = 0;
|
|
3915
|
+
let lastHovered = -1;
|
|
3916
|
+
select.onMouseDown = (event) => {
|
|
3917
|
+
event.stopPropagation();
|
|
3918
|
+
if (options.keepFocus) event.preventDefault();
|
|
3919
|
+
const index = hitIndexForY(selectRowGeometry(select), event.y);
|
|
3920
|
+
if (index < 0) {
|
|
3921
|
+
lastClickIndex = -1;
|
|
3922
|
+
options.onClickMiss?.();
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
const now = Date.now();
|
|
3926
|
+
const alreadySelected = select.getSelectedIndex() === index;
|
|
3927
|
+
const isDouble = alreadySelected && index === lastClickIndex && now - lastClickAt < DOUBLE_CLICK_MS;
|
|
3928
|
+
lastClickIndex = index;
|
|
3929
|
+
lastClickAt = now;
|
|
3930
|
+
if (isDouble) {
|
|
3931
|
+
lastClickIndex = -1;
|
|
3932
|
+
options.onOpen?.();
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
select.setSelectedIndex(index);
|
|
3936
|
+
};
|
|
3937
|
+
select.onMouseScroll = (event) => {
|
|
3938
|
+
event.stopPropagation();
|
|
3939
|
+
const direction = event.scroll?.direction;
|
|
3940
|
+
if (direction === "up") select.moveUp(wheelStep);
|
|
3941
|
+
else if (direction === "down") select.moveDown(wheelStep);
|
|
3942
|
+
else return;
|
|
3943
|
+
renderer.requestRender();
|
|
3944
|
+
};
|
|
3945
|
+
attachHoverHighlight(renderer, select, {
|
|
3946
|
+
onHover: (index) => {
|
|
3947
|
+
lastHovered = index;
|
|
3948
|
+
options.onHoverRow?.(index);
|
|
3949
|
+
},
|
|
3950
|
+
// A stale row must never outlive the options it pointed at.
|
|
3951
|
+
onLeave: () => {
|
|
3952
|
+
lastHovered = -1;
|
|
3953
|
+
}
|
|
3954
|
+
});
|
|
3955
|
+
return {
|
|
3956
|
+
reset() {
|
|
3957
|
+
lastClickIndex = -1;
|
|
3958
|
+
lastClickAt = 0;
|
|
3959
|
+
},
|
|
3960
|
+
get lastHovered() {
|
|
3961
|
+
return lastHovered;
|
|
3962
|
+
}
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
function attachHoverHighlight(renderer, select, options = {}) {
|
|
3966
|
+
const idleBackground = select.backgroundColor;
|
|
3967
|
+
const hoverBackground = "#ffffff0f";
|
|
3968
|
+
let hovered = -1;
|
|
3969
|
+
select.onMouseOver = () => {
|
|
3970
|
+
renderer.setMousePointer("pointer");
|
|
3971
|
+
select.backgroundColor = hoverBackground;
|
|
3972
|
+
renderer.requestRender();
|
|
3973
|
+
};
|
|
3974
|
+
select.onMouseOut = () => {
|
|
3975
|
+
renderer.setMousePointer("default");
|
|
3976
|
+
select.backgroundColor = idleBackground;
|
|
3977
|
+
if (hovered !== -1) {
|
|
3978
|
+
hovered = -1;
|
|
3979
|
+
options.onLeave?.();
|
|
3980
|
+
}
|
|
3981
|
+
renderer.requestRender();
|
|
3982
|
+
};
|
|
3983
|
+
select.onMouseMove = (event) => {
|
|
3984
|
+
const index = hitIndexForY(selectRowGeometry(select), event.y);
|
|
3985
|
+
if (index === hovered) return;
|
|
3986
|
+
hovered = index;
|
|
3987
|
+
options.onHover?.(index);
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
function attachClickOutside(target, onDismiss) {
|
|
3991
|
+
target.onMouseDown = (event) => {
|
|
3992
|
+
event.stopPropagation();
|
|
3993
|
+
onDismiss();
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
function attachClickableBox(renderer, box, handlers) {
|
|
3997
|
+
box.onMouseDown = (event) => {
|
|
3998
|
+
event.stopPropagation();
|
|
3999
|
+
handlers.onActivate();
|
|
4000
|
+
};
|
|
4001
|
+
box.onMouseOver = () => {
|
|
4002
|
+
renderer.setMousePointer("pointer");
|
|
4003
|
+
box.borderColor = handlers.activeBorder;
|
|
4004
|
+
handlers.onStateChange?.();
|
|
4005
|
+
renderer.requestRender();
|
|
4006
|
+
};
|
|
4007
|
+
box.onMouseOut = () => {
|
|
4008
|
+
renderer.setMousePointer("default");
|
|
4009
|
+
box.borderColor = handlers.idleBorder;
|
|
4010
|
+
handlers.onStateChange?.();
|
|
4011
|
+
renderer.requestRender();
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
var NON_INTERACTIVE_TEXT = { selectable: false };
|
|
4015
|
+
|
|
3877
4016
|
// src/help.ts
|
|
3878
4017
|
function buildHelpSections() {
|
|
3879
4018
|
return [
|
|
@@ -3895,7 +4034,7 @@ function buildHelpSections() {
|
|
|
3895
4034
|
{ keys: "\u2191 \u2193 / j k", action: "Move selection" },
|
|
3896
4035
|
{ keys: "Enter", action: "Open repo in browser" },
|
|
3897
4036
|
{ keys: "/", action: "Focus search input" },
|
|
3898
|
-
{ keys: "
|
|
4037
|
+
{ keys: "Esc", action: "Open command menu" },
|
|
3899
4038
|
{ keys: "? / Ctrl+H", action: "Toggle this help screen" },
|
|
3900
4039
|
{ keys: "q", action: "Quit" }
|
|
3901
4040
|
]
|
|
@@ -3929,7 +4068,8 @@ function buildHelpSections() {
|
|
|
3929
4068
|
rows: [
|
|
3930
4069
|
{ keys: "1-5", action: "Switch tab: Today \u2192 Week \u2192 Month \u2192 \u2026" },
|
|
3931
4070
|
{ keys: "\u2190 \u2192 / h l", action: "Navigate tabs" }
|
|
3932
|
-
]
|
|
4071
|
+
],
|
|
4072
|
+
note: "Tabs are also clickable."
|
|
3933
4073
|
},
|
|
3934
4074
|
{
|
|
3935
4075
|
title: " Packages Mode ",
|
|
@@ -3938,12 +4078,12 @@ function buildHelpSections() {
|
|
|
3938
4078
|
{ keys: "/", action: "Search npm packages" },
|
|
3939
4079
|
{ keys: "\u2191 \u2193 / j k", action: "Move selection" },
|
|
3940
4080
|
{ keys: "Enter", action: "View package details" },
|
|
3941
|
-
{ keys: "
|
|
4081
|
+
{ keys: "Esc", action: "Open command menu" }
|
|
3942
4082
|
],
|
|
3943
4083
|
note: "Search by name, description, or tags. Sort by downloads or score."
|
|
3944
4084
|
},
|
|
3945
4085
|
{
|
|
3946
|
-
title: " Command Menu (
|
|
4086
|
+
title: " Command Menu (Esc)",
|
|
3947
4087
|
titleColor: "purple",
|
|
3948
4088
|
rows: [
|
|
3949
4089
|
{ keys: "Sort", action: "Cycle sort: best-match \u2192 stars \u2192 \u2026" },
|
|
@@ -3968,7 +4108,7 @@ function buildHelpSections() {
|
|
|
3968
4108
|
{ keys: "History", action: "View search history" },
|
|
3969
4109
|
{ keys: "Help", action: "Show this help screen" }
|
|
3970
4110
|
],
|
|
3971
|
-
note: "Navigate menu with \u2191 \u2193, select with Enter, back with \u2190 / Esc"
|
|
4111
|
+
note: "Navigate menu with \u2191 \u2193, select with Enter, back with \u2190 / Esc. Clicking a row runs it directly. Esc (or the \u2630 menu button) opens this menu; Space types a space in the query."
|
|
3972
4112
|
},
|
|
3973
4113
|
{
|
|
3974
4114
|
title: " Bookmarks Page ",
|
|
@@ -3981,6 +4121,22 @@ function buildHelpSections() {
|
|
|
3981
4121
|
],
|
|
3982
4122
|
note: "A full page, not an overlay \u2014 Esc returns to the mode menu."
|
|
3983
4123
|
},
|
|
4124
|
+
{
|
|
4125
|
+
title: " Mouse ",
|
|
4126
|
+
titleColor: "green",
|
|
4127
|
+
rows: [
|
|
4128
|
+
{ keys: "Click", action: "Select a row / card / tab" },
|
|
4129
|
+
{ keys: "Double-click", action: "Open the repo or run the action" },
|
|
4130
|
+
{ keys: "Scroll wheel", action: "Move the selection / scroll a pane" },
|
|
4131
|
+
{ keys: "Click outside", action: "Dismiss an open overlay" },
|
|
4132
|
+
{ keys: "Click query box", action: "Focus the search input" },
|
|
4133
|
+
{
|
|
4134
|
+
keys: "\u2630 menu button",
|
|
4135
|
+
action: "Open the command menu (bottom-right)"
|
|
4136
|
+
}
|
|
4137
|
+
],
|
|
4138
|
+
note: "Every list is fully clickable; keyboard and mouse are interchangeable."
|
|
4139
|
+
},
|
|
3984
4140
|
{
|
|
3985
4141
|
title: " Overlay Keys ",
|
|
3986
4142
|
titleColor: "teal",
|
|
@@ -4724,10 +4880,12 @@ var StatusManager = class {
|
|
|
4724
4880
|
type = "idle";
|
|
4725
4881
|
message = "";
|
|
4726
4882
|
onUpdate;
|
|
4883
|
+
disposed = false;
|
|
4727
4884
|
constructor(onUpdate) {
|
|
4728
4885
|
this.onUpdate = onUpdate;
|
|
4729
4886
|
}
|
|
4730
4887
|
set(type, message) {
|
|
4888
|
+
if (this.disposed) return;
|
|
4731
4889
|
this.stopSpinner();
|
|
4732
4890
|
this.type = type;
|
|
4733
4891
|
this.message = message;
|
|
@@ -4740,6 +4898,7 @@ var StatusManager = class {
|
|
|
4740
4898
|
}
|
|
4741
4899
|
}
|
|
4742
4900
|
startSpinner(frames) {
|
|
4901
|
+
if (this.disposed) return;
|
|
4743
4902
|
this.spinnerIndex = 0;
|
|
4744
4903
|
this.emit(frames[0]);
|
|
4745
4904
|
this.spinnerInterval = setInterval(() => {
|
|
@@ -4754,14 +4913,23 @@ var StatusManager = class {
|
|
|
4754
4913
|
}
|
|
4755
4914
|
}
|
|
4756
4915
|
emit(spinner) {
|
|
4916
|
+
if (this.disposed) return;
|
|
4757
4917
|
const icon = this.type === "searching" ? "\u{1F50D}" : this.type === "loading" ? "\u{1F4E6}" : this.type === "success" ? "\u2713" : this.type === "error" ? "\u26A0" : " ";
|
|
4758
4918
|
const prefix = spinner ?? "";
|
|
4759
4919
|
this.onUpdate(`${icon} ${this.message} ${prefix}`.trim());
|
|
4760
4920
|
}
|
|
4761
4921
|
dispose() {
|
|
4922
|
+
this.disposed = true;
|
|
4762
4923
|
this.stopSpinner();
|
|
4763
4924
|
}
|
|
4764
4925
|
};
|
|
4926
|
+
function createStatusManager(bar, onFrame) {
|
|
4927
|
+
return new StatusManager((text) => {
|
|
4928
|
+
if (bar.isDestroyed) return;
|
|
4929
|
+
bar.content = ` ${text}`;
|
|
4930
|
+
onFrame();
|
|
4931
|
+
});
|
|
4932
|
+
}
|
|
4765
4933
|
|
|
4766
4934
|
// src/share.ts
|
|
4767
4935
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -5124,13 +5292,15 @@ function createTuiLogger() {
|
|
|
5124
5292
|
};
|
|
5125
5293
|
}
|
|
5126
5294
|
var logger = createTuiLogger();
|
|
5295
|
+
var activeStatusMgr = null;
|
|
5296
|
+
var activeRenderer = null;
|
|
5127
5297
|
var SORT_MODES = [
|
|
5128
5298
|
{ key: "best-match", label: "best-match" },
|
|
5129
5299
|
{ key: "stars", label: "stars" },
|
|
5130
5300
|
{ key: "updated", label: "updated" },
|
|
5131
5301
|
{ key: "forks", label: "forks" }
|
|
5132
5302
|
];
|
|
5133
|
-
async function launchBrowser(theme_override) {
|
|
5303
|
+
async function launchBrowser(theme_override, startMode) {
|
|
5134
5304
|
const terminalBg = await detectTerminalBackground();
|
|
5135
5305
|
let renderer;
|
|
5136
5306
|
try {
|
|
@@ -5166,6 +5336,7 @@ async function launchBrowser(theme_override) {
|
|
|
5166
5336
|
return;
|
|
5167
5337
|
}
|
|
5168
5338
|
const root = renderer.root;
|
|
5339
|
+
activeRenderer = renderer;
|
|
5169
5340
|
root.flexDirection = "column";
|
|
5170
5341
|
const config = loadConfig();
|
|
5171
5342
|
let githubToken = config.githubToken || process.env.GITHUB_TOKEN;
|
|
@@ -5197,7 +5368,7 @@ async function launchBrowser(theme_override) {
|
|
|
5197
5368
|
const compareList = [];
|
|
5198
5369
|
const _quitArmed = false;
|
|
5199
5370
|
const header = new TextRenderable5(renderer, {
|
|
5200
|
-
content: " ghfind \u2014 GitHub repo browser [/]search [
|
|
5371
|
+
content: " ghfind \u2014 GitHub repo browser [/]search [Esc]menu [\u2192]open [?]help [q]uit \xB7 click select \xB7 dbl-click open",
|
|
5201
5372
|
bg: colors.bg,
|
|
5202
5373
|
fg: colors.muted,
|
|
5203
5374
|
height: 1
|
|
@@ -5218,15 +5389,25 @@ async function launchBrowser(theme_override) {
|
|
|
5218
5389
|
const isActive = name === trendingTab;
|
|
5219
5390
|
const label = ` ${name} `;
|
|
5220
5391
|
const tt = new TextRenderable5(renderer, {
|
|
5392
|
+
...NON_INTERACTIVE_TEXT,
|
|
5221
5393
|
content: label,
|
|
5222
5394
|
fg: isActive ? colors.bg : colors.muted,
|
|
5223
5395
|
bg: isActive ? colors.blue : colors.bg,
|
|
5224
5396
|
height: 1
|
|
5225
5397
|
});
|
|
5398
|
+
tt.onMouseDown = (event) => {
|
|
5399
|
+
event.stopPropagation();
|
|
5400
|
+
if (name === trendingTab) return;
|
|
5401
|
+
trendingTab = name;
|
|
5402
|
+
loadTrending();
|
|
5403
|
+
};
|
|
5404
|
+
tt.onMouseOver = () => renderer.setMousePointer("pointer");
|
|
5405
|
+
tt.onMouseOut = () => renderer.setMousePointer("default");
|
|
5226
5406
|
trendingTabTexts.push(tt);
|
|
5227
5407
|
trendingTabBox.add(tt);
|
|
5228
5408
|
if (i < TAB_NAMES.length - 1) {
|
|
5229
5409
|
const sp = new TextRenderable5(renderer, {
|
|
5410
|
+
...NON_INTERACTIVE_TEXT,
|
|
5230
5411
|
content: " ",
|
|
5231
5412
|
fg: colors.muted,
|
|
5232
5413
|
bg: colors.bg,
|
|
@@ -5314,7 +5495,10 @@ async function launchBrowser(theme_override) {
|
|
|
5314
5495
|
const detailText = new TextRenderable5(renderer, {
|
|
5315
5496
|
content: "",
|
|
5316
5497
|
fg: colors.text,
|
|
5317
|
-
wrapMode: "none"
|
|
5498
|
+
wrapMode: "none",
|
|
5499
|
+
// Non-interactive: a left-press here would otherwise be swallowed as a
|
|
5500
|
+
// text-selection drag instead of reaching the click handlers.
|
|
5501
|
+
selectable: false
|
|
5318
5502
|
});
|
|
5319
5503
|
detailBox.add(detailText);
|
|
5320
5504
|
body.add(resultsBox);
|
|
@@ -5329,6 +5513,7 @@ async function launchBrowser(theme_override) {
|
|
|
5329
5513
|
});
|
|
5330
5514
|
root.add(landingBox);
|
|
5331
5515
|
const landingBanner = new TextRenderable5(renderer, {
|
|
5516
|
+
...NON_INTERACTIVE_TEXT,
|
|
5332
5517
|
content: [
|
|
5333
5518
|
" \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 ",
|
|
5334
5519
|
"\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",
|
|
@@ -5406,7 +5591,8 @@ async function launchBrowser(theme_override) {
|
|
|
5406
5591
|
card.add(spacerBot);
|
|
5407
5592
|
}
|
|
5408
5593
|
const landingHint = new TextRenderable5(renderer, {
|
|
5409
|
-
|
|
5594
|
+
...NON_INTERACTIVE_TEXT,
|
|
5595
|
+
content: " \u2191\u2193 Navigate \u21E9 Select [b]ookmarks [?]help [q]uit \xB7 click to pick a mode",
|
|
5410
5596
|
fg: colors.muted,
|
|
5411
5597
|
bg: colors.bg,
|
|
5412
5598
|
height: 1,
|
|
@@ -5434,6 +5620,28 @@ async function launchBrowser(theme_override) {
|
|
|
5434
5620
|
}
|
|
5435
5621
|
}
|
|
5436
5622
|
}
|
|
5623
|
+
landingCards.forEach((card, i) => {
|
|
5624
|
+
let lastClickAt = 0;
|
|
5625
|
+
card.onMouseDown = (event) => {
|
|
5626
|
+
event.stopPropagation();
|
|
5627
|
+
const now = Date.now();
|
|
5628
|
+
const isDouble = landingSelected === i && now - lastClickAt < DOUBLE_CLICK_MS;
|
|
5629
|
+
lastClickAt = now;
|
|
5630
|
+
if (isDouble) {
|
|
5631
|
+
landingOptions[i].action();
|
|
5632
|
+
return;
|
|
5633
|
+
}
|
|
5634
|
+
landingSelected = i;
|
|
5635
|
+
updateLandingCards();
|
|
5636
|
+
renderer.requestRender();
|
|
5637
|
+
};
|
|
5638
|
+
card.onMouseOver = () => {
|
|
5639
|
+
renderer.setMousePointer("pointer");
|
|
5640
|
+
};
|
|
5641
|
+
card.onMouseOut = () => {
|
|
5642
|
+
renderer.setMousePointer("default");
|
|
5643
|
+
};
|
|
5644
|
+
});
|
|
5437
5645
|
renderer.keyInput.on("keypress", (key) => {
|
|
5438
5646
|
if (!landingKeysActive(currentMode, currentOverlay)) return;
|
|
5439
5647
|
if (key.name === "up" || key.name === "k") {
|
|
@@ -5494,10 +5702,12 @@ async function launchBrowser(theme_override) {
|
|
|
5494
5702
|
leaderBox.visible = false;
|
|
5495
5703
|
leaderDim.visible = false;
|
|
5496
5704
|
readmeBox.visible = false;
|
|
5705
|
+
orgBox.visible = false;
|
|
5497
5706
|
updateBox.visible = false;
|
|
5498
5707
|
updateDim.visible = false;
|
|
5499
5708
|
if (type === "none") {
|
|
5500
5709
|
currentOverlay = "none";
|
|
5710
|
+
menuButton.visible = true;
|
|
5501
5711
|
if (currentMode === "landing") {
|
|
5502
5712
|
landingBox.visible = true;
|
|
5503
5713
|
body.visible = false;
|
|
@@ -5511,6 +5721,7 @@ async function launchBrowser(theme_override) {
|
|
|
5511
5721
|
return;
|
|
5512
5722
|
}
|
|
5513
5723
|
currentOverlay = type;
|
|
5724
|
+
menuButton.visible = false;
|
|
5514
5725
|
landingBox.visible = false;
|
|
5515
5726
|
if (type !== "leader") {
|
|
5516
5727
|
hideMainContent();
|
|
@@ -5772,7 +5983,8 @@ async function launchBrowser(theme_override) {
|
|
|
5772
5983
|
const compareText = new TextRenderable5(renderer, {
|
|
5773
5984
|
content: "",
|
|
5774
5985
|
fg: colors.text,
|
|
5775
|
-
bg: colors.bg
|
|
5986
|
+
bg: colors.bg,
|
|
5987
|
+
selectable: false
|
|
5776
5988
|
});
|
|
5777
5989
|
compareBox.add(compareText);
|
|
5778
5990
|
root.add(compareBox);
|
|
@@ -5901,7 +6113,8 @@ async function launchBrowser(theme_override) {
|
|
|
5901
6113
|
itemSpacing: 0
|
|
5902
6114
|
});
|
|
5903
6115
|
const leaderFooter = new TextRenderable5(renderer, {
|
|
5904
|
-
|
|
6116
|
+
...NON_INTERACTIVE_TEXT,
|
|
6117
|
+
content: " \u2191\u2193 select Enter run Esc/q close \xB7 click to run click outside to close ",
|
|
5905
6118
|
fg: colors.muted,
|
|
5906
6119
|
bg: colors.surfaceDim,
|
|
5907
6120
|
height: 1,
|
|
@@ -6033,10 +6246,59 @@ async function launchBrowser(theme_override) {
|
|
|
6033
6246
|
neverText.fg = updateSelectedOption === 2 ? colors.yellow : colors.text;
|
|
6034
6247
|
renderer.requestRender();
|
|
6035
6248
|
}
|
|
6249
|
+
function runUpdateOption(index) {
|
|
6250
|
+
updateSelectedOption = index;
|
|
6251
|
+
renderUpdateOptions();
|
|
6252
|
+
const action = ["now", "later", "never"][index];
|
|
6253
|
+
if (action === "now") {
|
|
6254
|
+
showOverlay("none");
|
|
6255
|
+
recordPreUpdateState(cachedVersion ?? "");
|
|
6256
|
+
performUpdate().then((ok) => {
|
|
6257
|
+
if (ok) {
|
|
6258
|
+
setStatus("\u2713 Update complete \u2014 restart ghfind");
|
|
6259
|
+
} else {
|
|
6260
|
+
setStatus("\u2717 Update failed \u2014 check terminal output");
|
|
6261
|
+
}
|
|
6262
|
+
}).catch(() => {
|
|
6263
|
+
setStatus("\u2717 Update failed \u2014 check terminal output");
|
|
6264
|
+
});
|
|
6265
|
+
} else if (action === "never") {
|
|
6266
|
+
suppressUpdateNotices();
|
|
6267
|
+
showOverlay("none");
|
|
6268
|
+
setStatus("Update notices suppressed");
|
|
6269
|
+
} else {
|
|
6270
|
+
snoozeUpdateNotices(3);
|
|
6271
|
+
showOverlay("none");
|
|
6272
|
+
setStatus("Update reminder snoozed for 3 days");
|
|
6273
|
+
}
|
|
6274
|
+
renderer.requestRender();
|
|
6275
|
+
}
|
|
6276
|
+
const updateCards = [
|
|
6277
|
+
[updateNowBox, 0],
|
|
6278
|
+
[laterBox, 1],
|
|
6279
|
+
[neverBox, 2]
|
|
6280
|
+
];
|
|
6281
|
+
for (const [box, index] of updateCards) {
|
|
6282
|
+
attachClickableBox(renderer, box, {
|
|
6283
|
+
onActivate: () => runUpdateOption(index),
|
|
6284
|
+
idleBorder: updateSelectedOption === index ? colors.yellow : colors.border,
|
|
6285
|
+
activeBorder: colors.yellow,
|
|
6286
|
+
// Hovering must not fight the selection highlight, so it only moves the
|
|
6287
|
+
// pointer cursor; the border stays owned by renderUpdateOptions().
|
|
6288
|
+
onStateChange: () => {
|
|
6289
|
+
box.borderColor = updateSelectedOption === index ? colors.yellow : colors.border;
|
|
6290
|
+
}
|
|
6291
|
+
});
|
|
6292
|
+
}
|
|
6293
|
+
attachClickOutside(updateDim, () => {
|
|
6294
|
+
showOverlay("none");
|
|
6295
|
+
renderer.requestRender();
|
|
6296
|
+
});
|
|
6036
6297
|
updateOptionsRow.add(updateNowBox);
|
|
6037
6298
|
updateOptionsRow.add(laterBox);
|
|
6038
6299
|
const updateFooter = new TextRenderable5(renderer, {
|
|
6039
|
-
|
|
6300
|
+
...NON_INTERACTIVE_TEXT,
|
|
6301
|
+
content: " \u2191\u2193/jk/PgUp/PgDn scroll \u2190\u2192 select Enter Esc/q close \xB7 click a button click outside to close",
|
|
6040
6302
|
fg: colors.muted,
|
|
6041
6303
|
bg: colors.surfaceDim,
|
|
6042
6304
|
height: 1,
|
|
@@ -6525,6 +6787,7 @@ async function launchBrowser(theme_override) {
|
|
|
6525
6787
|
}
|
|
6526
6788
|
});
|
|
6527
6789
|
const orgText = new TextRenderable5(renderer, {
|
|
6790
|
+
...NON_INTERACTIVE_TEXT,
|
|
6528
6791
|
content: "",
|
|
6529
6792
|
fg: colors.text,
|
|
6530
6793
|
bg: colors.bg
|
|
@@ -6532,6 +6795,7 @@ async function launchBrowser(theme_override) {
|
|
|
6532
6795
|
orgScroll.add(orgText);
|
|
6533
6796
|
orgBox.add(orgScroll);
|
|
6534
6797
|
const orgFooter = new TextRenderable5(renderer, {
|
|
6798
|
+
...NON_INTERACTIVE_TEXT,
|
|
6535
6799
|
content: " \u2191\u2193/jk scroll Esc/q close",
|
|
6536
6800
|
fg: colors.muted,
|
|
6537
6801
|
bg: colors.bg,
|
|
@@ -6671,10 +6935,46 @@ async function launchBrowser(theme_override) {
|
|
|
6671
6935
|
paddingX: 1
|
|
6672
6936
|
});
|
|
6673
6937
|
root.add(statusBar);
|
|
6674
|
-
const
|
|
6675
|
-
|
|
6676
|
-
|
|
6938
|
+
const menuButton = new BoxRenderable5(renderer, {
|
|
6939
|
+
position: "absolute",
|
|
6940
|
+
bottom: 1,
|
|
6941
|
+
right: 1,
|
|
6942
|
+
height: 1,
|
|
6943
|
+
paddingX: 1,
|
|
6944
|
+
backgroundColor: colors.surface,
|
|
6945
|
+
focusable: false
|
|
6946
|
+
});
|
|
6947
|
+
const menuButtonLabel = new TextRenderable5(renderer, {
|
|
6948
|
+
...NON_INTERACTIVE_TEXT,
|
|
6949
|
+
content: "\u2630 menu",
|
|
6950
|
+
fg: colors.muted,
|
|
6951
|
+
bg: colors.surface,
|
|
6952
|
+
height: 1
|
|
6677
6953
|
});
|
|
6954
|
+
menuButton.add(menuButtonLabel);
|
|
6955
|
+
root.add(menuButton);
|
|
6956
|
+
menuButton.onMouseDown = (event) => {
|
|
6957
|
+
event.stopPropagation();
|
|
6958
|
+
if (currentOverlay === "leader") showOverlay("none");
|
|
6959
|
+
else showLeaderMenu();
|
|
6960
|
+
renderer.requestRender();
|
|
6961
|
+
};
|
|
6962
|
+
menuButton.onMouseOver = () => {
|
|
6963
|
+
renderer.setMousePointer("pointer");
|
|
6964
|
+
menuButtonLabel.fg = colors.accent;
|
|
6965
|
+
renderer.requestRender();
|
|
6966
|
+
};
|
|
6967
|
+
menuButton.onMouseOut = () => {
|
|
6968
|
+
renderer.setMousePointer("default");
|
|
6969
|
+
menuButtonLabel.fg = colors.muted;
|
|
6970
|
+
renderer.requestRender();
|
|
6971
|
+
};
|
|
6972
|
+
activeStatusMgr = createStatusManager(
|
|
6973
|
+
statusBar,
|
|
6974
|
+
() => renderer.requestRender()
|
|
6975
|
+
);
|
|
6976
|
+
const statusMgr = activeStatusMgr;
|
|
6977
|
+
renderer.on("destroy", () => statusMgr.dispose());
|
|
6678
6978
|
setTimeout(() => {
|
|
6679
6979
|
if (currentOverlay === "none") {
|
|
6680
6980
|
setStatus(nextTip());
|
|
@@ -7264,6 +7564,158 @@ ${pack.description ?? ""}`;
|
|
|
7264
7564
|
if (repo) openUrl(repo.url);
|
|
7265
7565
|
}
|
|
7266
7566
|
});
|
|
7567
|
+
attachClickToSelect(renderer, resultsSelect, {
|
|
7568
|
+
keepFocus: true,
|
|
7569
|
+
onOpen: () => resultsSelect.selectCurrent()
|
|
7570
|
+
});
|
|
7571
|
+
function activateOverlaySelection() {
|
|
7572
|
+
switch (currentOverlay) {
|
|
7573
|
+
case "history": {
|
|
7574
|
+
const sel = historySelect.getSelectedOption();
|
|
7575
|
+
if (sel?.value) {
|
|
7576
|
+
const entry = sel.value.entry;
|
|
7577
|
+
showOverlay("none");
|
|
7578
|
+
if (!entry) return;
|
|
7579
|
+
if (entry.mode === "trending") {
|
|
7580
|
+
if (entry.tab)
|
|
7581
|
+
trendingTab = entry.tab;
|
|
7582
|
+
loadTrending();
|
|
7583
|
+
} else {
|
|
7584
|
+
searchInput.value = entry.query;
|
|
7585
|
+
showSearchMode();
|
|
7586
|
+
doSearch(entry.query);
|
|
7587
|
+
}
|
|
7588
|
+
}
|
|
7589
|
+
return;
|
|
7590
|
+
}
|
|
7591
|
+
case "bookmarks": {
|
|
7592
|
+
const sel = bookmarksSelect.getSelectedOption();
|
|
7593
|
+
if (sel?.value)
|
|
7594
|
+
openUrl(sel.value.repo?.url ?? "");
|
|
7595
|
+
return;
|
|
7596
|
+
}
|
|
7597
|
+
case "saved": {
|
|
7598
|
+
const sel = savedSelect.getSelectedOption();
|
|
7599
|
+
if (sel?.value) {
|
|
7600
|
+
const s = sel.value;
|
|
7601
|
+
showOverlay("none");
|
|
7602
|
+
touchSavedSearch(s.name);
|
|
7603
|
+
if (s.mode === "trending") {
|
|
7604
|
+
if (s.tab) trendingTab = s.tab;
|
|
7605
|
+
loadTrending();
|
|
7606
|
+
} else {
|
|
7607
|
+
searchInput.value = s.query;
|
|
7608
|
+
showSearchMode();
|
|
7609
|
+
currentSort = s.sort;
|
|
7610
|
+
currentLimit = s.limit;
|
|
7611
|
+
setToolbar();
|
|
7612
|
+
doSearch(s.query);
|
|
7613
|
+
}
|
|
7614
|
+
}
|
|
7615
|
+
return;
|
|
7616
|
+
}
|
|
7617
|
+
case "topics": {
|
|
7618
|
+
const sel = topicsSelect.getSelectedOption();
|
|
7619
|
+
if (sel?.value) {
|
|
7620
|
+
const topic = sel.value;
|
|
7621
|
+
showOverlay("none");
|
|
7622
|
+
searchInput.value = `topic:${topic.name ?? ""}`;
|
|
7623
|
+
showSearchMode();
|
|
7624
|
+
doSearch(`topic:${topic.name}`);
|
|
7625
|
+
}
|
|
7626
|
+
return;
|
|
7627
|
+
}
|
|
7628
|
+
case "export": {
|
|
7629
|
+
const sel = exportSelect.getSelectedOption();
|
|
7630
|
+
if (sel?.value && currentRepos.length > 0) {
|
|
7631
|
+
const format2 = sel.value;
|
|
7632
|
+
const path = exportToFile(currentRepos, format2);
|
|
7633
|
+
showOverlay("none");
|
|
7634
|
+
setStatus(`\u2713 Exported to ${path}`);
|
|
7635
|
+
} else {
|
|
7636
|
+
setStatus("No results to export");
|
|
7637
|
+
showOverlay("none");
|
|
7638
|
+
}
|
|
7639
|
+
renderer.requestRender();
|
|
7640
|
+
return;
|
|
7641
|
+
}
|
|
7642
|
+
case "share": {
|
|
7643
|
+
const sel = shareSelect.getSelectedOption();
|
|
7644
|
+
if (sel?.value) {
|
|
7645
|
+
const opt = resultsSelect.getSelectedOption();
|
|
7646
|
+
const repo = opt?.value;
|
|
7647
|
+
if (repo) {
|
|
7648
|
+
const text = formatShare(repo, sel.value);
|
|
7649
|
+
copyToClipboard(text).then((ok) => {
|
|
7650
|
+
showOverlay("none");
|
|
7651
|
+
setStatus(ok ? "\u2713 Copied!" : "Clipboard not available");
|
|
7652
|
+
});
|
|
7653
|
+
}
|
|
7654
|
+
}
|
|
7655
|
+
renderer.requestRender();
|
|
7656
|
+
return;
|
|
7657
|
+
}
|
|
7658
|
+
case "help": {
|
|
7659
|
+
showOverlay("none");
|
|
7660
|
+
renderer.requestRender();
|
|
7661
|
+
return;
|
|
7662
|
+
}
|
|
7663
|
+
default:
|
|
7664
|
+
return;
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
function attachOverlayMouse(box, select) {
|
|
7668
|
+
attachClickToSelect(renderer, select, {
|
|
7669
|
+
onOpen: () => activateOverlaySelection(),
|
|
7670
|
+
onClickMiss: () => {
|
|
7671
|
+
showOverlay("none");
|
|
7672
|
+
renderer.requestRender();
|
|
7673
|
+
}
|
|
7674
|
+
});
|
|
7675
|
+
attachClickOutside(box, () => {
|
|
7676
|
+
showOverlay("none");
|
|
7677
|
+
renderer.requestRender();
|
|
7678
|
+
});
|
|
7679
|
+
}
|
|
7680
|
+
attachOverlayMouse(historyBox, historySelect);
|
|
7681
|
+
attachOverlayMouse(bookmarksBox, bookmarksSelect);
|
|
7682
|
+
attachOverlayMouse(savedBox, savedSelect);
|
|
7683
|
+
attachOverlayMouse(topicsBox, topicsSelect);
|
|
7684
|
+
attachOverlayMouse(exportBox, exportSelect);
|
|
7685
|
+
attachOverlayMouse(shareBox, shareSelect);
|
|
7686
|
+
for (const panel of [helpBox, orgBox, readmeBox, compareBox, notifsBox]) {
|
|
7687
|
+
attachClickOutside(panel, () => {
|
|
7688
|
+
showOverlay("none");
|
|
7689
|
+
renderer.requestRender();
|
|
7690
|
+
});
|
|
7691
|
+
}
|
|
7692
|
+
for (const scroller of [helpScroll, orgScroll, readmeScroll, updateScroll]) {
|
|
7693
|
+
scroller.onMouseScroll = (event) => {
|
|
7694
|
+
event.stopPropagation();
|
|
7695
|
+
};
|
|
7696
|
+
}
|
|
7697
|
+
attachClickToSelect(renderer, leaderSelect, {
|
|
7698
|
+
onOpen: () => {
|
|
7699
|
+
const entry = leaderSelect.getSelectedOption()?.value;
|
|
7700
|
+
if (!entry) return;
|
|
7701
|
+
if (entry.type === "category") {
|
|
7702
|
+
pushMenuLevel(` Menu > ${entry.name}`, entry.name, entry.children, 0);
|
|
7703
|
+
} else {
|
|
7704
|
+
resetMenu();
|
|
7705
|
+
showOverlay("none");
|
|
7706
|
+
entry.action();
|
|
7707
|
+
}
|
|
7708
|
+
renderer.requestRender();
|
|
7709
|
+
},
|
|
7710
|
+
onClickMiss: () => {
|
|
7711
|
+
showOverlay("none");
|
|
7712
|
+
renderer.requestRender();
|
|
7713
|
+
}
|
|
7714
|
+
});
|
|
7715
|
+
attachClickOutside(leaderDim, () => {
|
|
7716
|
+
showOverlay("none");
|
|
7717
|
+
renderer.requestRender();
|
|
7718
|
+
});
|
|
7267
7719
|
renderer.keyInput.on("keypress", (key) => {
|
|
7268
7720
|
if (tokenPromptBox.visible) {
|
|
7269
7721
|
if (key.name === "escape") {
|
|
@@ -7357,21 +7809,7 @@ ${pack.description ?? ""}`;
|
|
|
7357
7809
|
return;
|
|
7358
7810
|
}
|
|
7359
7811
|
if (key.name === "enter" || key.name === "return") {
|
|
7360
|
-
|
|
7361
|
-
if (sel?.value) {
|
|
7362
|
-
const entry = sel.value.entry;
|
|
7363
|
-
showOverlay("none");
|
|
7364
|
-
if (!entry) return;
|
|
7365
|
-
if (entry.mode === "trending") {
|
|
7366
|
-
if (entry.tab)
|
|
7367
|
-
trendingTab = entry.tab;
|
|
7368
|
-
loadTrending();
|
|
7369
|
-
} else {
|
|
7370
|
-
searchInput.value = entry.query;
|
|
7371
|
-
showSearchMode();
|
|
7372
|
-
doSearch(entry.query);
|
|
7373
|
-
}
|
|
7374
|
-
}
|
|
7812
|
+
activateOverlaySelection();
|
|
7375
7813
|
return;
|
|
7376
7814
|
}
|
|
7377
7815
|
return;
|
|
@@ -7390,9 +7828,7 @@ ${pack.description ?? ""}`;
|
|
|
7390
7828
|
return;
|
|
7391
7829
|
}
|
|
7392
7830
|
if (key.name === "enter" || key.name === "return") {
|
|
7393
|
-
|
|
7394
|
-
if (sel?.value)
|
|
7395
|
-
openUrl(sel.value.repo?.url ?? "");
|
|
7831
|
+
activateOverlaySelection();
|
|
7396
7832
|
return;
|
|
7397
7833
|
}
|
|
7398
7834
|
return;
|
|
@@ -7409,54 +7845,21 @@ ${pack.description ?? ""}`;
|
|
|
7409
7845
|
return;
|
|
7410
7846
|
}
|
|
7411
7847
|
if (key.name === "enter" || key.name === "return") {
|
|
7412
|
-
|
|
7413
|
-
if (sel?.value) {
|
|
7414
|
-
const s = sel.value;
|
|
7415
|
-
showOverlay("none");
|
|
7416
|
-
touchSavedSearch(s.name);
|
|
7417
|
-
if (s.mode === "trending") {
|
|
7418
|
-
if (s.tab) trendingTab = s.tab;
|
|
7419
|
-
loadTrending();
|
|
7420
|
-
} else {
|
|
7421
|
-
searchInput.value = s.query;
|
|
7422
|
-
showSearchMode();
|
|
7423
|
-
currentSort = s.sort;
|
|
7424
|
-
currentLimit = s.limit;
|
|
7425
|
-
setToolbar();
|
|
7426
|
-
doSearch(s.query);
|
|
7427
|
-
}
|
|
7428
|
-
}
|
|
7848
|
+
activateOverlaySelection();
|
|
7429
7849
|
return;
|
|
7430
7850
|
}
|
|
7431
7851
|
return;
|
|
7432
7852
|
}
|
|
7433
7853
|
if (currentOverlay === "topics") {
|
|
7434
7854
|
if (key.name === "enter" || key.name === "return") {
|
|
7435
|
-
|
|
7436
|
-
if (sel?.value) {
|
|
7437
|
-
const topic = sel.value;
|
|
7438
|
-
showOverlay("none");
|
|
7439
|
-
searchInput.value = `topic:${topic.name ?? ""}`;
|
|
7440
|
-
showSearchMode();
|
|
7441
|
-
doSearch(`topic:${topic.name}`);
|
|
7442
|
-
}
|
|
7855
|
+
activateOverlaySelection();
|
|
7443
7856
|
return;
|
|
7444
7857
|
}
|
|
7445
7858
|
return;
|
|
7446
7859
|
}
|
|
7447
7860
|
if (currentOverlay === "export") {
|
|
7448
7861
|
if (key.name === "enter" || key.name === "return") {
|
|
7449
|
-
|
|
7450
|
-
if (sel?.value && currentRepos.length > 0) {
|
|
7451
|
-
const format2 = sel.value;
|
|
7452
|
-
const path = exportToFile(currentRepos, format2);
|
|
7453
|
-
showOverlay("none");
|
|
7454
|
-
setStatus(`\u2713 Exported to ${path}`);
|
|
7455
|
-
} else {
|
|
7456
|
-
setStatus("No results to export");
|
|
7457
|
-
showOverlay("none");
|
|
7458
|
-
}
|
|
7459
|
-
renderer.requestRender();
|
|
7862
|
+
activateOverlaySelection();
|
|
7460
7863
|
return;
|
|
7461
7864
|
}
|
|
7462
7865
|
return;
|
|
@@ -7485,26 +7888,13 @@ ${pack.description ?? ""}`;
|
|
|
7485
7888
|
}
|
|
7486
7889
|
if (currentOverlay === "share") {
|
|
7487
7890
|
if (key.name === "enter" || key.name === "return") {
|
|
7488
|
-
|
|
7489
|
-
if (sel?.value) {
|
|
7490
|
-
const opt = resultsSelect.getSelectedOption();
|
|
7491
|
-
const repo = opt?.value;
|
|
7492
|
-
if (repo) {
|
|
7493
|
-
const text = formatShare(repo, sel.value);
|
|
7494
|
-
copyToClipboard(text).then((ok) => {
|
|
7495
|
-
showOverlay("none");
|
|
7496
|
-
setStatus(ok ? "\u2713 Copied!" : "Clipboard not available");
|
|
7497
|
-
});
|
|
7498
|
-
}
|
|
7499
|
-
}
|
|
7500
|
-
renderer.requestRender();
|
|
7891
|
+
activateOverlaySelection();
|
|
7501
7892
|
return;
|
|
7502
7893
|
}
|
|
7503
7894
|
return;
|
|
7504
7895
|
}
|
|
7505
7896
|
if (currentOverlay === "help") {
|
|
7506
|
-
|
|
7507
|
-
renderer.requestRender();
|
|
7897
|
+
activateOverlaySelection();
|
|
7508
7898
|
return;
|
|
7509
7899
|
}
|
|
7510
7900
|
if (currentOverlay === "update") {
|
|
@@ -7529,29 +7919,7 @@ ${pack.description ?? ""}`;
|
|
|
7529
7919
|
return;
|
|
7530
7920
|
}
|
|
7531
7921
|
if (key.name === "enter" || key.name === "return") {
|
|
7532
|
-
|
|
7533
|
-
if (action === "now") {
|
|
7534
|
-
showOverlay("none");
|
|
7535
|
-
recordPreUpdateState(cachedVersion ?? "");
|
|
7536
|
-
performUpdate().then((ok) => {
|
|
7537
|
-
if (ok) {
|
|
7538
|
-
setStatus("\u2713 Update complete \u2014 restart ghfind");
|
|
7539
|
-
} else {
|
|
7540
|
-
setStatus("\u2717 Update failed \u2014 check terminal output");
|
|
7541
|
-
}
|
|
7542
|
-
}).catch(() => {
|
|
7543
|
-
setStatus("\u2717 Update failed \u2014 check terminal output");
|
|
7544
|
-
});
|
|
7545
|
-
} else if (action === "never") {
|
|
7546
|
-
suppressUpdateNotices();
|
|
7547
|
-
showOverlay("none");
|
|
7548
|
-
setStatus("Update notices suppressed");
|
|
7549
|
-
} else {
|
|
7550
|
-
snoozeUpdateNotices(3);
|
|
7551
|
-
showOverlay("none");
|
|
7552
|
-
setStatus("Update reminder snoozed for 3 days");
|
|
7553
|
-
}
|
|
7554
|
-
renderer.requestRender();
|
|
7922
|
+
runUpdateOption(updateSelectedOption);
|
|
7555
7923
|
return;
|
|
7556
7924
|
}
|
|
7557
7925
|
return;
|
|
@@ -7574,8 +7942,14 @@ ${pack.description ?? ""}`;
|
|
|
7574
7942
|
toggleGraph();
|
|
7575
7943
|
return;
|
|
7576
7944
|
}
|
|
7577
|
-
if (key.name === "
|
|
7578
|
-
|
|
7945
|
+
if (key.name === "escape") {
|
|
7946
|
+
if (currentOverlay !== "none") {
|
|
7947
|
+
showOverlay("none");
|
|
7948
|
+
setToolbar();
|
|
7949
|
+
} else {
|
|
7950
|
+
showLeaderMenu();
|
|
7951
|
+
}
|
|
7952
|
+
renderer.requestRender();
|
|
7579
7953
|
return;
|
|
7580
7954
|
}
|
|
7581
7955
|
if (!searchInput.focused && errorHint) {
|
|
@@ -7693,7 +8067,12 @@ ${pack.description ?? ""}`;
|
|
|
7693
8067
|
}
|
|
7694
8068
|
});
|
|
7695
8069
|
const _currentVersion = getVersion();
|
|
7696
|
-
|
|
8070
|
+
if (startMode === "trending") {
|
|
8071
|
+
showLanding(false);
|
|
8072
|
+
loadTrending();
|
|
8073
|
+
} else {
|
|
8074
|
+
showLanding(true);
|
|
8075
|
+
}
|
|
7697
8076
|
checkForUpdateAndShow();
|
|
7698
8077
|
checkPostUpgradePanel();
|
|
7699
8078
|
renderer.start();
|
|
@@ -7710,10 +8089,17 @@ function formatToolbar(sort, limit, totalCount) {
|
|
|
7710
8089
|
return ` sort: ${sortLabel} limit: ${limit} results: ${totalCount.toLocaleString()}`;
|
|
7711
8090
|
}
|
|
7712
8091
|
function cleanup() {
|
|
8092
|
+
activeStatusMgr?.dispose();
|
|
8093
|
+
activeStatusMgr = null;
|
|
7713
8094
|
try {
|
|
7714
8095
|
rotateHistory();
|
|
7715
8096
|
} catch {
|
|
7716
8097
|
}
|
|
8098
|
+
try {
|
|
8099
|
+
activeRenderer?.destroy();
|
|
8100
|
+
} catch {
|
|
8101
|
+
}
|
|
8102
|
+
activeRenderer = null;
|
|
7717
8103
|
process.exit(0);
|
|
7718
8104
|
}
|
|
7719
8105
|
if (import.meta.main && false) {
|
|
@@ -8385,7 +8771,7 @@ var TOOLS = [
|
|
|
8385
8771
|
token: resolveToken(state, args.token),
|
|
8386
8772
|
limit
|
|
8387
8773
|
});
|
|
8388
|
-
return { text:
|
|
8774
|
+
return { text: formatUserText(profile), data: { ...profile } };
|
|
8389
8775
|
}
|
|
8390
8776
|
},
|
|
8391
8777
|
{
|
|
@@ -8732,6 +9118,7 @@ var SORT_VALUES = [
|
|
|
8732
9118
|
"downloads",
|
|
8733
9119
|
"name"
|
|
8734
9120
|
];
|
|
9121
|
+
var SINCE_VALUES = ["daily", "weekly", "monthly"];
|
|
8735
9122
|
function parseArgs(args) {
|
|
8736
9123
|
const flags = {
|
|
8737
9124
|
query: "",
|
|
@@ -8744,6 +9131,7 @@ function parseArgs(args) {
|
|
|
8744
9131
|
token: process.env.GITHUB_TOKEN,
|
|
8745
9132
|
trending: false,
|
|
8746
9133
|
since: "daily",
|
|
9134
|
+
sinceExplicit: false,
|
|
8747
9135
|
watch: false,
|
|
8748
9136
|
releases: false,
|
|
8749
9137
|
interval: 300,
|
|
@@ -8844,15 +9232,51 @@ function parseArgs(args) {
|
|
|
8844
9232
|
case "--token":
|
|
8845
9233
|
flags.token = args[++i];
|
|
8846
9234
|
break;
|
|
8847
|
-
case "--
|
|
8848
|
-
|
|
9235
|
+
case "--interval": {
|
|
9236
|
+
const parsed = parseInt(args[++i], 10);
|
|
9237
|
+
if (Number.isNaN(parsed) || parsed < 1) {
|
|
9238
|
+
console.error(
|
|
9239
|
+
`Invalid interval: ${args[i] ?? "(missing)"} (must be a whole number of seconds, e.g. 300).`
|
|
9240
|
+
);
|
|
9241
|
+
process.exit(1);
|
|
9242
|
+
}
|
|
9243
|
+
flags.interval = parsed;
|
|
9244
|
+
break;
|
|
9245
|
+
}
|
|
9246
|
+
case "--since": {
|
|
9247
|
+
const since = args[++i];
|
|
9248
|
+
if (!since || !SINCE_VALUES.includes(since)) {
|
|
9249
|
+
console.error(
|
|
9250
|
+
`Invalid since: ${since ?? "(missing)"} (use daily|weekly|monthly).`
|
|
9251
|
+
);
|
|
9252
|
+
process.exit(1);
|
|
9253
|
+
}
|
|
9254
|
+
flags.since = since;
|
|
9255
|
+
flags.sinceExplicit = true;
|
|
8849
9256
|
break;
|
|
8850
|
-
|
|
8851
|
-
|
|
9257
|
+
}
|
|
9258
|
+
case "--pipe": {
|
|
9259
|
+
const target = args[++i];
|
|
9260
|
+
if (!target || !PIPE_TARGETS.includes(target)) {
|
|
9261
|
+
console.error(
|
|
9262
|
+
`Invalid pipe target: ${target ?? "(missing)"} (use open|clone).`
|
|
9263
|
+
);
|
|
9264
|
+
process.exit(1);
|
|
9265
|
+
}
|
|
9266
|
+
flags.pipe = target;
|
|
8852
9267
|
break;
|
|
8853
|
-
|
|
8854
|
-
|
|
9268
|
+
}
|
|
9269
|
+
case "--format": {
|
|
9270
|
+
const fmt = args[++i];
|
|
9271
|
+
if (!fmt || !FORMAT_VALUES.includes(fmt)) {
|
|
9272
|
+
console.error(
|
|
9273
|
+
`Invalid format: ${fmt ?? "(missing)"} (use ${FORMAT_VALUES.join("|")}).`
|
|
9274
|
+
);
|
|
9275
|
+
process.exit(1);
|
|
9276
|
+
}
|
|
9277
|
+
flags.format = fmt;
|
|
8855
9278
|
break;
|
|
9279
|
+
}
|
|
8856
9280
|
case "--registry":
|
|
8857
9281
|
flags.registry = args[++i] ?? "npm";
|
|
8858
9282
|
break;
|
|
@@ -9141,7 +9565,13 @@ Options:
|
|
|
9141
9565
|
await runNonInteractive(flags, outputFormat);
|
|
9142
9566
|
return;
|
|
9143
9567
|
}
|
|
9144
|
-
await launchBrowser(
|
|
9568
|
+
await launchBrowser(
|
|
9569
|
+
flags.theme,
|
|
9570
|
+
// `ghfind --trending` with no query/format promises the trending view
|
|
9571
|
+
// (TRACKER.md), but the bare flag used to fall through to the landing
|
|
9572
|
+
// menu. An explicit flag is explicit intent — skip the menu.
|
|
9573
|
+
flags.trending ? "trending" : void 0
|
|
9574
|
+
);
|
|
9145
9575
|
}
|
|
9146
9576
|
function buildSearchContext(flags) {
|
|
9147
9577
|
const parsed = applyFlagFilters(parseQuery(flags.query), {});
|
|
@@ -9606,7 +10036,8 @@ async function runNonInteractive(flags, outputFormat) {
|
|
|
9606
10036
|
limit: flags.limit,
|
|
9607
10037
|
token: flags.token,
|
|
9608
10038
|
intervalMs: flags.interval * 1e3,
|
|
9609
|
-
trending: flags.trending
|
|
10039
|
+
trending: flags.trending,
|
|
10040
|
+
since: flags.sinceExplicit ? flags.since : void 0
|
|
9610
10041
|
},
|
|
9611
10042
|
(repos, delta) => {
|
|
9612
10043
|
tick++;
|
|
@@ -9694,6 +10125,16 @@ Not found: ${missing.join(", ")}` : "";
|
|
|
9694
10125
|
}
|
|
9695
10126
|
};
|
|
9696
10127
|
const key = flags.compare.length > 0 ? "compare" : flags.trending && !flags.watch ? "trending" : flags.watch ? "watch" : flags.pipe ? "pipe" : flags.format ? "format" : "search";
|
|
10128
|
+
const needsQuery = key === "search" || key === "format" || key === "pipe" || key === "watch" && !flags.trending;
|
|
10129
|
+
if (needsQuery && flags.query.trim() === "") {
|
|
10130
|
+
console.error("\u26A0 No search query given.");
|
|
10131
|
+
console.error(
|
|
10132
|
+
' Usage: ghfind "<query>" [--count|--format <fmt>|--pipe <tgt>|--watch]'
|
|
10133
|
+
);
|
|
10134
|
+
console.error(' Example: ghfind "language:Rust stars:>500" --count');
|
|
10135
|
+
console.error(" Run `ghfind --help` for all options.");
|
|
10136
|
+
process.exit(1);
|
|
10137
|
+
}
|
|
9697
10138
|
const ctx = buildSearchContext(flags);
|
|
9698
10139
|
await handlers[key](ctx);
|
|
9699
10140
|
}
|