优化卡死的问题

This commit is contained in:
yinsx
2025-12-20 14:13:59 +08:00
parent 3098796a08
commit ad60f8c3ec
7 changed files with 495 additions and 108 deletions

View File

@ -1,17 +1,10 @@
import color from "picocolors";
import { initKeypress, onKey } from "./keyboard.js";
import { initKeypress, onKey, stopKeypress } from "./keyboard.js";
function clearScreen() {
if (process.stdout.isTTY) {
process.stdout.write("\x1b[2J"); // clear screen
process.stdout.write("\x1b[3J"); // clear scrollback
process.stdout.write("\x1b[H"); // move cursor home
} else {
console.clear();
}
process.stdout.write('\x1Bc');
}
// 计算字符串显示宽度
function strWidth(str) {
let width = 0;
for (const char of str) {
@ -20,25 +13,21 @@ function strWidth(str) {
return width;
}
// 右填充到指定宽度
function padEnd(str, width) {
const diff = width - strWidth(str);
return str + " ".repeat(Math.max(0, diff));
return str + " ".repeat(Math.max(0, width - strWidth(str)));
}
/**
* 网格选择菜单
*/
export async function gridSelect(options) {
const {
items,
cols = 3,
const {
items,
cols = 3,
colWidth = 24,
title = "",
renderHeader = null
renderHeader = null
} = options;
let current = 0;
let resolved = false;
const rows = Math.ceil(items.length / cols);
const termWidth = process.stdout.columns || 80;
const totalWidth = cols * colWidth;
@ -46,83 +35,90 @@ export async function gridSelect(options) {
function render() {
clearScreen();
if (renderHeader) {
console.log(renderHeader());
}
console.log("");
if (title) {
const titlePad = " ".repeat(Math.max(0, Math.floor((termWidth - title.length - 4) / 2)));
console.log(titlePad + color.bgMagenta(color.white(` ${title} `)));
}
console.log("");
console.log(pad + color.dim("↑ ↓ ← → 选择 | Enter 确认 | Esc 退出"));
console.log("");
console.log("");
console.log("\n");
for (let row = 0; row < rows; row++) {
let line = "";
let descLine = "";
for (let col = 0; col < cols; col++) {
const idx = row * cols + col;
if (idx < items.length) {
const item = items[idx];
if (idx === current) {
line += color.cyan("[" + item.name + "]");
line += " ".repeat(colWidth - strWidth(item.name) - 2);
} else {
line += " " + item.name + " ";
line += " ".repeat(colWidth - strWidth(item.name) - 2);
}
line += " ".repeat(colWidth - strWidth(item.name) - 2);
descLine += padEnd(item.desc || "", colWidth);
}
}
console.log(pad + line);
let descLine = "";
for (let col = 0; col < cols; col++) {
const idx = row * cols + col;
if (idx < items.length) {
descLine += padEnd(items[idx].desc || "", colWidth);
}
}
console.log(pad + color.dim(descLine));
console.log("");
console.log("");
console.log("\n");
}
}
initKeypress();
return new Promise((resolve) => {
return new Promise(resolve => {
initKeypress();
render();
onKey((str, key) => {
if (!key) return;
if (!key || resolved) return;
const row = Math.floor(current / cols);
const col = current % cols;
if (key.name === "up" && row > 0) {
current -= cols;
render();
} else if (key.name === "down" && row < rows - 1 && current + cols < items.length) {
current += cols;
render();
} else if (key.name === "left" && col > 0) {
current--;
render();
} else if (key.name === "right" && col < cols - 1 && current < items.length - 1) {
current++;
render();
} else if (key.name === "return") {
setImmediate(() => resolve(items[current]));
} else if (key.name === "escape" || (key.ctrl && key.name === "c")) {
process.stdin.setRawMode(false);
clearScreen();
console.log(color.yellow("👋 再见!"));
process.exit(0);
switch (key.name) {
case "up":
if (row > 0) { current -= cols; render(); }
break;
case "down":
if (row < rows - 1 && current + cols < items.length) { current += cols; render(); }
break;
case "left":
if (col > 0) { current--; render(); }
break;
case "right":
if (col < cols - 1 && current < items.length - 1) { current++; render(); }
break;
case "return":
resolved = true;
stopKeypress();
setImmediate(() => resolve(items[current]));
break;
case "escape":
resolved = true;
stopKeypress();
clearScreen();
console.log(color.yellow("再见!"));
process.exit(0);
break;
case "c":
if (key.ctrl) {
resolved = true;
stopKeypress();
clearScreen();
console.log(color.yellow("再见!"));
process.exit(0);
}
break;
}
});
});