优化卡死的问题
This commit is contained in:
@ -1,5 +1,9 @@
|
||||
import color from "picocolors";
|
||||
import { initKeypress, onKey } from "../keyboard.js";
|
||||
import { initKeypress, onKey, stopKeypress } from "../keyboard.js";
|
||||
|
||||
function clearScreen() {
|
||||
process.stdout.write('\x1Bc');
|
||||
}
|
||||
|
||||
export function createStepUI(options) {
|
||||
const { title, getSteps } = options;
|
||||
@ -9,6 +13,7 @@ export function createStepUI(options) {
|
||||
let completed = new Set();
|
||||
let currentStep = 0;
|
||||
let currentOption = 0;
|
||||
let resolved = false;
|
||||
|
||||
function initResults() {
|
||||
steps = typeof getSteps === "function" ? getSteps() : getSteps;
|
||||
@ -16,6 +21,7 @@ export function createStepUI(options) {
|
||||
completed = new Set();
|
||||
currentStep = 0;
|
||||
currentOption = 0;
|
||||
resolved = false;
|
||||
}
|
||||
|
||||
function renderNav() {
|
||||
@ -35,13 +41,10 @@ export function createStepUI(options) {
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
// 计算可显示的行数(终端高度 - 标题/导航/提示占用的行数)
|
||||
const termHeight = process.stdout.rows || 24;
|
||||
const reservedLines = 8;
|
||||
const maxVisible = Math.max(5, termHeight - reservedLines);
|
||||
const maxVisible = Math.max(5, termHeight - 8);
|
||||
const total = step.options.length;
|
||||
|
||||
// 计算滚动窗口
|
||||
let start = 0;
|
||||
if (total > maxVisible) {
|
||||
start = Math.max(0, Math.min(currentOption - Math.floor(maxVisible / 2), total - maxVisible));
|
||||
@ -71,38 +74,42 @@ export function createStepUI(options) {
|
||||
}
|
||||
|
||||
function render() {
|
||||
process.stdout.write('\x1Bc');
|
||||
clearScreen();
|
||||
console.log(color.bgCyan(color.black(` ${title} `)));
|
||||
console.log("\n" + renderNav());
|
||||
console.log(color.dim("\n← → 切换步骤 | ↑ ↓ 选择 | Space 选中 | Tab 提交 | Esc 返回\n"));
|
||||
console.log(renderOptions());
|
||||
}
|
||||
|
||||
function runInteractive() {
|
||||
initResults();
|
||||
initKeypress();
|
||||
return new Promise(resolve => {
|
||||
render();
|
||||
onKey((str, key) => {
|
||||
if (!key) return;
|
||||
const step = steps[currentStep];
|
||||
const optCount = step.options?.length || 0;
|
||||
if (key.name === "left") {
|
||||
if (currentStep > 0) { currentStep--; currentOption = 0; }
|
||||
render();
|
||||
} else if (key.name === "right") {
|
||||
if (currentStep < steps.length - 1) { currentStep++; currentOption = 0; }
|
||||
render();
|
||||
} else if (key.name === "up") {
|
||||
if (!optCount) return;
|
||||
function handleKey(key, resolve) {
|
||||
if (!key || resolved) return;
|
||||
|
||||
const step = steps[currentStep];
|
||||
const optCount = step.options?.length || 0;
|
||||
|
||||
switch (key.name) {
|
||||
case "left":
|
||||
if (currentStep > 0) { currentStep--; currentOption = 0; }
|
||||
render();
|
||||
break;
|
||||
case "right":
|
||||
if (currentStep < steps.length - 1) { currentStep++; currentOption = 0; }
|
||||
render();
|
||||
break;
|
||||
case "up":
|
||||
if (optCount) {
|
||||
currentOption = (currentOption - 1 + optCount) % optCount;
|
||||
render();
|
||||
} else if (key.name === "down") {
|
||||
if (!optCount) return;
|
||||
}
|
||||
break;
|
||||
case "down":
|
||||
if (optCount) {
|
||||
currentOption = (currentOption + 1) % optCount;
|
||||
render();
|
||||
} else if (key.name === "space") {
|
||||
if (!optCount) return;
|
||||
}
|
||||
break;
|
||||
case "space":
|
||||
if (optCount) {
|
||||
const opt = step.options[currentOption];
|
||||
if (step.type === "multiselect") {
|
||||
const list = results[currentStep];
|
||||
@ -114,25 +121,48 @@ export function createStepUI(options) {
|
||||
}
|
||||
completed.add(currentStep);
|
||||
render();
|
||||
} else if (key.name === "return") {
|
||||
if (!optCount) return;
|
||||
if (step.type === "select") {
|
||||
results[currentStep] = step.options[currentOption].value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "return":
|
||||
if (optCount && step.type === "select") {
|
||||
results[currentStep] = step.options[currentOption].value;
|
||||
completed.add(currentStep);
|
||||
if (currentStep < steps.length - 1) { currentStep++; currentOption = 0; }
|
||||
render();
|
||||
} else if (key.name === "tab") {
|
||||
resolve({ steps, results });
|
||||
} else if (key.name === "escape" || (key.ctrl && key.name === "c")) {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "tab":
|
||||
resolved = true;
|
||||
stopKeypress();
|
||||
setImmediate(() => resolve({ steps, results }));
|
||||
break;
|
||||
case "escape":
|
||||
resolved = true;
|
||||
stopKeypress();
|
||||
setImmediate(() => resolve(null));
|
||||
break;
|
||||
case "c":
|
||||
if (key.ctrl) {
|
||||
resolved = true;
|
||||
stopKeypress();
|
||||
setImmediate(() => resolve(null));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function runInteractive() {
|
||||
initResults();
|
||||
initKeypress();
|
||||
|
||||
return new Promise(resolve => {
|
||||
render();
|
||||
onKey((str, key) => handleKey(key, resolve));
|
||||
});
|
||||
}
|
||||
|
||||
function showSummary(lines) {
|
||||
console.clear();
|
||||
clearScreen();
|
||||
console.log(color.bgCyan(color.black(` ${title} `)));
|
||||
console.log("\n" + color.green("配置完成!当前设置:"));
|
||||
lines.forEach(line => console.log(" " + line));
|
||||
|
||||
Reference in New Issue
Block a user