@getparallel/parx 0.4.1 → 0.4.3
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 +25 -0
- package/README.md +20 -2
- package/dist/agente.js +9 -6
- package/dist/api.js +6 -0
- package/dist/bash.js +89 -0
- package/dist/cli.js +206 -16
- package/dist/consejos.js +4 -1
- package/dist/herramientas.js +12 -8
- package/dist/informe.js +6 -0
- package/dist/marca.js +26 -0
- package/dist/textos.js +50 -2
- package/dist/tui.js +693 -140
- package/dist/ui.js +66 -22
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { animacion, c, capacidades, sep, cabezaDePar, caraDePar, carril, fijarCapacidades, signo, ANCHO_DE_PAR, SIMBOLOS } from "./marca.js";
|
|
1
|
+
import { animacion, c, capacidades, colorDeModo, sep, cabezaDePar, caraDePar, carril, fijarCapacidades, signo, ANCHO_DE_PAR, SIMBOLOS } from "./marca.js";
|
|
2
2
|
import { anchoDe, envolver, puntos, recortar, rellenar } from "./texto.js";
|
|
3
3
|
import { ALIAS_COMANDO, COMANDOS, t as tt } from "./textos.js";
|
|
4
4
|
import { MODELOS, ORDEN_DE_MODELOS } from "./modelos.js";
|
|
@@ -24,6 +24,33 @@ export function bloqueDeTexto(texto, sangria = '') {
|
|
|
24
24
|
return out;
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
export function bloqueDeTabla(filas, o = {}) {
|
|
28
|
+
return (ancho) => {
|
|
29
|
+
const util = anchoUtil(ancho);
|
|
30
|
+
const sangria = ' '.repeat(o.sangria ?? 0);
|
|
31
|
+
const dentro = util - sangria.length;
|
|
32
|
+
const col = Math.min(Math.max(0, ...filas.map(([k]) => anchoDe(k))) + 3, Math.floor(dentro / 2));
|
|
33
|
+
const out = [];
|
|
34
|
+
if (o.titulo)
|
|
35
|
+
out.push(`${m}${c.negrita(o.titulo)}`);
|
|
36
|
+
for (const [k, d] of filas) {
|
|
37
|
+
const resto = dentro - col;
|
|
38
|
+
if (resto < 12) {
|
|
39
|
+
out.push(`${m}${sangria}${c.marca(recortar(k, dentro))}`);
|
|
40
|
+
for (const l of envolver(d, dentro - 2))
|
|
41
|
+
out.push(`${m}${sangria} ${l}`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
envolver(d, resto).forEach((l, i) => out.push(`${m}${sangria}${i === 0 ? c.marca(rellenar(recortar(k, col - 1), col)) : ' '.repeat(col)}${l}`));
|
|
45
|
+
}
|
|
46
|
+
if (o.pie) {
|
|
47
|
+
out.push('');
|
|
48
|
+
for (const l of envolver(o.pie, util))
|
|
49
|
+
out.push(`${m}${c.gris(l)}`);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
27
54
|
export function bloqueDeLinea(linea) {
|
|
28
55
|
return (ancho) => [`${m}${recortar(linea, anchoUtil(ancho))}`];
|
|
29
56
|
}
|
|
@@ -108,6 +135,26 @@ export function bloqueDeCierre(texto, marca) {
|
|
|
108
135
|
return [`${m}${izq}${resto > 0 ? ` ${c.tenue(c.gris((capacidades().unicode ? '─' : '-').repeat(resto)))}` : ''}`];
|
|
109
136
|
};
|
|
110
137
|
}
|
|
138
|
+
export function bloqueDeBash(comando) {
|
|
139
|
+
return (ancho) => {
|
|
140
|
+
const util = anchoUtil(ancho);
|
|
141
|
+
return ['', ...envolver(comando, util - 2).map((l, i) => `${m}${i === 0 ? c.bash(c.negrita('!')) : ' '} ${l}`)];
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
export function bloqueDeSalidaDeBash(lineas) {
|
|
145
|
+
return (ancho) => {
|
|
146
|
+
const util = anchoUtil(ancho);
|
|
147
|
+
const raya = c.tenue(c.bash(capacidades().unicode ? '│' : '|'));
|
|
148
|
+
return lineas.map((l) => `${m}${raya} ${recortar(l.replace(/\t/g, ' '), util - 2)}`);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function bloqueDeFinDeBash(bien, texto) {
|
|
152
|
+
return (ancho) => {
|
|
153
|
+
const u = capacidades().unicode;
|
|
154
|
+
const marca = bien ? c.ok(u ? '✓' : 'v') : c.error(u ? '✗' : 'x');
|
|
155
|
+
return [`${m}${c.tenue(c.bash(u ? '╰' : '`'))} ${marca} ${recortar(c.gris(texto), anchoUtil(ancho) - 4)}`];
|
|
156
|
+
};
|
|
157
|
+
}
|
|
111
158
|
export function trocearTeclas(datos, estado) {
|
|
112
159
|
const out = [];
|
|
113
160
|
let i = 0;
|
|
@@ -125,6 +172,20 @@ export function trocearTeclas(datos, estado) {
|
|
|
125
172
|
}
|
|
126
173
|
const ch = datos[i];
|
|
127
174
|
if (ch === '\x1b') {
|
|
175
|
+
const sgr = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])/.exec(datos.slice(i));
|
|
176
|
+
if (sgr) {
|
|
177
|
+
i += sgr[0].length;
|
|
178
|
+
out.push(teclaDeRaton(Number(sgr[1]), Number(sgr[2]), Number(sgr[3]), sgr[4] === 'm'));
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (datos.startsWith('\x1b[M', i) && datos.length >= i + 6) {
|
|
182
|
+
const b = datos.charCodeAt(i + 3) - 32;
|
|
183
|
+
const x = datos.charCodeAt(i + 4) - 32;
|
|
184
|
+
const y = datos.charCodeAt(i + 5) - 32;
|
|
185
|
+
i += 6;
|
|
186
|
+
out.push(teclaDeRaton(b, x, y, (b & 3) === 3 && (b & 64) === 0 && (b & 32) === 0, b & 64 ? 3 : b & 3));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
128
189
|
const r = /^\x1b(?:\[([0-9;?]*)([ -/]*[@-~])|O([@-~])|([\s\S]))?/.exec(datos.slice(i));
|
|
129
190
|
const seq = r[0];
|
|
130
191
|
i += Math.max(1, seq.length);
|
|
@@ -147,10 +208,16 @@ export function trocearTeclas(datos, estado) {
|
|
|
147
208
|
out.push({ t: 'abajo' });
|
|
148
209
|
else if (fin === 'H' || (fin === '~' && (params === '1' || params === '7')))
|
|
149
210
|
out.push({ t: 'inicio' });
|
|
211
|
+
else if ((fin === 'F' && /;5$/.test(params)) || (fin === '~' && /^[48];5$/.test(params)))
|
|
212
|
+
out.push({ t: 'fondo' });
|
|
150
213
|
else if (fin === 'F' || (fin === '~' && (params === '4' || params === '8')))
|
|
151
214
|
out.push({ t: 'fin' });
|
|
152
215
|
else if (fin === '~' && params === '3')
|
|
153
216
|
out.push({ t: 'suprimir' });
|
|
217
|
+
else if (fin === '~' && params === '5')
|
|
218
|
+
out.push({ t: 'pagina_arriba' });
|
|
219
|
+
else if (fin === '~' && params === '6')
|
|
220
|
+
out.push({ t: 'pagina_abajo' });
|
|
154
221
|
else if (fin === 'Z')
|
|
155
222
|
out.push({ t: 'cambiar' });
|
|
156
223
|
else if (fin === 'I' && params === '')
|
|
@@ -194,6 +261,8 @@ export function trocearTeclas(datos, estado) {
|
|
|
194
261
|
out.push({ t: 'borrar_palabra' });
|
|
195
262
|
else if (ch === '\x0c')
|
|
196
263
|
out.push({ t: 'limpiar' });
|
|
264
|
+
else if (ch === '\x1a')
|
|
265
|
+
out.push({ t: 'suspender' });
|
|
197
266
|
else if (ch === '\x10')
|
|
198
267
|
out.push({ t: 'arriba' });
|
|
199
268
|
else if (ch === '\x0e')
|
|
@@ -210,8 +279,17 @@ export function trocearTeclas(datos, estado) {
|
|
|
210
279
|
}
|
|
211
280
|
return out;
|
|
212
281
|
}
|
|
213
|
-
|
|
282
|
+
function teclaDeRaton(b, x, y, soltar, botonX10) {
|
|
283
|
+
const rueda = b & 64 ? ((b & 1) === 0 ? -1 : 1) : 0;
|
|
284
|
+
const mover = Boolean(b & 32);
|
|
285
|
+
const boton = botonX10 ?? (rueda ? 3 : b & 3);
|
|
286
|
+
return { t: 'raton', boton, x, y, soltar, mover, rueda: rueda };
|
|
287
|
+
}
|
|
288
|
+
export const RATON_SI = '\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h';
|
|
289
|
+
export const RATON_NO = '\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?1006l';
|
|
290
|
+
const CON_VALOR = new Set(['mode', 'model', 'tips', 'notify', 'teach', 'mouse']);
|
|
214
291
|
const CON_TEXTO = new Set(['folder']);
|
|
292
|
+
const SE_MANDAN_SOLOS = new Set(['teach', 'notify', 'tips', 'folder', 'mouse']);
|
|
215
293
|
const MODOS_DEL_MENU = ['ask', 'auto', 'read', 'bypass'];
|
|
216
294
|
export function opcionesDelMenu(valor) {
|
|
217
295
|
if (!valor.startsWith('/') || valor.includes('\n'))
|
|
@@ -226,7 +304,8 @@ export function opcionesDelMenu(valor) {
|
|
|
226
304
|
if (!casa)
|
|
227
305
|
continue;
|
|
228
306
|
const conAlgo = CON_VALOR.has(cmd) || CON_TEXTO.has(cmd);
|
|
229
|
-
|
|
307
|
+
const entero = q === cmd || ALIAS_COMANDO[q] === cmd;
|
|
308
|
+
out.push({ nombre: `/${cmd}`, descripcion, completar: `/${cmd}${conAlgo ? ' ' : ''}`, enviar: !conAlgo || (entero && SE_MANDAN_SOLOS.has(cmd)) });
|
|
230
309
|
}
|
|
231
310
|
return out;
|
|
232
311
|
}
|
|
@@ -242,31 +321,52 @@ export function opcionesDelMenu(valor) {
|
|
|
242
321
|
: cmd === 'model'
|
|
243
322
|
? ORDEN_DE_MODELOS.map((k) => [k, `${MODELOS[k].nombre} ${MODELOS[k].version}: ${MODELOS[k].descripcion}`])
|
|
244
323
|
: [
|
|
245
|
-
['on', cmd === 'teach' ? 'Explain each step as it codes' : cmd === 'notify' ? 'Notify me when it finishes or needs me' : 'Show them when parx opens'],
|
|
246
|
-
['off', cmd === 'teach' ? 'Back to normal' : cmd === 'notify' ? 'No desktop notifications' : 'Don’t show them again'],
|
|
324
|
+
['on', cmd === 'teach' ? 'Explain each step as it codes' : cmd === 'notify' ? 'Notify me when it finishes or needs me' : cmd === 'mouse' ? 'Click options, scroll with the wheel' : 'Show them when parx opens'],
|
|
325
|
+
['off', cmd === 'teach' ? 'Back to normal' : cmd === 'notify' ? 'No desktop notifications' : cmd === 'mouse' ? 'The terminal selects and scrolls as usual' : 'Don’t show them again'],
|
|
247
326
|
];
|
|
248
327
|
return valores
|
|
249
328
|
.filter(([v]) => v.startsWith(q))
|
|
250
|
-
.map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode'
|
|
329
|
+
.map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode' ? { modo: v, ...(v === 'bypass' ? { peligro: true } : {}) } : {}) }));
|
|
251
330
|
}
|
|
252
331
|
export function componerBarra(e, util) {
|
|
332
|
+
return componerBarraConZonas(e, util).texto;
|
|
333
|
+
}
|
|
334
|
+
export function componerBarraConZonas(e, util) {
|
|
335
|
+
const u = capacidades().unicode;
|
|
253
336
|
const punto = c.gris(sep());
|
|
254
|
-
const
|
|
337
|
+
const tinta = e.clave ? colorDeModo(e.clave) : e.peligro ? c.peligro : c.gris;
|
|
338
|
+
const modo = e.peligro ? tinta(c.negrita(`${u ? '▲' : '!'} ${e.modo}`)) : tinta(e.modo);
|
|
255
339
|
const extra = e.extra ? `${punto}${c.marca(e.extra)}` : '';
|
|
340
|
+
const n = e.esperando ?? 0;
|
|
341
|
+
const espera = n ? c.aviso(`${u ? '●' : '*'} ${tt('bandeja.esperando', { n })}`) : '';
|
|
342
|
+
const esperaCorta = n ? c.aviso(`${u ? '●' : '*'} ${n}`) : '';
|
|
343
|
+
const conEspera = (base, e2) => (e2 ? [...base, { t: punto }, { t: e2, id: 'bandeja' }] : base);
|
|
344
|
+
const m = { t: modo, id: 'modo' };
|
|
256
345
|
const opciones = [
|
|
257
|
-
[`${
|
|
258
|
-
[`${
|
|
259
|
-
[`${
|
|
260
|
-
[
|
|
346
|
+
[conEspera([m, { t: `${punto}${c.gris(e.modelo)}${extra}` }], espera), e.saldo],
|
|
347
|
+
[conEspera([m, { t: `${punto}${c.gris(e.modelo)}${extra}` }], espera), e.saldoCorto ?? e.saldo],
|
|
348
|
+
[conEspera([m, { t: `${punto}${c.gris(e.modelo)}` }], esperaCorta), e.saldoCorto ?? e.saldo],
|
|
349
|
+
[conEspera([m], esperaCorta), e.saldoCorto ?? e.saldo],
|
|
350
|
+
[[m], e.saldoCorto ?? e.saldo],
|
|
261
351
|
];
|
|
262
|
-
for (const [
|
|
352
|
+
for (const [trozos, der] of opciones) {
|
|
353
|
+
const izq = trozos.map((x) => x.t).join('');
|
|
263
354
|
const hueco = util - anchoDe(izq) - anchoDe(der);
|
|
264
|
-
if (hueco
|
|
265
|
-
|
|
355
|
+
if (hueco < 2)
|
|
356
|
+
continue;
|
|
357
|
+
const zonas = [];
|
|
358
|
+
let col = 0;
|
|
359
|
+
for (const x of trozos) {
|
|
360
|
+
const w = anchoDe(x.t);
|
|
361
|
+
if (x.id)
|
|
362
|
+
zonas.push({ desde: col, hasta: col + w, id: x.id });
|
|
363
|
+
col += w;
|
|
364
|
+
}
|
|
365
|
+
return { texto: `${izq}${' '.repeat(hueco)}${c.gris(der)}`, zonas };
|
|
266
366
|
}
|
|
267
367
|
const der = e.saldoCorto ?? '';
|
|
268
368
|
const izq = recortar(modo, Math.max(1, util - anchoDe(der) - 2));
|
|
269
|
-
return rellenar(`${izq}${' '.repeat(Math.max(0, util - anchoDe(izq) - anchoDe(der)))}${c.gris(der)}`, util);
|
|
369
|
+
return { texto: rellenar(`${izq}${' '.repeat(Math.max(0, util - anchoDe(izq) - anchoDe(der)))}${c.gris(der)}`, util), zonas: [{ desde: 0, hasta: anchoDe(izq), id: 'modo' }] };
|
|
270
370
|
}
|
|
271
371
|
export function duracion(ms) {
|
|
272
372
|
const s = Math.max(0, Math.floor(ms / 1000));
|
|
@@ -308,11 +408,16 @@ export function textoDeTrabajo(w, ahora) {
|
|
|
308
408
|
return { texto: w.texto, anim: w.anim };
|
|
309
409
|
return { texto: fraseDeEspera(ahora - w.esperaDesde, w.semilla), anim: 'ruta' };
|
|
310
410
|
}
|
|
311
|
-
export function filaDeTrabajo(w, ahora) {
|
|
411
|
+
export function filaDeTrabajo(w, ahora, ancho = Infinity) {
|
|
312
412
|
const { texto, anim } = textoDeTrabajo(w, ahora);
|
|
313
413
|
const tiempo = duracion(ahora - w.desde);
|
|
314
414
|
const gasto = w.acciones ? `${sep()}${acciones(w.acciones)}` : '';
|
|
315
|
-
|
|
415
|
+
for (const cola of [`${sep()}${tiempo}${gasto}`, `${sep()}${tiempo}${w.acciones ? `${sep()}${w.acciones.toLocaleString('en-US')}` : ''}`, `${sep()}${tiempo}`]) {
|
|
416
|
+
const fila = `${animacion(anim, w.paso)} ${texto}${c.gris(cola)}`;
|
|
417
|
+
if (anchoDe(fila) <= ancho)
|
|
418
|
+
return fila;
|
|
419
|
+
}
|
|
420
|
+
return recortar(`${animacion(anim, w.paso)} ${texto}`, ancho);
|
|
316
421
|
}
|
|
317
422
|
export function filaDeCarril(k, util, ahora) {
|
|
318
423
|
const fin = k.hasta ?? ahora;
|
|
@@ -333,8 +438,11 @@ export function filaDeCarril(k, util, ahora) {
|
|
|
333
438
|
}
|
|
334
439
|
const anchoTarea = Math.max(8, Math.floor(util * 0.32));
|
|
335
440
|
const tarea = recortar(k.tarea.replace(/\s+/g, ' '), anchoTarea);
|
|
336
|
-
const
|
|
337
|
-
|
|
441
|
+
const sitio = util - (anchoDe(derecha) + 2 <= util / 2 ? anchoDe(derecha) + 2 : 0);
|
|
442
|
+
const base = `${numero} ${señal} ${c.negrita(tarea)}`;
|
|
443
|
+
const libre = sitio - anchoDe(base) - anchoDe(sep());
|
|
444
|
+
const izq = libre >= 8 ? `${base}${c.gris(sep())}${c.gris(recortar(texto, libre))}` : base;
|
|
445
|
+
return izquierdaYDerecha(recortar(izq, sitio), derecha, util);
|
|
338
446
|
}
|
|
339
447
|
function izquierdaYDerecha(izq, der, util) {
|
|
340
448
|
if (anchoDe(izq) + anchoDe(der) + 2 <= util)
|
|
@@ -367,77 +475,163 @@ export function ventanaDeEntrada(unidades, cursor, ancho) {
|
|
|
367
475
|
export function cabePar(ancho) {
|
|
368
476
|
return ancho >= 56;
|
|
369
477
|
}
|
|
478
|
+
export function esBash(unidades) {
|
|
479
|
+
return unidades[0] === '!';
|
|
480
|
+
}
|
|
481
|
+
export function boton(etiqueta, numero, o = {}) {
|
|
482
|
+
const u = capacidades().unicode;
|
|
483
|
+
const n = numero === null ? '' : `${numero} `;
|
|
484
|
+
if (o.elegido)
|
|
485
|
+
return c.boton(`[${u ? '▸' : '>'}${n}${etiqueta} ]`, o.peligro);
|
|
486
|
+
const pinta = o.peligro ? c.peligro : (x) => x;
|
|
487
|
+
if (o.sobre)
|
|
488
|
+
return `${c.claro('[')} ${c.marca(`${n}${etiqueta}`)} ${c.claro(']')}`;
|
|
489
|
+
return `${c.gris('[')} ${numero === null ? '' : c.claro(n)}${pinta(etiqueta)} ${c.gris(']')}`;
|
|
490
|
+
}
|
|
491
|
+
function filaDeBotones(etiquetas, p, sobre, ancho) {
|
|
492
|
+
const partes = etiquetas.map((e, i) => boton(e, i + 1, { elegido: i === p.elegida, sobre: sobre === `opcion:${i}`, peligro: p.peligro || p.notas?.[i]?.peligro }));
|
|
493
|
+
const total = partes.reduce((n, x) => n + anchoDe(x), 0) + 2 * (partes.length - 1);
|
|
494
|
+
if (total > ancho)
|
|
495
|
+
return null;
|
|
496
|
+
const zonas = [];
|
|
497
|
+
let col = 0;
|
|
498
|
+
partes.forEach((x, i) => {
|
|
499
|
+
zonas.push({ desde: col, hasta: col + anchoDe(x), id: `opcion:${i}` });
|
|
500
|
+
col += anchoDe(x) + 2;
|
|
501
|
+
});
|
|
502
|
+
return { texto: partes.join(' '), zonas };
|
|
503
|
+
}
|
|
370
504
|
export function componerCarril(d, ancho, alto) {
|
|
371
505
|
const util = anchoUtil(ancho);
|
|
372
506
|
const conPar = cabePar(ancho);
|
|
373
507
|
const huecoPar = conPar ? ANCHO_DE_PAR + 2 : 0;
|
|
374
|
-
const
|
|
508
|
+
const u = capacidades().unicode;
|
|
509
|
+
const bash = !d.pregunta && esBash(d.unidades);
|
|
510
|
+
const signoW = bash ? 2 : 3;
|
|
511
|
+
const holgado = alto >= 14;
|
|
512
|
+
const medio = alto >= 9;
|
|
513
|
+
const vacia = `${m}${' '.repeat(util)}`;
|
|
375
514
|
let filaEscribir;
|
|
376
515
|
let cursor = null;
|
|
377
516
|
const anchoEscribir = util - (conPar ? huecoPar + 1 : 0);
|
|
378
|
-
|
|
379
|
-
const p = d.pregunta;
|
|
380
|
-
const pinta = (etiquetas) => etiquetas
|
|
381
|
-
.map((e, i) => {
|
|
382
|
-
const txt = `${i + 1} ${e}`;
|
|
383
|
-
return i === p.elegida ? `${c.claro(capacidades().unicode ? '▸' : '>')} ${c.negrita(txt)}` : ` ${c.gris(txt)}`;
|
|
384
|
-
})
|
|
385
|
-
.join(' ');
|
|
386
|
-
let opciones = pinta(p.opciones);
|
|
387
|
-
if (anchoDe(opciones) > anchoEscribir - signoW)
|
|
388
|
-
opciones = pinta(p.cortas);
|
|
389
|
-
filaEscribir = rellenar(`${(p.peligro ? c.peligro : c.aviso)(signo())} ${opciones}`, anchoEscribir);
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
517
|
+
{
|
|
392
518
|
const libre = Math.max(4, anchoEscribir - signoW);
|
|
393
|
-
const color = d.trabajo ? c.gris : c.claro;
|
|
394
|
-
|
|
395
|
-
|
|
519
|
+
const color = d.trabajo || d.pregunta ? c.gris : d.estado.clave ? colorDeModo(d.estado.clave) : c.claro;
|
|
520
|
+
const marca = bash ? c.bash(c.negrita('!')) : color(signo());
|
|
521
|
+
const unidades = bash ? d.unidades.slice(1) : d.unidades;
|
|
522
|
+
const enCursor = bash ? Math.max(0, d.cursor - 1) : d.cursor;
|
|
523
|
+
if (!unidades.length) {
|
|
524
|
+
const ejemplo = bash ? tt('bash.ejemplo') : d.pregunta ? '' : d.ejemplo;
|
|
525
|
+
filaEscribir = rellenar(`${marca} ${c.gris(recortar(ejemplo, libre))}`, anchoEscribir);
|
|
396
526
|
cursor = { fila: 0, col: MARGEN + signoW };
|
|
397
527
|
}
|
|
398
528
|
else {
|
|
399
|
-
const v = ventanaDeEntrada(
|
|
400
|
-
filaEscribir = rellenar(`${
|
|
529
|
+
const v = ventanaDeEntrada(unidades, enCursor, libre);
|
|
530
|
+
filaEscribir = rellenar(`${marca} ${d.pregunta ? c.gris(v.texto) : v.texto}`, anchoEscribir);
|
|
401
531
|
cursor = { fila: 0, col: MARGEN + signoW + v.col };
|
|
402
532
|
}
|
|
533
|
+
if (d.pregunta)
|
|
534
|
+
cursor = null;
|
|
403
535
|
}
|
|
404
536
|
if (conPar)
|
|
405
537
|
filaEscribir += ` ${cabezaDePar()} `;
|
|
406
|
-
const tinta = (t) => c.violeta(t);
|
|
538
|
+
const tinta = (t) => (bash ? c.bash(t) : c.violeta(t));
|
|
407
539
|
const linea = conPar ? `${tinta(carril(util - ANCHO_DE_PAR - 2))}${caraDePar(d.gesto)}${tinta(carril(2))}` : tinta(carril(util));
|
|
408
540
|
let barra;
|
|
541
|
+
let zonasBarra = [];
|
|
409
542
|
const enCarriles = (d.carriles ?? []).filter((k) => k.estado === 'trabaja').length;
|
|
410
543
|
if (d.trabajo && !d.pregunta && d.carriles?.length) {
|
|
411
544
|
const gasto = d.carriles.reduce((n, k) => n + (k.trabajo.acciones ?? 0), 0);
|
|
412
|
-
const
|
|
413
|
-
|
|
545
|
+
const base = `${animacion('tren', d.trabajo.paso)} ${tt('carriles.en_marcha', { n: enCarriles, total: d.carriles.length })}`;
|
|
546
|
+
const tiempo = `${sep()}${duracion(d.ahora - d.trabajo.desde)}`;
|
|
547
|
+
const izq = [`${base}${c.gris(`${tiempo}${gasto ? `${sep()}${acciones(gasto)}` : ''}`)}`, `${base}${c.gris(tiempo)}`, base].find((x) => anchoDe(x) <= util) ?? recortar(base, util);
|
|
548
|
+
barra = izquierdaYDerecha(izq, c.tenue(c.gris(d.aviso ?? tt('tui.parar'))), util);
|
|
414
549
|
}
|
|
415
550
|
else if (d.trabajo && !d.pregunta) {
|
|
416
|
-
barra = izquierdaYDerecha(
|
|
551
|
+
barra = izquierdaYDerecha(filaDeTrabajo(d.trabajo, d.ahora, util), c.tenue(c.gris(d.aviso ?? tt('tui.parar'))), util);
|
|
417
552
|
}
|
|
418
553
|
else if (d.aviso) {
|
|
419
554
|
barra = izquierdaYDerecha(c.aviso(recortar(d.aviso, util)), '', util);
|
|
420
555
|
}
|
|
556
|
+
else if (bash) {
|
|
557
|
+
const etiqueta = c.bash(c.negrita(tt('bash.etiqueta')));
|
|
558
|
+
const largo = `${etiqueta}${c.gris(`${sep()}${tt('bash.intro')}`)}`;
|
|
559
|
+
barra = izquierdaYDerecha(anchoDe(largo) + anchoDe(d.estado.saldoCorto ?? '') + 2 <= util ? largo : etiqueta, c.gris(d.estado.saldoCorto ?? ''), util);
|
|
560
|
+
}
|
|
421
561
|
else {
|
|
422
|
-
|
|
562
|
+
const b = componerBarraConZonas(d.estado, util);
|
|
563
|
+
barra = b.texto;
|
|
564
|
+
zonasBarra = b.zonas;
|
|
423
565
|
}
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
const
|
|
566
|
+
const filas = [filaEscribir, linea, ...(holgado ? [''] : []), barra].map((f) => (f ? `${m}${f}` : vacia));
|
|
567
|
+
const zonas = [];
|
|
568
|
+
const filaBarra = filas.length - 1;
|
|
569
|
+
for (const z of zonasBarra)
|
|
570
|
+
zonas.push({ fila: filaBarra, desde: MARGEN + z.desde, hasta: MARGEN + z.hasta, id: z.id });
|
|
571
|
+
let abajo = alto >= 3 ? filas : alto === 2 ? [filas[0], filas[filas.length - 1]] : [filas[0]];
|
|
572
|
+
if (abajo !== filas)
|
|
573
|
+
zonas.length = 0;
|
|
574
|
+
const carriles = (d.carriles ?? []).slice(0, Math.max(0, alto - abajo.length - 2));
|
|
427
575
|
const filasDeCarriles = carriles.map((k) => `${m}${rellenar(filaDeCarril(k, util, d.ahora), util)}`);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const hueco = Math.max(0, alto - filas.length);
|
|
432
|
-
let encima = [];
|
|
433
|
-
if (d.pregunta) {
|
|
576
|
+
let arriba = [...filasDeCarriles];
|
|
577
|
+
const zonasPregunta = [];
|
|
578
|
+
if (d.pregunta && alto >= 3) {
|
|
434
579
|
const p = d.pregunta;
|
|
435
|
-
const marca = p.peligro ? c.peligro(
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
580
|
+
const marca = p.peligro ? c.peligro(u ? '▲' : '!') : c.aviso('?');
|
|
581
|
+
const bloque = [];
|
|
582
|
+
const sitio = Math.max(1, alto - abajo.length - arriba.length - 2);
|
|
583
|
+
const titulo = envolver(p.texto, util - 2);
|
|
584
|
+
bloque.push(...titulo.map((l, i) => `${m}${rellenar(`${i === 0 ? marca : ' '} ${c.negrita(p.peligro ? c.peligro(l) : l)}`, util)}`));
|
|
585
|
+
if (p.detalle)
|
|
586
|
+
bloque.push(...envolver(p.detalle, util - 2).slice(0, 3).map((l) => `${m} ${rellenar(c.gris(l), util - 2)}`));
|
|
587
|
+
if (holgado)
|
|
588
|
+
bloque.push(vacia);
|
|
589
|
+
const enFila = !p.vertical ? (filaDeBotones(p.opciones, p, d.sobre, util - 2) ?? filaDeBotones(p.cortas, p, d.sobre, util - 2)) : null;
|
|
590
|
+
const filasBotones = [];
|
|
591
|
+
const zonasBotones = [];
|
|
592
|
+
if (enFila) {
|
|
593
|
+
filasBotones.push(`${m} ${rellenar(enFila.texto, util - 2)}`);
|
|
594
|
+
for (const z of enFila.zonas)
|
|
595
|
+
zonasBotones.push({ fila: 0, desde: MARGEN + 2 + z.desde, hasta: MARGEN + 2 + z.hasta, id: z.id });
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
const lista = filasDeLista(p, d.sobre, util, Math.max(1, sitio - bloque.length - (holgado ? 1 : 0)));
|
|
599
|
+
filasBotones.push(...lista.filas);
|
|
600
|
+
zonasBotones.push(...lista.zonas);
|
|
601
|
+
}
|
|
602
|
+
if (holgado)
|
|
603
|
+
filasBotones.push(vacia);
|
|
604
|
+
let todo = [...bloque, ...filasBotones];
|
|
605
|
+
let inicioBotones = bloque.length;
|
|
606
|
+
if (todo.length > sitio) {
|
|
607
|
+
const una = `${m}${rellenar(`${marca} ${c.negrita(recortar(p.texto, util - 2))}`, util)}`;
|
|
608
|
+
todo = [una, ...filasBotones.filter((x) => x !== vacia)];
|
|
609
|
+
inicioBotones = 1;
|
|
610
|
+
}
|
|
611
|
+
for (const z of zonasBotones)
|
|
612
|
+
zonasPregunta.push({ ...z, fila: inicioBotones + z.fila });
|
|
613
|
+
arriba = [...todo, ...arriba];
|
|
439
614
|
}
|
|
440
|
-
|
|
615
|
+
let separacion = medio || d.fondo ? vacia : null;
|
|
616
|
+
const zonaFondo = [];
|
|
617
|
+
if (separacion !== null && d.fondo) {
|
|
618
|
+
const texto = `${u ? '↓' : 'v'} ${tt('tui.al_fondo')}${d.fondo.nuevas ? `${sep()}${tt('tui.nuevas', { n: d.fondo.nuevas.toLocaleString('en-US') })}` : ''}`;
|
|
619
|
+
const b = d.sobre === 'fondo' ? c.boton(` ${texto} `) : boton(texto, null);
|
|
620
|
+
separacion = `${m}${rellenar(b, util)}`;
|
|
621
|
+
zonaFondo.push({ fila: 0, desde: MARGEN, hasta: MARGEN + anchoDe(b), id: 'fondo' });
|
|
622
|
+
}
|
|
623
|
+
const cabeza = separacion === null ? [] : [separacion];
|
|
624
|
+
const todas = [...cabeza, ...arriba, ...abajo];
|
|
625
|
+
const desplazar = cabeza.length + arriba.length;
|
|
626
|
+
for (const z of zonas)
|
|
627
|
+
z.fila += desplazar;
|
|
628
|
+
const zonasFinales = [...zonaFondo, ...zonasPregunta.map((z) => ({ ...z, fila: z.fila + cabeza.length })), ...zonas];
|
|
629
|
+
if (cursor)
|
|
630
|
+
cursor = { fila: cursor.fila + desplazar, col: cursor.col };
|
|
631
|
+
const hueco = Math.max(0, alto - todas.length);
|
|
632
|
+
let encima = [];
|
|
633
|
+
const zonasEncima = [];
|
|
634
|
+
if (!d.pregunta && d.menu && d.menu.opciones.length) {
|
|
441
635
|
const ops = d.menu.opciones;
|
|
442
636
|
const visibles = Math.min(6, ops.length, hueco);
|
|
443
637
|
if (visibles > 0) {
|
|
@@ -446,20 +640,61 @@ export function componerCarril(d, ancho, alto) {
|
|
|
446
640
|
encima = ops.slice(ini, ini + visibles).map((o, k) => {
|
|
447
641
|
const i = ini + k;
|
|
448
642
|
const sel = i === d.menu.elegida;
|
|
449
|
-
const
|
|
643
|
+
const sobre = d.sobre === `menu:${i}`;
|
|
644
|
+
zonasEncima.push({ fila: k, desde: MARGEN, hasta: MARGEN + util, id: `menu:${i}` });
|
|
645
|
+
const tinta = o.modo ? colorDeModo(o.modo) : o.peligro ? c.peligro : c.claro;
|
|
646
|
+
const marca = sel ? tinta(u ? '▌' : '>') : ' ';
|
|
450
647
|
const resto = Math.max(0, util - 2 - anchoNombre);
|
|
451
648
|
const desc = recortar(o.descripcion, resto);
|
|
452
649
|
if (o.peligro) {
|
|
453
|
-
const nombre = rellenar(recortar(`${
|
|
454
|
-
return `${m}${rellenar(`${marca} ${sel ? c.negrita(c.peligro(nombre)) : c.peligro(nombre)}${sel ? c.peligro(desc) : c.tenue(c.peligro(desc))}`, util)}`;
|
|
650
|
+
const nombre = rellenar(recortar(`${u ? '▲' : '!'} ${o.nombre}`, anchoNombre - 1), anchoNombre);
|
|
651
|
+
return `${m}${rellenar(`${marca} ${sel || sobre ? c.negrita(c.peligro(nombre)) : c.peligro(nombre)}${sel ? c.peligro(desc) : c.tenue(c.peligro(desc))}`, util)}`;
|
|
455
652
|
}
|
|
456
653
|
const nombre = rellenar(recortar(o.nombre, anchoNombre - 1), anchoNombre);
|
|
457
|
-
|
|
654
|
+
if (o.modo)
|
|
655
|
+
return `${m}${rellenar(`${marca} ${sel || sobre ? c.negrita(tinta(nombre)) : tinta(nombre)}${sel || sobre ? desc : c.tenue(c.gris(desc))}`, util)}`;
|
|
656
|
+
return `${m}${rellenar(`${marca} ${sel ? c.negrita(c.marca(nombre)) : sobre ? c.marca(nombre) : c.gris(nombre)}${sel || sobre ? desc : c.tenue(c.gris(desc))}`, util)}`;
|
|
458
657
|
});
|
|
459
658
|
}
|
|
460
659
|
}
|
|
461
|
-
|
|
462
|
-
|
|
660
|
+
const fuera = Math.max(0, encima.length - hueco);
|
|
661
|
+
encima = encima.slice(fuera);
|
|
662
|
+
return {
|
|
663
|
+
encima,
|
|
664
|
+
carril: todas,
|
|
665
|
+
cursor: cursor && todas.length ? cursor : null,
|
|
666
|
+
zonas: zonasFinales,
|
|
667
|
+
zonasEncima: zonasEncima.filter((z) => z.fila >= fuera).map((z) => ({ ...z, fila: z.fila - fuera })),
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function filasDeLista(p, sobre, util, max) {
|
|
671
|
+
const u = capacidades().unicode;
|
|
672
|
+
const n = p.opciones.length;
|
|
673
|
+
const visibles = Math.max(1, Math.min(n, max, 8));
|
|
674
|
+
const ini = Math.max(0, Math.min(p.elegida - visibles + 1, n - visibles));
|
|
675
|
+
const filas = [];
|
|
676
|
+
const zonas = [];
|
|
677
|
+
const recom = anchoDe(tt('bandeja.recomendada')) + 2;
|
|
678
|
+
const anchoEtiqueta = Math.max(...p.opciones.map((o, i) => anchoDe(o) + (p.notas?.[i]?.recomendada ? recom : 0))) + 2;
|
|
679
|
+
const conNotas = anchoEtiqueta <= Math.floor(util * 0.65);
|
|
680
|
+
for (let k = 0; k < visibles; k++) {
|
|
681
|
+
const i = ini + k;
|
|
682
|
+
const sel = i === p.elegida;
|
|
683
|
+
const enc = sobre === `opcion:${i}`;
|
|
684
|
+
const nota = p.notas?.[i];
|
|
685
|
+
const peligro = p.peligro || nota?.peligro;
|
|
686
|
+
const marca = sel ? (peligro ? c.peligro : c.claro)(u ? '▌' : '>') : ' ';
|
|
687
|
+
const num = i < 9 ? `${i + 1}` : ' ';
|
|
688
|
+
const recomendada = nota?.recomendada ? ` ${c.marca(tt('bandeja.recomendada'))}` : '';
|
|
689
|
+
const etiqueta = sel ? c.negrita(peligro ? c.peligro(p.opciones[i]) : p.opciones[i]) : enc ? c.marca(p.opciones[i]) : peligro ? c.peligro(p.opciones[i]) : p.opciones[i];
|
|
690
|
+
const cabeza = `${marca} ${c.claro(num)} `;
|
|
691
|
+
const base = conNotas ? `${cabeza}${rellenar(`${etiqueta}${recomendada}`, anchoEtiqueta)}` : `${cabeza}${recortar(`${etiqueta}${recomendada}`, Math.max(4, util - anchoDe(cabeza)))}`;
|
|
692
|
+
const resto = util - anchoDe(base);
|
|
693
|
+
const extra = conNotas && nota?.nota && resto >= 6 ? c.gris(recortar(nota.nota, resto)) : '';
|
|
694
|
+
filas.push(`${m}${rellenar(`${base}${extra}`, util)}`);
|
|
695
|
+
zonas.push({ fila: k, desde: MARGEN, hasta: MARGEN + util, id: `opcion:${i}` });
|
|
696
|
+
}
|
|
697
|
+
return { filas, zonas };
|
|
463
698
|
}
|
|
464
699
|
export function opcionesDePregunta(tipo) {
|
|
465
700
|
switch (tipo) {
|
|
@@ -495,20 +730,37 @@ export function rutaDeImagenPegada(texto) {
|
|
|
495
730
|
v = decodeURIComponent(v.slice(7));
|
|
496
731
|
return IMAGEN.test(v) && /^(\/|~|[A-Za-z]:\\|\.)/.test(v) ? v : null;
|
|
497
732
|
}
|
|
733
|
+
function sinBlancoDoble(lineas, previaEnBlanco) {
|
|
734
|
+
let i = 0;
|
|
735
|
+
if (previaEnBlanco)
|
|
736
|
+
while (i < lineas.length && lineas[i].trim() === '')
|
|
737
|
+
i++;
|
|
738
|
+
return i ? lineas.slice(i) : lineas;
|
|
739
|
+
}
|
|
498
740
|
export class Superficie {
|
|
499
741
|
o;
|
|
500
742
|
bloques = [];
|
|
501
743
|
lineas = [];
|
|
744
|
+
volcadas = 0;
|
|
745
|
+
subidas = 0;
|
|
746
|
+
vistaSucia = false;
|
|
502
747
|
anchoCompuesto = 0;
|
|
748
|
+
ultimoAlto = 0;
|
|
749
|
+
ultimoTrasBlanco = false;
|
|
503
750
|
encimaPintadas = 0;
|
|
504
751
|
carrilPintadas = 0;
|
|
505
752
|
activa = false;
|
|
506
753
|
oyente = null;
|
|
507
754
|
alRedimensionar = null;
|
|
755
|
+
alReanudar = null;
|
|
508
756
|
relojResize = null;
|
|
509
757
|
relojAnim = null;
|
|
510
758
|
relojAviso = null;
|
|
511
759
|
pegando = { pegando: false };
|
|
760
|
+
raton;
|
|
761
|
+
zonas = [];
|
|
762
|
+
sobre = null;
|
|
763
|
+
pulsado = null;
|
|
512
764
|
unidades = [];
|
|
513
765
|
cursor = 0;
|
|
514
766
|
pegados = [];
|
|
@@ -518,7 +770,7 @@ export class Superficie {
|
|
|
518
770
|
borrador = [];
|
|
519
771
|
menuCerradoPara = null;
|
|
520
772
|
menuElegida = 0;
|
|
521
|
-
cola =
|
|
773
|
+
cola = [];
|
|
522
774
|
ctrlC = 0;
|
|
523
775
|
ejemplo = null;
|
|
524
776
|
resolverLectura = null;
|
|
@@ -535,6 +787,7 @@ export class Superficie {
|
|
|
535
787
|
peligroPintado = false;
|
|
536
788
|
constructor(o) {
|
|
537
789
|
this.o = o;
|
|
790
|
+
this.raton = o.raton !== false;
|
|
538
791
|
}
|
|
539
792
|
get ancho() {
|
|
540
793
|
return Math.max(20, this.o.salida.columns || 80);
|
|
@@ -545,6 +798,9 @@ export class Superficie {
|
|
|
545
798
|
get enfocada() {
|
|
546
799
|
return this.foco;
|
|
547
800
|
}
|
|
801
|
+
get conRaton() {
|
|
802
|
+
return this.raton;
|
|
803
|
+
}
|
|
548
804
|
escribir(s) {
|
|
549
805
|
this.o.salida.write(s);
|
|
550
806
|
}
|
|
@@ -553,6 +809,7 @@ export class Superficie {
|
|
|
553
809
|
const ops = this.menuCerradoPara === valor ? null : opcionesDelMenu(valor);
|
|
554
810
|
if (ops && this.menuElegida >= ops.length)
|
|
555
811
|
this.menuElegida = Math.max(0, ops.length - 1);
|
|
812
|
+
const pendientes = this.lineas.length - this.volcadas;
|
|
556
813
|
return {
|
|
557
814
|
unidades: this.unidades.map((u) => this.vistaDeUnidad(u)),
|
|
558
815
|
cursor: this.cursor,
|
|
@@ -565,6 +822,8 @@ export class Superficie {
|
|
|
565
822
|
carriles: this.carriles,
|
|
566
823
|
gesto: this.pregunta ? 'pregunta' : this.trabajo || this.carriles.some((k) => k.estado === 'trabaja') ? (((this.trabajo?.paso ?? this.carriles[0]?.trabajo.paso ?? 0) >> 1) % 4) : this.gesto,
|
|
567
824
|
ahora: Date.now(),
|
|
825
|
+
sobre: this.raton ? this.sobre : null,
|
|
826
|
+
fondo: this.subidas > 0 || pendientes > 0 ? { nuevas: pendientes } : null,
|
|
568
827
|
};
|
|
569
828
|
}
|
|
570
829
|
vistaDeUnidad(u) {
|
|
@@ -584,14 +843,31 @@ export class Superficie {
|
|
|
584
843
|
return this.alto - n + 1;
|
|
585
844
|
}
|
|
586
845
|
desplazadas(altoCarril) {
|
|
587
|
-
return Math.max(0, this.
|
|
846
|
+
return Math.max(0, this.volcadas - (this.alto - altoCarril));
|
|
588
847
|
}
|
|
589
848
|
filaTrasLaConversacion(altoCarril) {
|
|
590
|
-
return Math.min(this.
|
|
849
|
+
return Math.min(this.volcadas, Math.max(0, this.alto - altoCarril)) + 1;
|
|
591
850
|
}
|
|
592
851
|
lineaDeFila(fila, altoCarril) {
|
|
593
|
-
const indice = this.desplazadas(altoCarril) + (fila - 1);
|
|
594
|
-
return indice >= 0 ? (this.lineas[indice] ?? '') : '';
|
|
852
|
+
const indice = this.desplazadas(altoCarril) - this.subidas + (fila - 1);
|
|
853
|
+
return indice >= 0 && indice < this.volcadas ? (this.lineas[indice] ?? '') : '';
|
|
854
|
+
}
|
|
855
|
+
componerTodo() {
|
|
856
|
+
const out = [];
|
|
857
|
+
for (const b of this.bloques) {
|
|
858
|
+
this.ultimoTrasBlanco = out.length === 0 || out[out.length - 1].trim() === '';
|
|
859
|
+
const l = sinBlancoDoble(b(this.ancho), this.ultimoTrasBlanco);
|
|
860
|
+
this.ultimoAlto = l.length;
|
|
861
|
+
out.push(...l);
|
|
862
|
+
}
|
|
863
|
+
this.lineas = out;
|
|
864
|
+
}
|
|
865
|
+
recortarMemoria() {
|
|
866
|
+
const sobran = this.lineas.length - MAX_LINEAS;
|
|
867
|
+
if (sobran <= 0)
|
|
868
|
+
return;
|
|
869
|
+
this.lineas.splice(0, sobran);
|
|
870
|
+
this.volcadas = Math.max(0, this.volcadas - sobran);
|
|
595
871
|
}
|
|
596
872
|
pintar() {
|
|
597
873
|
if (!this.activa)
|
|
@@ -607,21 +883,34 @@ export class Superficie {
|
|
|
607
883
|
const k = componerCarril(this.datos(), this.ancho, this.alto);
|
|
608
884
|
const n = k.carril.length;
|
|
609
885
|
let s = '\x1b[?2026h\x1b[?25l';
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
if (subir)
|
|
615
|
-
s += `\x1b[${this.alto};1H${'\r\n'.repeat(subir)}`;
|
|
886
|
+
const subido = this.subidas > 0 || this.volcadas < this.lineas.length;
|
|
887
|
+
if (this.carrilPintadas && n !== this.carrilPintadas && subido) {
|
|
888
|
+
this.vistaSucia = true;
|
|
889
|
+
this.encimaPintadas = 0;
|
|
616
890
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
891
|
+
else {
|
|
892
|
+
if (this.carrilPintadas && n > this.carrilPintadas) {
|
|
893
|
+
s += this.destapar();
|
|
894
|
+
const ocupadas = Math.min(this.volcadas, Math.max(0, this.alto - this.carrilPintadas));
|
|
895
|
+
const subir = Math.max(0, ocupadas - Math.max(0, this.alto - n));
|
|
896
|
+
if (subir)
|
|
897
|
+
s += `\x1b[${this.alto};1H${'\r\n'.repeat(subir)}`;
|
|
898
|
+
}
|
|
899
|
+
if (this.carrilPintadas && n < this.carrilPintadas) {
|
|
900
|
+
s += this.destapar();
|
|
901
|
+
const topNuevo = this.filaDelCarril(n);
|
|
902
|
+
for (let fila = 1; fila < topNuevo; fila++)
|
|
903
|
+
s += `\x1b[${fila};1H\x1b[2K${this.lineaDeFila(fila, n)}`;
|
|
904
|
+
}
|
|
622
905
|
}
|
|
623
906
|
this.carrilPintadas = n;
|
|
624
907
|
const top = this.filaDelCarril(n);
|
|
908
|
+
if (this.vistaSucia) {
|
|
909
|
+
for (let fila = 1; fila < top; fila++)
|
|
910
|
+
s += `\x1b[${fila};1H\x1b[2K${this.lineaDeFila(fila, n)}`;
|
|
911
|
+
this.vistaSucia = false;
|
|
912
|
+
this.encimaPintadas = 0;
|
|
913
|
+
}
|
|
625
914
|
for (let i = k.encima.length; i < this.encimaPintadas; i++) {
|
|
626
915
|
const fila = top - 1 - i;
|
|
627
916
|
if (fila >= 1)
|
|
@@ -636,6 +925,12 @@ export class Superficie {
|
|
|
636
925
|
k.carril.forEach((l, i) => {
|
|
637
926
|
s += `\x1b[${top + i};1H\x1b[2K${l}`;
|
|
638
927
|
});
|
|
928
|
+
this.zonas = [
|
|
929
|
+
...k.zonasEncima.map((z) => ({ ...z, fila: top - k.encima.length + z.fila })),
|
|
930
|
+
...k.zonas.map((z) => ({ ...z, fila: top + z.fila })),
|
|
931
|
+
];
|
|
932
|
+
if (this.sobre && !this.zonas.some((z) => z.id === this.sobre))
|
|
933
|
+
this.sobre = null;
|
|
639
934
|
if (k.cursor)
|
|
640
935
|
s += `\x1b[${top + k.cursor.fila};${k.cursor.col + 1}H\x1b[?25h`;
|
|
641
936
|
s += '\x1b[?2026l';
|
|
@@ -659,9 +954,13 @@ export class Superficie {
|
|
|
659
954
|
this.consejosVisibles = false;
|
|
660
955
|
if (!this.activa)
|
|
661
956
|
return;
|
|
662
|
-
this.
|
|
663
|
-
|
|
664
|
-
|
|
957
|
+
if (this.subidas > 0 || this.volcadas < this.lineas.length) {
|
|
958
|
+
this.recomponer();
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
this.componerTodo();
|
|
962
|
+
this.volcadas = this.lineas.length;
|
|
963
|
+
this.recortarMemoria();
|
|
665
964
|
const n = componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
666
965
|
const top = this.filaDelCarril(n);
|
|
667
966
|
let s = '\x1b[?2026h\x1b[?25l';
|
|
@@ -672,41 +971,68 @@ export class Superficie {
|
|
|
672
971
|
this.escribir(s);
|
|
673
972
|
this.pintar();
|
|
674
973
|
}
|
|
974
|
+
terminaEnBlanco() {
|
|
975
|
+
const ultima = this.lineas[this.lineas.length - 1];
|
|
976
|
+
return ultima === undefined || ultima.trim() === '';
|
|
977
|
+
}
|
|
675
978
|
anadir(b) {
|
|
676
979
|
this.ocultarConsejos();
|
|
677
|
-
const destapado = this.activa ? this.destapar() : '';
|
|
678
|
-
const n = this.activa ? this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length : 0;
|
|
679
|
-
const desde = this.activa ? this.filaTrasLaConversacion(n) : 0;
|
|
680
980
|
this.bloques.push(b);
|
|
681
981
|
if (this.bloques.length > MAX_BLOQUES)
|
|
682
982
|
this.bloques.splice(0, this.bloques.length - MAX_BLOQUES);
|
|
683
|
-
|
|
983
|
+
this.ultimoTrasBlanco = this.terminaEnBlanco();
|
|
984
|
+
const nuevas = sinBlancoDoble(b(this.ancho), this.ultimoTrasBlanco);
|
|
985
|
+
this.ultimoAlto = nuevas.length;
|
|
986
|
+
if (this.activa && (this.subidas > 0 || this.volcadas < this.lineas.length)) {
|
|
987
|
+
this.lineas.push(...nuevas);
|
|
988
|
+
this.recortarMemoria();
|
|
989
|
+
this.pintar();
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const destapado = this.activa ? this.destapar() : '';
|
|
684
993
|
this.lineas.push(...nuevas);
|
|
685
|
-
if (this.
|
|
686
|
-
this.
|
|
687
|
-
|
|
994
|
+
if (!this.activa) {
|
|
995
|
+
this.volcadas = this.lineas.length;
|
|
996
|
+
this.recortarMemoria();
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
this.escribir(destapado);
|
|
1000
|
+
this.volcar();
|
|
1001
|
+
this.pintar();
|
|
1002
|
+
}
|
|
1003
|
+
volcar() {
|
|
1004
|
+
const nuevas = this.lineas.slice(this.volcadas);
|
|
1005
|
+
if (!nuevas.length)
|
|
688
1006
|
return;
|
|
689
|
-
|
|
690
|
-
|
|
1007
|
+
const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
1008
|
+
const desde = this.filaTrasLaConversacion(n);
|
|
1009
|
+
let s = `\x1b[?2026h\x1b[?25l\x1b[${desde};1H\x1b[J`;
|
|
691
1010
|
s += nuevas.map((l) => `${l}\x1b[K\r\n`).join('');
|
|
692
1011
|
s += '\r\n'.repeat(Math.max(0, n - 1));
|
|
693
1012
|
s += '\x1b[?2026l';
|
|
1013
|
+
this.volcadas = this.lineas.length;
|
|
1014
|
+
this.recortarMemoria();
|
|
1015
|
+
this.encimaPintadas = 0;
|
|
694
1016
|
this.escribir(s);
|
|
695
|
-
this.pintar();
|
|
696
1017
|
}
|
|
697
1018
|
ultimoBloque() {
|
|
698
1019
|
return this.bloques[this.bloques.length - 1];
|
|
699
1020
|
}
|
|
700
1021
|
reemplazarUltimo(b) {
|
|
701
1022
|
const viejo = this.ultimoBloque();
|
|
702
|
-
const k = viejo ?
|
|
703
|
-
const nuevas = b(this.ancho);
|
|
1023
|
+
const k = viejo ? this.ultimoAlto : -1;
|
|
1024
|
+
const nuevas = sinBlancoDoble(b(this.ancho), this.ultimoTrasBlanco);
|
|
704
1025
|
if (!viejo || !this.activa || nuevas.length !== k || this.encimaPintadas > 0 || this.lineas.length < k) {
|
|
705
1026
|
this.anadir(b);
|
|
706
1027
|
return;
|
|
707
1028
|
}
|
|
708
1029
|
this.bloques[this.bloques.length - 1] = b;
|
|
709
1030
|
this.lineas.splice(this.lineas.length - k, k, ...nuevas);
|
|
1031
|
+
if (this.subidas > 0 || this.volcadas < this.lineas.length) {
|
|
1032
|
+
this.vistaSucia = true;
|
|
1033
|
+
this.pintar();
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
710
1036
|
const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
711
1037
|
const primera = this.lineas.length - k - this.desplazadas(n) + 1;
|
|
712
1038
|
let s = '\x1b[?2026h\x1b[?25l';
|
|
@@ -724,9 +1050,10 @@ export class Superficie {
|
|
|
724
1050
|
return;
|
|
725
1051
|
fijarCapacidades({ ancho: this.ancho });
|
|
726
1052
|
this.anchoCompuesto = this.ancho;
|
|
727
|
-
this.
|
|
728
|
-
|
|
729
|
-
|
|
1053
|
+
this.componerTodo();
|
|
1054
|
+
this.volcadas = this.lineas.length;
|
|
1055
|
+
this.subidas = 0;
|
|
1056
|
+
this.recortarMemoria();
|
|
730
1057
|
const n = componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
731
1058
|
let s = alEmpezar ? `\x1b[?2026h\x1b[?25l${'\r\n'.repeat(this.alto)}\x1b[H` : '\x1b[?2026h\x1b[?25l\x1b[H\x1b[2J\x1b[3J\x1b[H';
|
|
732
1059
|
s += this.lineas.map((l) => `${l}\x1b[K\r\n`).join('');
|
|
@@ -737,6 +1064,113 @@ export class Superficie {
|
|
|
737
1064
|
this.escribir(s);
|
|
738
1065
|
this.pintar();
|
|
739
1066
|
}
|
|
1067
|
+
filasDeVista() {
|
|
1068
|
+
return Math.max(1, this.filaDelCarril(this.carrilPintadas || 3) - 1);
|
|
1069
|
+
}
|
|
1070
|
+
desplazar(n) {
|
|
1071
|
+
if (!this.activa)
|
|
1072
|
+
return;
|
|
1073
|
+
const max = this.desplazadas(this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length);
|
|
1074
|
+
const nuevo = Math.max(0, Math.min(max, this.subidas + n));
|
|
1075
|
+
if (nuevo === 0) {
|
|
1076
|
+
if (this.subidas > 0 || this.volcadas < this.lineas.length)
|
|
1077
|
+
this.irAlFondo();
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
if (nuevo === this.subidas)
|
|
1081
|
+
return;
|
|
1082
|
+
this.subidas = nuevo;
|
|
1083
|
+
this.vistaSucia = true;
|
|
1084
|
+
this.pintar();
|
|
1085
|
+
}
|
|
1086
|
+
irAlFondo() {
|
|
1087
|
+
if (!this.activa || (this.subidas === 0 && this.volcadas === this.lineas.length))
|
|
1088
|
+
return;
|
|
1089
|
+
this.subidas = 0;
|
|
1090
|
+
const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
1091
|
+
const top = this.filaDelCarril(n);
|
|
1092
|
+
let s = '\x1b[?2026h\x1b[?25l';
|
|
1093
|
+
for (let fila = 1; fila < top; fila++)
|
|
1094
|
+
s += `\x1b[${fila};1H\x1b[2K${this.lineaDeFila(fila, n)}`;
|
|
1095
|
+
s += '\x1b[?2026l';
|
|
1096
|
+
this.encimaPintadas = 0;
|
|
1097
|
+
this.escribir(s);
|
|
1098
|
+
this.volcar();
|
|
1099
|
+
this.pintar();
|
|
1100
|
+
}
|
|
1101
|
+
get _vista() {
|
|
1102
|
+
return { subidas: this.subidas, pendientes: this.lineas.length - this.volcadas };
|
|
1103
|
+
}
|
|
1104
|
+
fijarRaton(si) {
|
|
1105
|
+
this.raton = si;
|
|
1106
|
+
this.sobre = null;
|
|
1107
|
+
this.pulsado = null;
|
|
1108
|
+
if (this.activa)
|
|
1109
|
+
this.escribir(si ? RATON_SI : RATON_NO);
|
|
1110
|
+
if (!si)
|
|
1111
|
+
this.irAlFondo();
|
|
1112
|
+
this.pintar();
|
|
1113
|
+
}
|
|
1114
|
+
zonaEn(x, y) {
|
|
1115
|
+
const col = x - 1;
|
|
1116
|
+
for (const z of this.zonas)
|
|
1117
|
+
if (z.fila === y && col >= z.desde && col < z.hasta)
|
|
1118
|
+
return z.id;
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
alRaton(k) {
|
|
1122
|
+
if (!this.raton)
|
|
1123
|
+
return;
|
|
1124
|
+
if (k.rueda) {
|
|
1125
|
+
this.desplazar(-k.rueda * 3);
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
const zona = this.zonaEn(k.x, k.y);
|
|
1129
|
+
if (k.mover && k.boton === 3) {
|
|
1130
|
+
if (zona !== this.sobre) {
|
|
1131
|
+
this.sobre = zona;
|
|
1132
|
+
this.pintar();
|
|
1133
|
+
}
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
if (k.boton !== 0 && !(k.soltar && k.boton === 3))
|
|
1137
|
+
return;
|
|
1138
|
+
if (!k.soltar) {
|
|
1139
|
+
if (!k.mover)
|
|
1140
|
+
this.pulsado = zona;
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const pulsado = this.pulsado;
|
|
1144
|
+
this.pulsado = null;
|
|
1145
|
+
if (pulsado && zona === pulsado)
|
|
1146
|
+
this.activar(pulsado);
|
|
1147
|
+
}
|
|
1148
|
+
activar(id) {
|
|
1149
|
+
if (id === 'fondo')
|
|
1150
|
+
return this.irAlFondo();
|
|
1151
|
+
if (id === 'bandeja') {
|
|
1152
|
+
if (this.resolverLectura && !this.trabajo && !this.pregunta)
|
|
1153
|
+
this.o.alBandeja?.();
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (id === 'modo') {
|
|
1157
|
+
if (!this.pregunta)
|
|
1158
|
+
this.o.alCambiarModo?.();
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const opcion = /^opcion:(\d+)$/.exec(id);
|
|
1162
|
+
if (opcion && this.pregunta)
|
|
1163
|
+
return this.responder(Number(opcion[1]));
|
|
1164
|
+
const menu = /^menu:(\d+)$/.exec(id);
|
|
1165
|
+
if (menu && !this.pregunta) {
|
|
1166
|
+
this.menuElegida = Number(menu[1]);
|
|
1167
|
+
this.tecla({ t: 'intro' });
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
modosSi() {
|
|
1171
|
+
return `\x1b[?2004h\x1b[?1004h${this.raton ? RATON_SI : ''}`;
|
|
1172
|
+
}
|
|
1173
|
+
static MODOS_NO = `${RATON_NO}\x1b[?2004l\x1b[?1004l\x1b[?25h`;
|
|
740
1174
|
iniciar(bienvenida, consejos = []) {
|
|
741
1175
|
if (this.activa)
|
|
742
1176
|
return;
|
|
@@ -744,7 +1178,7 @@ export class Superficie {
|
|
|
744
1178
|
if (bienvenida)
|
|
745
1179
|
this.bloques.push(bienvenida);
|
|
746
1180
|
if (consejos.length) {
|
|
747
|
-
const ocupado = (bienvenida ? bienvenida(this.ancho).length : 0) +
|
|
1181
|
+
const ocupado = (bienvenida ? bienvenida(this.ancho).length : 0) + componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
748
1182
|
let n = consejos.length;
|
|
749
1183
|
while (n > 0 && ocupado + bloqueDeConsejos(() => consejos.slice(0, n))(this.ancho).length > this.alto)
|
|
750
1184
|
n--;
|
|
@@ -753,7 +1187,7 @@ export class Superficie {
|
|
|
753
1187
|
if (n > 0)
|
|
754
1188
|
this.bloques.push(bloqueDeConsejos(() => (this.consejosVisibles ? this.consejos : [])));
|
|
755
1189
|
}
|
|
756
|
-
this.escribir(
|
|
1190
|
+
this.escribir(this.modosSi());
|
|
757
1191
|
try {
|
|
758
1192
|
this.o.entrada.setRawMode?.(true);
|
|
759
1193
|
}
|
|
@@ -799,12 +1233,13 @@ export class Superficie {
|
|
|
799
1233
|
terminar(despedida) {
|
|
800
1234
|
if (!this.activa)
|
|
801
1235
|
return;
|
|
1236
|
+
this.irAlFondo();
|
|
802
1237
|
const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
803
1238
|
let s = this.destapar();
|
|
804
1239
|
s += `\x1b[${this.filaTrasLaConversacion(n)};1H\x1b[J`;
|
|
805
1240
|
if (despedida)
|
|
806
|
-
s += `${m}${despedida}\r\n`;
|
|
807
|
-
s +=
|
|
1241
|
+
s += `${this.terminaEnBlanco() ? '' : '\r\n'}${m}${despedida}\r\n`;
|
|
1242
|
+
s += Superficie.MODOS_NO;
|
|
808
1243
|
this.escribir(s);
|
|
809
1244
|
this.activa = false;
|
|
810
1245
|
if (this.relojAnim)
|
|
@@ -817,6 +1252,8 @@ export class Superficie {
|
|
|
817
1252
|
this.o.entrada.removeListener('data', this.oyente);
|
|
818
1253
|
if (this.alRedimensionar)
|
|
819
1254
|
this.o.salida.removeListener('resize', this.alRedimensionar);
|
|
1255
|
+
if (this.alReanudar)
|
|
1256
|
+
process.removeListener('SIGCONT', this.alReanudar);
|
|
820
1257
|
try {
|
|
821
1258
|
this.o.entrada.setRawMode?.(false);
|
|
822
1259
|
}
|
|
@@ -827,21 +1264,65 @@ export class Superficie {
|
|
|
827
1264
|
restaurarDeUrgencia() {
|
|
828
1265
|
if (!this.activa)
|
|
829
1266
|
return;
|
|
830
|
-
this.o.salida.write(
|
|
1267
|
+
this.o.salida.write(`${Superficie.MODOS_NO}\x1b[?2026l`);
|
|
831
1268
|
try {
|
|
832
1269
|
this.o.entrada.setRawMode?.(false);
|
|
833
1270
|
}
|
|
834
1271
|
catch {
|
|
835
1272
|
}
|
|
836
1273
|
}
|
|
1274
|
+
suspender() {
|
|
1275
|
+
if (process.platform === 'win32' && !this.o.suspenderProceso)
|
|
1276
|
+
return;
|
|
1277
|
+
this.irAlFondo();
|
|
1278
|
+
const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
1279
|
+
let s = this.destapar();
|
|
1280
|
+
s += `\x1b[${this.filaTrasLaConversacion(n)};1H\x1b[J`;
|
|
1281
|
+
s += Superficie.MODOS_NO;
|
|
1282
|
+
this.escribir(s);
|
|
1283
|
+
try {
|
|
1284
|
+
this.o.entrada.setRawMode?.(false);
|
|
1285
|
+
}
|
|
1286
|
+
catch {
|
|
1287
|
+
}
|
|
1288
|
+
if (!this.alReanudar) {
|
|
1289
|
+
this.alReanudar = () => this.reanudar();
|
|
1290
|
+
if (!this.o.suspenderProceso)
|
|
1291
|
+
process.on('SIGCONT', this.alReanudar);
|
|
1292
|
+
}
|
|
1293
|
+
if (this.o.suspenderProceso)
|
|
1294
|
+
this.o.suspenderProceso();
|
|
1295
|
+
else
|
|
1296
|
+
process.kill(process.pid, 'SIGTSTP');
|
|
1297
|
+
}
|
|
1298
|
+
reanudar() {
|
|
1299
|
+
if (!this.activa)
|
|
1300
|
+
return;
|
|
1301
|
+
try {
|
|
1302
|
+
this.o.entrada.setRawMode?.(true);
|
|
1303
|
+
}
|
|
1304
|
+
catch {
|
|
1305
|
+
}
|
|
1306
|
+
this.o.entrada.resume();
|
|
1307
|
+
const n = componerCarril(this.datos(), this.ancho, this.alto).carril.length;
|
|
1308
|
+
let s = `\x1b[?2026h\x1b[?25l${this.modosSi()}${'\r\n'.repeat(this.alto)}`;
|
|
1309
|
+
for (let fila = 1; fila < this.filaDelCarril(n); fila++)
|
|
1310
|
+
s += `\x1b[${fila};1H\x1b[2K${this.lineaDeFila(fila, n)}`;
|
|
1311
|
+
s += '\x1b[?2026l';
|
|
1312
|
+
this.carrilPintadas = n;
|
|
1313
|
+
this.encimaPintadas = 0;
|
|
1314
|
+
this.escribir(s);
|
|
1315
|
+
this.pintar();
|
|
1316
|
+
}
|
|
837
1317
|
leer(ejemplo = null) {
|
|
838
1318
|
this.ejemplo = ejemplo;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1319
|
+
const enCola = this.cola.shift();
|
|
1320
|
+
if (enCola !== undefined) {
|
|
1321
|
+
const r = enCola;
|
|
842
1322
|
this.ejemplo = null;
|
|
843
|
-
this.mostrarAviso(null);
|
|
844
|
-
|
|
1323
|
+
this.mostrarAviso(this.cola.length ? tt('tui.en_cola_n', { n: this.cola.length }) : null);
|
|
1324
|
+
if (r.trim() && r.trim() !== '!')
|
|
1325
|
+
this.anadir(this.bloqueDeEnvio(r));
|
|
845
1326
|
return Promise.resolve(this.expandir(r));
|
|
846
1327
|
}
|
|
847
1328
|
return new Promise((resolver) => {
|
|
@@ -852,6 +1333,15 @@ export class Superficie {
|
|
|
852
1333
|
this.pintar();
|
|
853
1334
|
});
|
|
854
1335
|
}
|
|
1336
|
+
escribirYMandar(texto) {
|
|
1337
|
+
if (!this.libre)
|
|
1338
|
+
return;
|
|
1339
|
+
this.ponerValor(texto);
|
|
1340
|
+
this.enviar();
|
|
1341
|
+
}
|
|
1342
|
+
get libre() {
|
|
1343
|
+
return Boolean(this.resolverLectura) && !this.trabajo && !this.pregunta;
|
|
1344
|
+
}
|
|
855
1345
|
trabajar(alParar) {
|
|
856
1346
|
if (this.trabajo)
|
|
857
1347
|
this.trabajo.alParar = alParar;
|
|
@@ -885,31 +1375,55 @@ export class Superficie {
|
|
|
885
1375
|
this.pintar();
|
|
886
1376
|
}
|
|
887
1377
|
preguntar(texto, tipo = 'normal') {
|
|
1378
|
+
const o = opcionesDePregunta(tipo);
|
|
1379
|
+
const peligro = tipo === 'bypass';
|
|
888
1380
|
return new Promise((resolver) => {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1381
|
+
this.mostrarPregunta({
|
|
1382
|
+
texto,
|
|
1383
|
+
opciones: o.opciones,
|
|
1384
|
+
cortas: o.cortas,
|
|
1385
|
+
elegida: o.elegida,
|
|
1386
|
+
...(peligro ? { peligro: true } : {}),
|
|
1387
|
+
indiceNo: o.valores.indexOf('no'),
|
|
1388
|
+
siConY: o.valores[o.elegida] !== 'no' || peligro,
|
|
1389
|
+
}, (i) => resolver(i === null ? 'no' : (o.valores[i] ?? 'no')));
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
elegir(texto, opciones, o = {}) {
|
|
1393
|
+
return new Promise((resolver) => {
|
|
1394
|
+
this.mostrarPregunta({
|
|
1395
|
+
texto,
|
|
1396
|
+
...(o.detalle ? { detalle: o.detalle } : {}),
|
|
1397
|
+
opciones: opciones.map((x) => x.etiqueta),
|
|
1398
|
+
cortas: opciones.map((x) => x.corta ?? x.etiqueta),
|
|
1399
|
+
notas: opciones.map((x) => ({ nota: x.nota, recomendada: x.recomendada, peligro: x.peligro })),
|
|
1400
|
+
elegida: Math.max(0, Math.min(opciones.length - 1, o.elegida ?? 0)),
|
|
1401
|
+
...(o.vertical ? { vertical: true } : {}),
|
|
1402
|
+
indiceNo: null,
|
|
1403
|
+
siConY: false,
|
|
1404
|
+
}, resolver);
|
|
899
1405
|
});
|
|
900
1406
|
}
|
|
1407
|
+
mostrarPregunta(p, resolver) {
|
|
1408
|
+
const mostrar = () => {
|
|
1409
|
+
this.pregunta = { ...p, resolver, sordaHasta: Date.now() + this.guardaDePregunta };
|
|
1410
|
+
this.o.alPreguntar?.(p.texto);
|
|
1411
|
+
this.pintar();
|
|
1412
|
+
};
|
|
1413
|
+
if (this.pregunta)
|
|
1414
|
+
this.esperando.push(mostrar);
|
|
1415
|
+
else
|
|
1416
|
+
mostrar();
|
|
1417
|
+
}
|
|
901
1418
|
responder(i) {
|
|
902
1419
|
const p = this.pregunta;
|
|
903
1420
|
if (!p)
|
|
904
1421
|
return;
|
|
905
|
-
const r = p.valores[i] ?? 'no';
|
|
906
1422
|
this.pregunta = null;
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
this.pintar();
|
|
912
|
-
p.resolver(r);
|
|
1423
|
+
this.sobre = null;
|
|
1424
|
+
this.pulsado = null;
|
|
1425
|
+
this.pintar();
|
|
1426
|
+
p.resolver(i);
|
|
913
1427
|
this.esperando.shift()?.();
|
|
914
1428
|
}
|
|
915
1429
|
mostrarAviso(texto, ms = 0) {
|
|
@@ -933,14 +1447,18 @@ export class Superficie {
|
|
|
933
1447
|
}
|
|
934
1448
|
expandir(v) {
|
|
935
1449
|
return v
|
|
936
|
-
.replace(
|
|
937
|
-
.replace(
|
|
1450
|
+
.replace(/(\d+)/g, (_x, i) => this.pegados[Number(i)] ?? '')
|
|
1451
|
+
.replace(/(\d+)/g, (_x, i) => `${this.imagenes[Number(i)] ?? ''}`);
|
|
1452
|
+
}
|
|
1453
|
+
bloqueDeEnvio(crudo) {
|
|
1454
|
+
const v = crudo.trim();
|
|
1455
|
+
return v.startsWith('!') ? bloqueDeBash(this.vistaDeEnvio(v.slice(1).trim())) : bloqueDeLaPersona(this.vistaDeEnvio(v));
|
|
938
1456
|
}
|
|
939
1457
|
vistaDeEnvio(v) {
|
|
940
|
-
return v.replace(/[
|
|
1458
|
+
return v.replace(/[]\d+/g, (x) => sinColorSimple(this.vistaDeUnidad(x)));
|
|
941
1459
|
}
|
|
942
1460
|
ponerValor(v) {
|
|
943
|
-
this.unidades = v.match(/[
|
|
1461
|
+
this.unidades = v.match(/[]\d+|[\s\S]/gu) ?? [];
|
|
944
1462
|
this.cursor = this.unidades.length;
|
|
945
1463
|
}
|
|
946
1464
|
insertar(texto) {
|
|
@@ -959,17 +1477,18 @@ export class Superficie {
|
|
|
959
1477
|
if (v && this.historial[this.historial.length - 1] !== crudo)
|
|
960
1478
|
this.historial.push(crudo);
|
|
961
1479
|
this.posHistorial = this.historial.length;
|
|
1480
|
+
this.irAlFondo();
|
|
962
1481
|
if (this.trabajo || !this.resolverLectura) {
|
|
963
1482
|
if (v) {
|
|
964
|
-
this.cola
|
|
965
|
-
this.mostrarAviso(tt('tui.en_cola'));
|
|
1483
|
+
this.cola.push(crudo);
|
|
1484
|
+
this.mostrarAviso(this.cola.length > 1 ? tt('tui.en_cola_n', { n: this.cola.length }) : tt('tui.en_cola'));
|
|
966
1485
|
}
|
|
967
1486
|
return;
|
|
968
1487
|
}
|
|
969
1488
|
const r = this.resolverLectura;
|
|
970
1489
|
this.resolverLectura = null;
|
|
971
|
-
if (v)
|
|
972
|
-
this.anadir(
|
|
1490
|
+
if (v && v !== '!')
|
|
1491
|
+
this.anadir(this.bloqueDeEnvio(crudo));
|
|
973
1492
|
else
|
|
974
1493
|
this.pintar();
|
|
975
1494
|
r(this.expandir(crudo));
|
|
@@ -986,6 +1505,14 @@ export class Superficie {
|
|
|
986
1505
|
this.foco = k.t === 'foco_si';
|
|
987
1506
|
return;
|
|
988
1507
|
}
|
|
1508
|
+
if (k.t === 'raton')
|
|
1509
|
+
return this.alRaton(k);
|
|
1510
|
+
if (k.t === 'pagina_arriba' || k.t === 'pagina_abajo')
|
|
1511
|
+
return this.desplazar((k.t === 'pagina_arriba' ? 1 : -1) * Math.max(1, this.filasDeVista() - 2));
|
|
1512
|
+
if (k.t === 'fondo')
|
|
1513
|
+
return this.irAlFondo();
|
|
1514
|
+
if (k.t === 'suspender')
|
|
1515
|
+
return this.suspender();
|
|
989
1516
|
if (this.pregunta)
|
|
990
1517
|
return this.teclaDePregunta(k);
|
|
991
1518
|
if (k.t !== 'ctrlc' && this.ctrlC && !this.trabajo) {
|
|
@@ -1007,13 +1534,13 @@ export class Superficie {
|
|
|
1007
1534
|
const imagen = rutaDeImagenPegada(v);
|
|
1008
1535
|
if (imagen) {
|
|
1009
1536
|
this.imagenes.push(imagen);
|
|
1010
|
-
this.unidades.splice(this.cursor, 0,
|
|
1537
|
+
this.unidades.splice(this.cursor, 0, `${this.imagenes.length - 1}`, ' ');
|
|
1011
1538
|
this.cursor += 2;
|
|
1012
1539
|
break;
|
|
1013
1540
|
}
|
|
1014
1541
|
if (v.includes('\n') || v.length > PEGADO_LARGO) {
|
|
1015
1542
|
this.pegados.push(v);
|
|
1016
|
-
this.unidades.splice(this.cursor, 0,
|
|
1543
|
+
this.unidades.splice(this.cursor, 0, `${this.pegados.length - 1}`);
|
|
1017
1544
|
this.cursor++;
|
|
1018
1545
|
}
|
|
1019
1546
|
else
|
|
@@ -1042,6 +1569,8 @@ export class Superficie {
|
|
|
1042
1569
|
this.menuCerradoPara = valor;
|
|
1043
1570
|
else if (this.trabajo)
|
|
1044
1571
|
this.trabajo.alParar();
|
|
1572
|
+
else if (this.subidas > 0 || this.volcadas < this.lineas.length)
|
|
1573
|
+
this.irAlFondo();
|
|
1045
1574
|
break;
|
|
1046
1575
|
case 'borrar':
|
|
1047
1576
|
if (this.cursor > 0) {
|
|
@@ -1083,6 +1612,8 @@ export class Superficie {
|
|
|
1083
1612
|
this.cursor = 0;
|
|
1084
1613
|
break;
|
|
1085
1614
|
case 'fin':
|
|
1615
|
+
if (this.cursor >= this.unidades.length && (this.subidas > 0 || this.volcadas < this.lineas.length))
|
|
1616
|
+
this.irAlFondo();
|
|
1086
1617
|
this.cursor = this.unidades.length;
|
|
1087
1618
|
break;
|
|
1088
1619
|
case 'borrar_linea':
|
|
@@ -1157,17 +1688,38 @@ export class Superficie {
|
|
|
1157
1688
|
break;
|
|
1158
1689
|
}
|
|
1159
1690
|
}
|
|
1691
|
+
get guardaDePregunta() {
|
|
1692
|
+
return this.o.guardaDePreguntaMs ?? (this.o.quieta ? 0 : 600);
|
|
1693
|
+
}
|
|
1160
1694
|
teclaDePregunta(k) {
|
|
1161
1695
|
const p = this.pregunta;
|
|
1162
1696
|
const n = p.opciones.length;
|
|
1697
|
+
const ahora = Date.now();
|
|
1698
|
+
if (k.t === 'esc' || k.t === 'ctrlc')
|
|
1699
|
+
return this.responder(p.indiceNo);
|
|
1700
|
+
const r0 = k.t === 'texto' ? k.v.trim().toLowerCase() : '';
|
|
1701
|
+
const esRespuesta = k.t === 'texto' && (/^[1-9]$/.test(r0) || ((r0 === 'y' || r0 === 'n') && p.indiceNo !== null));
|
|
1702
|
+
if (k.t === 'texto' && !esRespuesta) {
|
|
1703
|
+
this.insertar(k.v);
|
|
1704
|
+
p.escribiendo = true;
|
|
1705
|
+
p.sordaHasta = Math.max(p.sordaHasta, ahora + this.guardaDePregunta);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (ahora < p.sordaHasta) {
|
|
1709
|
+
if (k.t === 'texto' && p.escribiendo) {
|
|
1710
|
+
this.insertar(k.v);
|
|
1711
|
+
p.sordaHasta = ahora + this.guardaDePregunta;
|
|
1712
|
+
}
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1163
1715
|
if (k.t === 'texto') {
|
|
1164
1716
|
const r = k.v.trim().toLowerCase();
|
|
1165
1717
|
const num = Number(r);
|
|
1166
1718
|
if (Number.isInteger(num) && num >= 1 && num <= n)
|
|
1167
1719
|
return this.responder(num - 1);
|
|
1168
|
-
if (r === 'n')
|
|
1169
|
-
return this.responder(p.
|
|
1170
|
-
if (r === 'y' &&
|
|
1720
|
+
if (r === 'n' && p.indiceNo !== null)
|
|
1721
|
+
return this.responder(p.indiceNo);
|
|
1722
|
+
if (r === 'y' && p.siConY)
|
|
1171
1723
|
return this.responder(0);
|
|
1172
1724
|
return;
|
|
1173
1725
|
}
|
|
@@ -1177,8 +1729,6 @@ export class Superficie {
|
|
|
1177
1729
|
p.elegida = (p.elegida + 1) % n;
|
|
1178
1730
|
else if (k.t === 'intro')
|
|
1179
1731
|
this.responder(p.elegida);
|
|
1180
|
-
else if (k.t === 'esc' || k.t === 'ctrlc')
|
|
1181
|
-
this.responder(p.valores.indexOf('no'));
|
|
1182
1732
|
}
|
|
1183
1733
|
get _lineas() {
|
|
1184
1734
|
return this.lineas;
|
|
@@ -1192,6 +1742,9 @@ export class Superficie {
|
|
|
1192
1742
|
get _trabajo() {
|
|
1193
1743
|
return this.trabajo;
|
|
1194
1744
|
}
|
|
1745
|
+
get _zonas() {
|
|
1746
|
+
return this.zonas;
|
|
1747
|
+
}
|
|
1195
1748
|
}
|
|
1196
1749
|
function sinColorSimple(t) {
|
|
1197
1750
|
return t.replace(/\x1b\[[0-9;]*m/g, '');
|