@getparallel/parx 0.4.3 → 0.5.0

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/dist/tui.js CHANGED
@@ -1,9 +1,11 @@
1
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
- import { ALIAS_COMANDO, COMANDOS, t as tt } from "./textos.js";
3
+ import { ALIAS_COMANDO, ALIAS_DESDE, COMANDOS, t as tt } from "./textos.js";
4
4
  import { MODELOS, ORDEN_DE_MODELOS } from "./modelos.js";
5
5
  import { consejo, ordenDeConsejos } from "./consejos.js";
6
+ import { conexionesQueSalen, insertarMencion, mencionEnLaCaja, mencionTerminada } from "./menciones.js";
6
7
  export { anchoDe } from "./texto.js";
8
+ import { conElipsis, fraseDeEspera } from "./actividad.js";
7
9
  export const MARGEN = 2;
8
10
  export function anchoUtil(ancho) {
9
11
  return Math.max(10, ancho - MARGEN * 2);
@@ -287,9 +289,9 @@ function teclaDeRaton(b, x, y, soltar, botonX10) {
287
289
  }
288
290
  export const RATON_SI = '\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h';
289
291
  export const RATON_NO = '\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?1006l';
290
- const CON_VALOR = new Set(['mode', 'model', 'tips', 'notify', 'teach', 'mouse']);
292
+ const CON_VALOR = new Set(['mode', 'model', 'tips', 'notify', 'teach', 'mouse', 'animation']);
291
293
  const CON_TEXTO = new Set(['folder']);
292
- const SE_MANDAN_SOLOS = new Set(['teach', 'notify', 'tips', 'folder', 'mouse']);
294
+ const SE_MANDAN_SOLOS = new Set(['teach', 'notify', 'tips', 'folder', 'mouse', 'animation']);
293
295
  const MODOS_DEL_MENU = ['ask', 'auto', 'read', 'bypass'];
294
296
  export function opcionesDelMenu(valor) {
295
297
  if (!valor.startsWith('/') || valor.includes('\n'))
@@ -300,7 +302,7 @@ export function opcionesDelMenu(valor) {
300
302
  const q = sinBarra.toLocaleLowerCase();
301
303
  const out = [];
302
304
  for (const [cmd, descripcion] of COMANDOS) {
303
- const casa = cmd.startsWith(q) || (q.length > 0 && Object.entries(ALIAS_COMANDO).some(([alias, destino]) => destino === cmd && alias.startsWith(q)));
305
+ const casa = cmd.startsWith(q) || (q.length > 0 && Object.entries(ALIAS_COMANDO).some(([alias, destino]) => destino === cmd && alias.startsWith(q) && q.length >= (ALIAS_DESDE[alias] ?? 1)));
304
306
  if (!casa)
305
307
  continue;
306
308
  const conAlgo = CON_VALOR.has(cmd) || CON_TEXTO.has(cmd);
@@ -321,13 +323,30 @@ export function opcionesDelMenu(valor) {
321
323
  : cmd === 'model'
322
324
  ? ORDEN_DE_MODELOS.map((k) => [k, `${MODELOS[k].nombre} ${MODELOS[k].version}: ${MODELOS[k].descripcion}`])
323
325
  : [
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'],
326
+ ['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' : cmd === 'animation' ? 'Write answers out as they arrive' : 'Show them when parx opens'],
327
+ ['off', cmd === 'teach' ? 'Back to normal' : cmd === 'notify' ? 'No desktop notifications' : cmd === 'mouse' ? 'The terminal selects and scrolls as usual' : cmd === 'animation' ? 'Show answers whole, at once' : 'Don’t show them again'],
326
328
  ];
327
329
  return valores
328
330
  .filter(([v]) => v.startsWith(q))
329
331
  .map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode' ? { modo: v, ...(v === 'bypass' ? { peligro: true } : {}) } : {}) }));
330
332
  }
333
+ export function opcionesDeArroba(unidades, cursor, conexiones) {
334
+ if (!conexiones || !conexiones.length)
335
+ return null;
336
+ const m = mencionEnLaCaja(unidades, cursor);
337
+ if (!m || mencionTerminada(m.consulta, conexiones))
338
+ return null;
339
+ const salen = conexionesQueSalen(conexiones, m.consulta);
340
+ if (!salen.length)
341
+ return null;
342
+ return salen.map((x) => ({
343
+ nombre: `@${x.nombre}`,
344
+ descripcion: x.conectada ? tt('arroba.conectada') : tt('arroba.conectar'),
345
+ completar: '',
346
+ enviar: false,
347
+ mencion: { inicio: m.inicio, fin: cursor, conexion: x },
348
+ }));
349
+ }
331
350
  export function componerBarra(e, util) {
332
351
  return componerBarraConZonas(e, util).texto;
333
352
  }
@@ -380,17 +399,11 @@ export function duracion(ms) {
380
399
  export function acciones(n) {
381
400
  return n === 1 ? tt('estado.accion') : tt('estado.acciones', { n: n.toLocaleString('en-US') });
382
401
  }
383
- const FRASES = ['trabajo.ruta', 'trabajo.puntos', 'trabajo.carriles', 'trabajo.numeros', 'trabajo.mapa', 'trabajo.afinar', 'trabajo.agujas', 'trabajo.estacion'];
384
- export const MS_POR_FRASE = 2800;
385
- export function fraseDeEspera(ms, semilla = 0) {
386
- const vuelta = Math.floor(Math.max(0, ms) / MS_POR_FRASE);
387
- if (vuelta === 0)
388
- return `${tt(FRASES[0])}…`;
389
- return `${tt(FRASES[1 + ((semilla + vuelta - 1) % (FRASES.length - 1))])}…`;
390
- }
402
+ export { fraseDeEspera } from "./actividad.js";
391
403
  export function ponerTextoDeTrabajo(w, texto, anim = 'ruta', vivo = false, ahora = Date.now()) {
392
404
  if (texto) {
393
405
  w.texto = texto;
406
+ w.trasHerramientas = true;
394
407
  w.anim = anim;
395
408
  w.vivo = vivo;
396
409
  w.literalHasta = ahora + 1800;
@@ -401,12 +414,12 @@ export function ponerTextoDeTrabajo(w, texto, anim = 'ruta', vivo = false, ahora
401
414
  }
402
415
  }
403
416
  export function nuevoTrabajo(ahora = Date.now()) {
404
- return { texto: null, literalHasta: 0, vivo: false, anim: 'ruta', desde: ahora, esperaDesde: ahora, paso: 0, acciones: null, semilla: Math.floor(Math.random() * 7) };
417
+ return { texto: null, literalHasta: 0, vivo: false, anim: 'ruta', desde: ahora, esperaDesde: ahora, paso: 0, acciones: null, trasHerramientas: false };
405
418
  }
406
419
  export function textoDeTrabajo(w, ahora) {
407
420
  if (w.texto && (w.vivo || ahora < w.literalHasta))
408
- return { texto: w.texto, anim: w.anim };
409
- return { texto: fraseDeEspera(ahora - w.esperaDesde, w.semilla), anim: 'ruta' };
421
+ return { texto: conElipsis(w.texto), anim: w.anim };
422
+ return { texto: fraseDeEspera(ahora - w.esperaDesde, w.trasHerramientas), anim: 'ruta' };
410
423
  }
411
424
  export function filaDeTrabajo(w, ahora, ancho = Infinity) {
412
425
  const { texto, anim } = textoDeTrabajo(w, ahora);
@@ -653,7 +666,8 @@ export function componerCarril(d, ancho, alto) {
653
666
  const nombre = rellenar(recortar(o.nombre, anchoNombre - 1), anchoNombre);
654
667
  if (o.modo)
655
668
  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)}`;
669
+ const nota = o.mencion && !o.mencion.conexion.conectada ? c.marca(desc) : sel || sobre ? desc : c.tenue(c.gris(desc));
670
+ return `${m}${rellenar(`${marca} ${sel ? c.negrita(c.marca(nombre)) : sobre ? c.marca(nombre) : c.gris(nombre)}${nota}`, util)}`;
657
671
  });
658
672
  }
659
673
  }
@@ -712,6 +726,9 @@ export function opcionesDePregunta(tipo) {
712
726
  return { opciones: [tt('tui.si'), tt('tui.siempre'), tt('tui.no')], cortas: [tt('tui.si'), tt('tui.siempre_corto'), tt('tui.no')], valores: ['si', 'siempre', 'no'], elegida: 0 };
713
727
  }
714
728
  }
729
+ export function esNueva(v) {
730
+ return ALIAS_COMANDO[/^\/(\S+)$/.exec(v.trim())?.[1]?.toLowerCase() ?? ''] === 'new';
731
+ }
715
732
  const MAX_LINEAS = 4000;
716
733
  const MAX_BLOQUES = 1500;
717
734
  const PEGADO_LARGO = 280;
@@ -770,6 +787,8 @@ export class Superficie {
770
787
  borrador = [];
771
788
  menuCerradoPara = null;
772
789
  menuElegida = 0;
790
+ conexiones = null;
791
+ avisadoArroba = false;
773
792
  cola = [];
774
793
  ctrlC = 0;
775
794
  ejemplo = null;
@@ -804,9 +823,51 @@ export class Superficie {
804
823
  escribir(s) {
805
824
  this.o.salida.write(s);
806
825
  }
826
+ menuActual(valor = this.valorCrudo()) {
827
+ if (this.menuCerradoPara === valor)
828
+ return null;
829
+ const barra = opcionesDelMenu(valor);
830
+ if (barra && barra.length)
831
+ return barra;
832
+ const arroba = mencionEnLaCaja(this.unidades, this.cursor);
833
+ if (!arroba) {
834
+ this.avisadoArroba = false;
835
+ return null;
836
+ }
837
+ if (!this.avisadoArroba) {
838
+ this.avisadoArroba = true;
839
+ this.o.alArroba?.();
840
+ }
841
+ return opcionesDeArroba(this.unidades, this.cursor, this.conexiones);
842
+ }
843
+ fijarConexiones(lista) {
844
+ this.conexiones = lista ? [...lista] : null;
845
+ this.pintar();
846
+ }
847
+ ponerEnLaCaja(texto) {
848
+ this.ponerValor(texto);
849
+ this.menuCerradoPara = this.valorCrudo();
850
+ this.menuElegida = 0;
851
+ this.pintar();
852
+ }
853
+ elegirMencion(o) {
854
+ const m = o.mencion;
855
+ if (m.conexion.conectada) {
856
+ const r = insertarMencion(this.unidades, m.inicio, m.fin, m.conexion.nombre);
857
+ this.unidades = r.unidades;
858
+ this.cursor = r.cursor;
859
+ this.menuElegida = 0;
860
+ this.menuCerradoPara = null;
861
+ return;
862
+ }
863
+ this.menuCerradoPara = this.valorCrudo();
864
+ this.menuElegida = 0;
865
+ this.avisadoArroba = false;
866
+ this.o.alConectar?.(m.conexion);
867
+ }
807
868
  datos() {
808
869
  const valor = this.valorCrudo();
809
- const ops = this.menuCerradoPara === valor ? null : opcionesDelMenu(valor);
870
+ const ops = this.menuActual(valor);
810
871
  if (ops && this.menuElegida >= ops.length)
811
872
  this.menuElegida = Math.max(0, ops.length - 1);
812
873
  const pendientes = this.lineas.length - this.volcadas;
@@ -1045,6 +1106,98 @@ export class Superficie {
1045
1106
  this.escribir(s);
1046
1107
  this.pintar();
1047
1108
  }
1109
+ refrescarUltimo() {
1110
+ const b = this.ultimoBloque();
1111
+ if (!b)
1112
+ return;
1113
+ const k = this.ultimoAlto;
1114
+ if (this.lineas.length < k)
1115
+ return;
1116
+ const nuevas = sinBlancoDoble(b(this.ancho), this.ultimoTrasBlanco);
1117
+ const base = this.lineas.length - k;
1118
+ const viejas = this.lineas.slice(base);
1119
+ if (nuevas.length === k && nuevas.every((l, i) => l === viejas[i]))
1120
+ return;
1121
+ if (nuevas.length < k) {
1122
+ this.bloques[this.bloques.length - 1] = b;
1123
+ this.recomponer();
1124
+ return;
1125
+ }
1126
+ this.lineas.splice(base, k, ...nuevas);
1127
+ this.ultimoAlto = nuevas.length;
1128
+ if (!this.activa) {
1129
+ this.volcadas = this.lineas.length;
1130
+ this.recortarMemoria();
1131
+ return;
1132
+ }
1133
+ const subido = this.subidas > 0 || this.volcadas < base + k;
1134
+ const n = this.carrilPintadas || componerCarril(this.datos(), this.ancho, this.alto).carril.length;
1135
+ if (subido) {
1136
+ const desde = this.desplazadas(n) - this.subidas;
1137
+ const cambiaVisible = viejas.some((l, i) => base + i < this.volcadas && base + i >= desde && nuevas[i] !== l);
1138
+ if (cambiaVisible)
1139
+ this.vistaSucia = true;
1140
+ this.recortarMemoria();
1141
+ if (cambiaVisible || nuevas.length !== k)
1142
+ this.pintar();
1143
+ return;
1144
+ }
1145
+ const top = this.filaDelCarril(n);
1146
+ const tapadas = top - this.encimaPintadas;
1147
+ let s = '';
1148
+ for (let i = 0; i < k; i++) {
1149
+ if (nuevas[i] === viejas[i])
1150
+ continue;
1151
+ const fila = base + i - this.desplazadas(n) + 1;
1152
+ if (fila >= 1 && fila < tapadas)
1153
+ s += `\x1b[${fila};1H\x1b[2K${nuevas[i]}`;
1154
+ }
1155
+ if (s)
1156
+ this.escribir(`\x1b[?2026h\x1b7${s}\x1b8\x1b[?2026l`);
1157
+ if (nuevas.length > k) {
1158
+ this.escribir(this.destapar());
1159
+ this.volcar();
1160
+ this.pintar();
1161
+ }
1162
+ }
1163
+ reiniciar(bienvenida, consejos = []) {
1164
+ this.bloques = [];
1165
+ this.lineas = [];
1166
+ this.volcadas = 0;
1167
+ this.subidas = 0;
1168
+ this.vistaSucia = false;
1169
+ this.cola = [];
1170
+ this.aviso = null;
1171
+ this.ultimoAlto = 0;
1172
+ this.ultimoTrasBlanco = false;
1173
+ this.encimaPintadas = 0;
1174
+ this.sobre = null;
1175
+ this.pulsado = null;
1176
+ this.ctrlC = 0;
1177
+ this.alRevelar = null;
1178
+ this.ponerBienvenida(bienvenida, consejos);
1179
+ this.recomponer();
1180
+ }
1181
+ ponerBienvenida(bienvenida, consejos = []) {
1182
+ if (bienvenida)
1183
+ this.bloques.push(bienvenida);
1184
+ this.consejos = [];
1185
+ this.consejosVisibles = false;
1186
+ if (consejos.length) {
1187
+ const ocupado = (bienvenida ? bienvenida(this.ancho).length : 0) + componerCarril(this.datos(), this.ancho, this.alto).carril.length;
1188
+ let n = consejos.length;
1189
+ while (n > 0 && ocupado + bloqueDeConsejos(() => consejos.slice(0, n))(this.ancho).length > this.alto)
1190
+ n--;
1191
+ this.consejos = consejos.slice(0, n);
1192
+ this.consejosVisibles = n > 0;
1193
+ if (n > 0)
1194
+ this.bloques.push(bloqueDeConsejos(() => (this.consejosVisibles ? this.consejos : [])));
1195
+ }
1196
+ }
1197
+ alRevelar = null;
1198
+ revelando(fn) {
1199
+ this.alRevelar = fn;
1200
+ }
1048
1201
  recomponer(alEmpezar = false) {
1049
1202
  if (!this.activa)
1050
1203
  return;
@@ -1098,6 +1251,10 @@ export class Superficie {
1098
1251
  this.volcar();
1099
1252
  this.pintar();
1100
1253
  }
1254
+ nuevaTrasParar() {
1255
+ this.cola = ['/new'];
1256
+ this.mostrarAviso(null);
1257
+ }
1101
1258
  get _vista() {
1102
1259
  return { subidas: this.subidas, pendientes: this.lineas.length - this.volcadas };
1103
1260
  }
@@ -1175,18 +1332,7 @@ export class Superficie {
1175
1332
  if (this.activa)
1176
1333
  return;
1177
1334
  this.activa = true;
1178
- if (bienvenida)
1179
- this.bloques.push(bienvenida);
1180
- if (consejos.length) {
1181
- const ocupado = (bienvenida ? bienvenida(this.ancho).length : 0) + componerCarril(this.datos(), this.ancho, this.alto).carril.length;
1182
- let n = consejos.length;
1183
- while (n > 0 && ocupado + bloqueDeConsejos(() => consejos.slice(0, n))(this.ancho).length > this.alto)
1184
- n--;
1185
- this.consejos = consejos.slice(0, n);
1186
- this.consejosVisibles = n > 0;
1187
- if (n > 0)
1188
- this.bloques.push(bloqueDeConsejos(() => (this.consejosVisibles ? this.consejos : [])));
1189
- }
1335
+ this.ponerBienvenida(bienvenida, consejos);
1190
1336
  this.escribir(this.modosSi());
1191
1337
  try {
1192
1338
  this.o.entrada.setRawMode?.(true);
@@ -1321,7 +1467,7 @@ export class Superficie {
1321
1467
  const r = enCola;
1322
1468
  this.ejemplo = null;
1323
1469
  this.mostrarAviso(this.cola.length ? tt('tui.en_cola_n', { n: this.cola.length }) : null);
1324
- if (r.trim() && r.trim() !== '!')
1470
+ if (r.trim() && r.trim() !== '!' && !esNueva(r.trim()))
1325
1471
  this.anadir(this.bloqueDeEnvio(r));
1326
1472
  return Promise.resolve(this.expandir(r));
1327
1473
  }
@@ -1479,6 +1625,10 @@ export class Superficie {
1479
1625
  this.posHistorial = this.historial.length;
1480
1626
  this.irAlFondo();
1481
1627
  if (this.trabajo || !this.resolverLectura) {
1628
+ if (this.trabajo && this.o.alNuevaEnMarcha && esNueva(v)) {
1629
+ this.o.alNuevaEnMarcha();
1630
+ return;
1631
+ }
1482
1632
  if (v) {
1483
1633
  this.cola.push(crudo);
1484
1634
  this.mostrarAviso(this.cola.length > 1 ? tt('tui.en_cola_n', { n: this.cola.length }) : tt('tui.en_cola'));
@@ -1487,7 +1637,7 @@ export class Superficie {
1487
1637
  }
1488
1638
  const r = this.resolverLectura;
1489
1639
  this.resolverLectura = null;
1490
- if (v && v !== '!')
1640
+ if (v && v !== '!' && !esNueva(v))
1491
1641
  this.anadir(this.bloqueDeEnvio(crudo));
1492
1642
  else
1493
1643
  this.pintar();
@@ -1507,6 +1657,11 @@ export class Superficie {
1507
1657
  }
1508
1658
  if (k.t === 'raton')
1509
1659
  return this.alRaton(k);
1660
+ if (this.alRevelar && k.t !== 'pagina_arriba' && k.t !== 'pagina_abajo' && k.t !== 'fondo') {
1661
+ const f = this.alRevelar;
1662
+ this.alRevelar = null;
1663
+ f();
1664
+ }
1510
1665
  if (k.t === 'pagina_arriba' || k.t === 'pagina_abajo')
1511
1666
  return this.desplazar((k.t === 'pagina_arriba' ? 1 : -1) * Math.max(1, this.filasDeVista() - 2));
1512
1667
  if (k.t === 'fondo')
@@ -1521,7 +1676,7 @@ export class Superficie {
1521
1676
  this.aviso = null;
1522
1677
  }
1523
1678
  const valor = this.valorCrudo();
1524
- const ops = this.menuCerradoPara === valor ? null : opcionesDelMenu(valor);
1679
+ const ops = this.menuActual(valor);
1525
1680
  const menu = ops && ops.length ? ops : null;
1526
1681
  switch (k.t) {
1527
1682
  case 'texto':
@@ -1548,6 +1703,10 @@ export class Superficie {
1548
1703
  break;
1549
1704
  }
1550
1705
  case 'intro':
1706
+ if (menu && menu[this.menuElegida]?.mencion) {
1707
+ this.elegirMencion(menu[this.menuElegida]);
1708
+ break;
1709
+ }
1551
1710
  if (menu) {
1552
1711
  const o = menu[this.menuElegida];
1553
1712
  this.ponerValor(o.completar);
@@ -1559,6 +1718,10 @@ export class Superficie {
1559
1718
  this.enviar();
1560
1719
  break;
1561
1720
  case 'tab':
1721
+ if (menu && menu[this.menuElegida]?.mencion) {
1722
+ this.elegirMencion(menu[this.menuElegida]);
1723
+ break;
1724
+ }
1562
1725
  if (menu) {
1563
1726
  this.ponerValor(menu[this.menuElegida].completar);
1564
1727
  this.menuElegida = 0;
package/dist/ui.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { animacion, c, capacidades, SIMBOLOS } from "./marca.js";
2
2
  import { cuantos, t } from "./textos.js";
3
3
  import { trozos } from "./diff.js";
4
+ import { caracteresDe, caracteresVisibles, cursorEncendido, duracionDeRevelado, MS_MAX_INTERMEDIO, MS_MAX_RESPUESTA, MS_POR_FOTOGRAMA, revelarLineas, simboloDeCursor } from "./actividad.js";
4
5
  import { anchoDe, envolver, recortar, recortarMedio, rellenar, sinColor } from "./texto.js";
5
6
  import { anchoUtil, bloqueDeCierre, bloqueDeLinea, bloqueDeTexto, filaDeTrabajo, MARGEN, nuevoTrabajo, opcionesDePregunta, ponerTextoDeTrabajo, } from "./tui.js";
6
7
  export function leerRespuesta(texto, tipo = 'normal') {
@@ -89,6 +90,8 @@ export class Pantalla {
89
90
  };
90
91
  }
91
92
  bloque(b, grupo = 'otro') {
93
+ if (this.revelado)
94
+ this.terminarRevelado();
92
95
  const bc = this.conCarril(this.conAire(b, grupo));
93
96
  if (this.superficie) {
94
97
  this.superficie.anadir(bc);
@@ -290,42 +293,147 @@ export class Pantalla {
290
293
  }
291
294
  }
292
295
  texto(md) {
293
- const lineas = md.replace(/\r/g, '').split('\n');
294
- this.bloque((ancho) => {
295
- const util = anchoUtil(ancho);
296
- const pre = ' '.repeat(MARGEN);
297
- const out = [];
298
- let enBloque = false;
299
- for (const linea of lineas) {
300
- if (/^```/.test(linea.trim())) {
301
- enBloque = !enBloque;
302
- continue;
303
- }
304
- if (enBloque) {
305
- out.push(`${pre} ${c.marca(recortar(linea.replace(/\t/g, ' '), util - 2))}`);
306
- continue;
307
- }
308
- const titulo = /^#{1,6}\s+(.*)$/.exec(linea);
309
- if (titulo) {
310
- for (const l of envolver(c.negrita(titulo[1]), util))
311
- out.push(`${pre}${l}`);
312
- continue;
313
- }
314
- let l = linea;
315
- let sangria = '';
316
- const lista = /^(\s*)([-*]|\d+[.)])\s+/.exec(l);
317
- if (lista) {
318
- const marca = /\d/.test(lista[2]) ? lista[2] : SIMBOLOS.punto === '●' ? '·' : '-';
319
- l = `${lista[1]}${c.claro(marca)} ${l.slice(lista[0].length)}`;
320
- sangria = ' '.repeat(anchoDe(lista[1]) + anchoDe(marca) + 1);
321
- }
322
- l = l.replace(/\*\*([^*]+)\*\*/g, (_m, x) => c.negrita(x));
323
- l = l.replace(/`([^`]+)`/g, (_m, x) => c.marca(x));
324
- for (const p of envolver(l, util, sangria))
325
- out.push(`${pre}${p}`);
296
+ this.terminarRevelado();
297
+ this.bloque(bloqueDeMarkdown(md), 'texto');
298
+ }
299
+ animar = true;
300
+ revelado = null;
301
+ terminarRevelado() {
302
+ const f = this.revelado;
303
+ this.revelado = null;
304
+ f?.();
305
+ }
306
+ textoAnimado(md, o = {}) {
307
+ this.terminarRevelado();
308
+ const conSuperficie = this.superficie !== null;
309
+ if (!this.animar || this.carril || !this.tty || (!conSuperficie && !process.stdout.isTTY)) {
310
+ this.texto(md);
311
+ return Promise.resolve();
312
+ }
313
+ const completo = bloqueDeMarkdown(md);
314
+ const maxMs = o.intermedio ? MS_MAX_INTERMEDIO : MS_MAX_RESPUESTA;
315
+ const estado = { inicio: Date.now(), fin: false, ahora: Date.now() };
316
+ const total = caracteresDe(completo(this.superficie?.ancho ?? Math.max(20, process.stdout.columns || 80)));
317
+ const duracion = duracionDeRevelado(total, maxMs);
318
+ const parcial = (ancho) => {
319
+ const lineas = completo(ancho);
320
+ if (estado.fin)
321
+ return lineas;
322
+ const ms = estado.ahora - estado.inicio;
323
+ const n = caracteresVisibles(caracteresDe(lineas), ms, duracion);
324
+ return revelarLineas(lineas, n, cursorEncendido(ms) ? simboloDeCursor() : ' ', anchoUtil(ancho) + MARGEN * 2);
325
+ };
326
+ return new Promise((resolver) => {
327
+ let reloj = null;
328
+ const acabar = () => {
329
+ if (estado.fin)
330
+ return;
331
+ estado.fin = true;
332
+ if (reloj)
333
+ clearInterval(reloj);
334
+ if (this.revelado === acabar)
335
+ this.revelado = null;
336
+ this.superficie?.revelando(null);
337
+ if (conSuperficie)
338
+ this.superficie.refrescarUltimo();
339
+ else
340
+ this.revelarEnLinea(completo, Infinity);
341
+ resolver();
342
+ };
343
+ if (conSuperficie) {
344
+ this.bloque(parcial, 'texto');
345
+ this.superficie.revelando(acabar);
326
346
  }
327
- return out;
328
- }, 'texto');
347
+ else {
348
+ this.pausarLinea();
349
+ this.ultimoGrupo = 'texto';
350
+ this.lineaEnCurso = { escritas: 0, parcial: '' };
351
+ this.revelarEnLinea(completo, 0);
352
+ }
353
+ this.revelado = acabar;
354
+ const fotograma = () => {
355
+ estado.ahora = Date.now();
356
+ if (estado.ahora - estado.inicio >= duracion)
357
+ return acabar();
358
+ if (conSuperficie)
359
+ this.superficie.refrescarUltimo();
360
+ else
361
+ this.revelarEnLinea(completo, caracteresVisibles(total, estado.ahora - estado.inicio, duracion), cursorEncendido(estado.ahora - estado.inicio));
362
+ };
363
+ reloj = setInterval(fotograma, MS_POR_FOTOGRAMA);
364
+ reloj.unref?.();
365
+ });
329
366
  }
367
+ lineaEnCurso = null;
368
+ revelarEnLinea(completo, n, cursor = false) {
369
+ const l = this.lineaEnCurso;
370
+ if (!l)
371
+ return;
372
+ const ancho = Math.max(20, process.stdout.columns || capacidades().ancho || 80);
373
+ const lineas = completo(ancho);
374
+ const vistas = revelarLineas(lineas, n, null);
375
+ let s = '';
376
+ while (l.escritas < vistas.length - 1 || (n >= caracteresDe(lineas) && l.escritas < lineas.length)) {
377
+ s += `\r\x1b[2K${lineas[l.escritas]}\n`;
378
+ l.escritas++;
379
+ l.parcial = '';
380
+ }
381
+ if (n < caracteresDe(lineas)) {
382
+ const parcial = vistas[l.escritas] ?? '';
383
+ s += `\r\x1b[2K${parcial}${cursor ? `${anchoDe(parcial) ? ' ' : ''}${simboloDeCursor()}` : ''}`;
384
+ l.parcial = parcial;
385
+ }
386
+ else {
387
+ this.lineaEnCurso = null;
388
+ if (lineas.length)
389
+ this.enBlanco = lineas[lineas.length - 1].trim() === '';
390
+ }
391
+ if (s)
392
+ process.stdout.write(s);
393
+ }
394
+ reiniciar() {
395
+ this.terminarRevelado();
396
+ this.ultimoGrupo = null;
397
+ this.enBlanco = true;
398
+ this.lecturas = null;
399
+ }
400
+ }
401
+ export function bloqueDeMarkdown(md) {
402
+ const lineas = md.replace(/\r/g, '').split('\n');
403
+ return (ancho) => {
404
+ const util = anchoUtil(ancho);
405
+ const pre = ' '.repeat(MARGEN);
406
+ const out = [];
407
+ let enBloque = false;
408
+ for (const linea of lineas) {
409
+ if (/^```/.test(linea.trim())) {
410
+ enBloque = !enBloque;
411
+ continue;
412
+ }
413
+ if (enBloque) {
414
+ out.push(`${pre} ${c.marca(recortar(linea.replace(/\t/g, ' '), util - 2))}`);
415
+ continue;
416
+ }
417
+ const titulo = /^#{1,6}\s+(.*)$/.exec(linea);
418
+ if (titulo) {
419
+ for (const l of envolver(c.negrita(titulo[1]), util))
420
+ out.push(`${pre}${l}`);
421
+ continue;
422
+ }
423
+ let l = linea;
424
+ let sangria = '';
425
+ const lista = /^(\s*)([-*]|\d+[.)])\s+/.exec(l);
426
+ if (lista) {
427
+ const marca = /\d/.test(lista[2]) ? lista[2] : SIMBOLOS.punto === '●' ? '·' : '-';
428
+ l = `${lista[1]}${c.claro(marca)} ${l.slice(lista[0].length)}`;
429
+ sangria = ' '.repeat(anchoDe(lista[1]) + anchoDe(marca) + 1);
430
+ }
431
+ l = l.replace(/\*\*([^*]+)\*\*/g, (_m, x) => c.negrita(x));
432
+ l = l.replace(/`([^`]+)`/g, (_m, x) => c.marca(x));
433
+ for (const p of envolver(l, util, sangria))
434
+ out.push(`${pre}${p}`);
435
+ }
436
+ return out;
437
+ };
330
438
  }
331
439
  export { bloqueDeLinea };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getparallel/parx",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "parx: the coding agent of Parallel in your terminal. Reads and edits your project, runs commands and tests, and does coding tasks end to end. Mac, Windows and Linux.",
5
5
  "keywords": [
6
6
  "parx",