chocolatito-code 1.4.3 → 1.6.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/index.js +12 -0
- package/dist/ui/historial.d.ts +49 -0
- package/dist/ui/historial.js +92 -0
- package/dist/ui/ink/App.d.ts +25 -0
- package/dist/ui/ink/App.js +59 -0
- package/dist/ui/ink/Prompt.d.ts +9 -1
- package/dist/ui/ink/Prompt.js +64 -16
- package/dist/ui/ink/control.d.ts +36 -0
- package/dist/ui/ink/control.js +54 -0
- package/dist/ui/ink/montarApp.d.ts +2 -0
- package/dist/ui/ink/montarApp.js +36 -0
- package/dist/ui/ink/montarPrompt.js +12 -0
- package/dist/ui/pantalla.d.ts +31 -0
- package/dist/ui/pantalla.js +105 -0
- package/dist/ui/pieFijo.d.ts +10 -0
- package/dist/ui/pieFijo.js +39 -3
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@ import { codigoDeSalida, EXIT_OK, EXIT_FALLO, EXIT_USO, EXIT_LICENCIA } from "./
|
|
|
15
15
|
import { showBanner, animateStartupBanner, showHelp, showEffortMenu } from "./ui/banner.js";
|
|
16
16
|
import { fijarMotor } from "./ui/motorActual.js";
|
|
17
17
|
import { elegirDeLista } from "./ui/selector.js";
|
|
18
|
+
import { entrarEnPantallaFija, pantallaFijaPedida } from "./ui/pantalla.js";
|
|
19
|
+
import { montarArbol } from "./ui/ink/montarApp.js";
|
|
18
20
|
import { reafirmarModoCrudo } from "./ui/keyboardGuard.js";
|
|
19
21
|
import { askInteractivePrompt, SLASH_COMMANDS } from "./ui/prompt.js";
|
|
20
22
|
import { changeDir } from "./tools/changeDir.js";
|
|
@@ -235,6 +237,16 @@ ${nodeViejo}
|
|
|
235
237
|
const hookManager = new HookManager(context.cwd);
|
|
236
238
|
const sessionManager = new SessionManager();
|
|
237
239
|
const sessionId = `session_${Date.now()}`;
|
|
240
|
+
// La barra de abajo solo puede quedarse clavada si el programa toma la
|
|
241
|
+
// pantalla entera. Se pide con CHOCOLATITO_PANTALLA=fija y se paga con el
|
|
242
|
+
// historial del terminal: ver ui/pantalla.ts.
|
|
243
|
+
if (pantallaFijaPedida()) {
|
|
244
|
+
entrarEnPantallaFija();
|
|
245
|
+
// Entrar y empezar a dibujar son la misma decision: entrar sin montar el
|
|
246
|
+
// arbol deja una consola en blanco de la que solo se sale cerrando la
|
|
247
|
+
// ventana.
|
|
248
|
+
montarArbol();
|
|
249
|
+
}
|
|
238
250
|
let currentModel = DEFAULT_ESPECTRO;
|
|
239
251
|
// La barra de estado lo lee de aqui. Fijarlo al arrancar y no solo al
|
|
240
252
|
// cambiarlo: si no, hasta el primer /effort la barra no dice nada.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LO QUE HA SALIDO POR PANTALLA, GUARDADO EN MEMORIA
|
|
3
|
+
*
|
|
4
|
+
* POR QUE HACE FALTA
|
|
5
|
+
*
|
|
6
|
+
* En la pantalla normal el historial lo lleva el terminal: sale una línea, se va
|
|
7
|
+
* hacia arriba, y la rueda del ratón la recupera. Por eso la barra de abajo sube
|
|
8
|
+
* con el scroll: es una línea más del historial, no una capa encima.
|
|
9
|
+
*
|
|
10
|
+
* En la pantalla alternativa —la que usan vim o htop— el terminal NO guarda
|
|
11
|
+
* nada. A cambio, la barra se queda clavada de verdad. Pero si nadie recuerda lo
|
|
12
|
+
* que salió, la conversación desaparece en cuanto pasa de una pantalla, que sería
|
|
13
|
+
* mucho peor que el problema que se quiere resolver.
|
|
14
|
+
*
|
|
15
|
+
* Así que aquí se guarda. Es el precio de tener la barra fija: el historial deja
|
|
16
|
+
* de ser del terminal y pasa a ser nuestro.
|
|
17
|
+
*
|
|
18
|
+
* POR QUE SE GUARDA POR LÍNEAS Y NO EL FLUJO CRUDO
|
|
19
|
+
*
|
|
20
|
+
* Lo que llega trae códigos de color y a veces medio renglón sin terminar. Para
|
|
21
|
+
* poder pintar "las últimas N líneas" hay que saber dónde acaba cada una, así
|
|
22
|
+
* que se parte por saltos y el resto sin terminar se queda esperando al suyo.
|
|
23
|
+
* Los colores se conservan tal cual: recortarlos aquí sería pintar la
|
|
24
|
+
* conversación en gris.
|
|
25
|
+
*/
|
|
26
|
+
/** Añade lo que se acaba de escribir. Acepta trozos a medio renglón. */
|
|
27
|
+
export declare function apuntar(texto: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Todas las líneas, con el resto sin terminar como última.
|
|
30
|
+
*
|
|
31
|
+
* Se incluye a propósito: mientras el modelo escribe una frase larga, el resto
|
|
32
|
+
* ES lo que está saliendo. Ocultarlo hasta el salto haría que la respuesta
|
|
33
|
+
* apareciera a tirones, un renglón entero de golpe.
|
|
34
|
+
*/
|
|
35
|
+
export declare function todas(): string[];
|
|
36
|
+
export declare function cuantas(): number;
|
|
37
|
+
/** Se llama en cada escritura, para que quien pinte se entere. */
|
|
38
|
+
export declare function alEscribir(cb: () => void): () => void;
|
|
39
|
+
export declare function vaciar(): void;
|
|
40
|
+
/**
|
|
41
|
+
* La ventana visible: `alto` líneas terminando `desdeElFinal` por encima del
|
|
42
|
+
* final.
|
|
43
|
+
*
|
|
44
|
+
* `desdeElFinal` es cuánto se ha subido con el scroll. Cero es el fondo, que es
|
|
45
|
+
* donde se está mientras se trabaja.
|
|
46
|
+
*/
|
|
47
|
+
export declare function ventana(alto: number, desdeElFinal?: number): string[];
|
|
48
|
+
/** Cuánto se puede subir todavía. Sirve para no pasarse del principio. */
|
|
49
|
+
export declare function tope(alto: number): number;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LO QUE HA SALIDO POR PANTALLA, GUARDADO EN MEMORIA
|
|
3
|
+
*
|
|
4
|
+
* POR QUE HACE FALTA
|
|
5
|
+
*
|
|
6
|
+
* En la pantalla normal el historial lo lleva el terminal: sale una línea, se va
|
|
7
|
+
* hacia arriba, y la rueda del ratón la recupera. Por eso la barra de abajo sube
|
|
8
|
+
* con el scroll: es una línea más del historial, no una capa encima.
|
|
9
|
+
*
|
|
10
|
+
* En la pantalla alternativa —la que usan vim o htop— el terminal NO guarda
|
|
11
|
+
* nada. A cambio, la barra se queda clavada de verdad. Pero si nadie recuerda lo
|
|
12
|
+
* que salió, la conversación desaparece en cuanto pasa de una pantalla, que sería
|
|
13
|
+
* mucho peor que el problema que se quiere resolver.
|
|
14
|
+
*
|
|
15
|
+
* Así que aquí se guarda. Es el precio de tener la barra fija: el historial deja
|
|
16
|
+
* de ser del terminal y pasa a ser nuestro.
|
|
17
|
+
*
|
|
18
|
+
* POR QUE SE GUARDA POR LÍNEAS Y NO EL FLUJO CRUDO
|
|
19
|
+
*
|
|
20
|
+
* Lo que llega trae códigos de color y a veces medio renglón sin terminar. Para
|
|
21
|
+
* poder pintar "las últimas N líneas" hay que saber dónde acaba cada una, así
|
|
22
|
+
* que se parte por saltos y el resto sin terminar se queda esperando al suyo.
|
|
23
|
+
* Los colores se conservan tal cual: recortarlos aquí sería pintar la
|
|
24
|
+
* conversación en gris.
|
|
25
|
+
*/
|
|
26
|
+
/** Tope de líneas recordadas. Más allá, se olvidan las de arriba. */
|
|
27
|
+
const MAXIMO = Number(process.env.CHOCOLATITO_HISTORIAL_LINEAS || 5000);
|
|
28
|
+
let lineas = [];
|
|
29
|
+
let resto = "";
|
|
30
|
+
const oyentes = [];
|
|
31
|
+
/** Añade lo que se acaba de escribir. Acepta trozos a medio renglón. */
|
|
32
|
+
export function apuntar(texto) {
|
|
33
|
+
if (!texto)
|
|
34
|
+
return;
|
|
35
|
+
const completo = resto + texto.replace(/\r\n/g, "\n");
|
|
36
|
+
const partes = completo.split("\n");
|
|
37
|
+
// El último trozo no lleva salto: todavía no es una línea terminada.
|
|
38
|
+
resto = partes.pop() ?? "";
|
|
39
|
+
for (const l of partes)
|
|
40
|
+
lineas.push(l);
|
|
41
|
+
if (lineas.length > MAXIMO)
|
|
42
|
+
lineas = lineas.slice(lineas.length - MAXIMO);
|
|
43
|
+
for (const cb of oyentes) {
|
|
44
|
+
try {
|
|
45
|
+
cb();
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Todas las líneas, con el resto sin terminar como última.
|
|
52
|
+
*
|
|
53
|
+
* Se incluye a propósito: mientras el modelo escribe una frase larga, el resto
|
|
54
|
+
* ES lo que está saliendo. Ocultarlo hasta el salto haría que la respuesta
|
|
55
|
+
* apareciera a tirones, un renglón entero de golpe.
|
|
56
|
+
*/
|
|
57
|
+
export function todas() {
|
|
58
|
+
return resto ? [...lineas, resto] : lineas;
|
|
59
|
+
}
|
|
60
|
+
export function cuantas() {
|
|
61
|
+
return todas().length;
|
|
62
|
+
}
|
|
63
|
+
/** Se llama en cada escritura, para que quien pinte se entere. */
|
|
64
|
+
export function alEscribir(cb) {
|
|
65
|
+
oyentes.push(cb);
|
|
66
|
+
return () => {
|
|
67
|
+
const i = oyentes.indexOf(cb);
|
|
68
|
+
if (i >= 0)
|
|
69
|
+
oyentes.splice(i, 1);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function vaciar() {
|
|
73
|
+
lineas = [];
|
|
74
|
+
resto = "";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* La ventana visible: `alto` líneas terminando `desdeElFinal` por encima del
|
|
78
|
+
* final.
|
|
79
|
+
*
|
|
80
|
+
* `desdeElFinal` es cuánto se ha subido con el scroll. Cero es el fondo, que es
|
|
81
|
+
* donde se está mientras se trabaja.
|
|
82
|
+
*/
|
|
83
|
+
export function ventana(alto, desdeElFinal = 0) {
|
|
84
|
+
const todo = todas();
|
|
85
|
+
const fin = Math.max(0, todo.length - Math.max(0, desdeElFinal));
|
|
86
|
+
const inicio = Math.max(0, fin - Math.max(1, alto));
|
|
87
|
+
return todo.slice(inicio, fin);
|
|
88
|
+
}
|
|
89
|
+
/** Cuánto se puede subir todavía. Sirve para no pasarse del principio. */
|
|
90
|
+
export function tope(alto) {
|
|
91
|
+
return Math.max(0, cuantas() - Math.max(1, alto));
|
|
92
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* EL ÁRBOL ÚNICO
|
|
4
|
+
*
|
|
5
|
+
* POR QUE EXISTE
|
|
6
|
+
*
|
|
7
|
+
* Antes Ink solo era dueño del prompt: se montaba para pedir una orden y se
|
|
8
|
+
* desmontaba al enviarla. Mientras el agente trabajaba, el terminal volvía a ser
|
|
9
|
+
* de siempre y la barra de abajo la pintaba `pieFijo` borrando y repintando a
|
|
10
|
+
* mano.
|
|
11
|
+
*
|
|
12
|
+
* Eso son DOS dueños del mismo trozo de pantalla turnándose, y de ahí salían
|
|
13
|
+
* casi todas las quejas: la barra que sube con el scroll, el hueco que aparece,
|
|
14
|
+
* el marco que se descuadra. Cada arreglo era coordinar mejor a los dos dueños.
|
|
15
|
+
*
|
|
16
|
+
* Aquí hay uno solo, y vive toda la sesión. Lo que sale del agente entra en el
|
|
17
|
+
* historial (historial.ts) y se pinta arriba; abajo va SIEMPRE la barra, sea la
|
|
18
|
+
* de escribir o la de trabajar. Nadie tiene que ponerse de acuerdo con nadie.
|
|
19
|
+
*
|
|
20
|
+
* Y POR ESO LA BARRA SE QUEDA QUIETA
|
|
21
|
+
*
|
|
22
|
+
* No porque se repinte rápido, sino porque es la última fila de un árbol que
|
|
23
|
+
* ocupa la ventana entera. No hay nada que pueda moverla, ni la rueda del ratón.
|
|
24
|
+
*/
|
|
25
|
+
export declare function App(): React.ReactElement;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Box, Text, useStdout } from "ink";
|
|
4
|
+
import { Prompt } from "./Prompt.js";
|
|
5
|
+
import { alEscribir, tope, ventana } from "../historial.js";
|
|
6
|
+
import { cuandoCambieElPie, lineasDelPie } from "../pieFijo.js";
|
|
7
|
+
import { alCambiarElTurno, estadoDelTurno } from "./control.js";
|
|
8
|
+
/**
|
|
9
|
+
* EL ÁRBOL ÚNICO
|
|
10
|
+
*
|
|
11
|
+
* POR QUE EXISTE
|
|
12
|
+
*
|
|
13
|
+
* Antes Ink solo era dueño del prompt: se montaba para pedir una orden y se
|
|
14
|
+
* desmontaba al enviarla. Mientras el agente trabajaba, el terminal volvía a ser
|
|
15
|
+
* de siempre y la barra de abajo la pintaba `pieFijo` borrando y repintando a
|
|
16
|
+
* mano.
|
|
17
|
+
*
|
|
18
|
+
* Eso son DOS dueños del mismo trozo de pantalla turnándose, y de ahí salían
|
|
19
|
+
* casi todas las quejas: la barra que sube con el scroll, el hueco que aparece,
|
|
20
|
+
* el marco que se descuadra. Cada arreglo era coordinar mejor a los dos dueños.
|
|
21
|
+
*
|
|
22
|
+
* Aquí hay uno solo, y vive toda la sesión. Lo que sale del agente entra en el
|
|
23
|
+
* historial (historial.ts) y se pinta arriba; abajo va SIEMPRE la barra, sea la
|
|
24
|
+
* de escribir o la de trabajar. Nadie tiene que ponerse de acuerdo con nadie.
|
|
25
|
+
*
|
|
26
|
+
* Y POR ESO LA BARRA SE QUEDA QUIETA
|
|
27
|
+
*
|
|
28
|
+
* No porque se repinte rápido, sino porque es la última fila de un árbol que
|
|
29
|
+
* ocupa la ventana entera. No hay nada que pueda moverla, ni la rueda del ratón.
|
|
30
|
+
*/
|
|
31
|
+
export function App() {
|
|
32
|
+
const { stdout } = useStdout();
|
|
33
|
+
const filas = Math.max(6, stdout?.rows || 24);
|
|
34
|
+
const [, setRedibujar] = useState(0);
|
|
35
|
+
const [subido, setSubido] = useState(0);
|
|
36
|
+
const [turno, setTurno] = useState(estadoDelTurno());
|
|
37
|
+
const repintar = () => setRedibujar((n) => n + 1);
|
|
38
|
+
// Tres fuentes de cambio, todas fuera de React: lo que escribe el agente, lo
|
|
39
|
+
// que publica el spinner, y el paso de "esperando orden" a "trabajando".
|
|
40
|
+
useEffect(() => alEscribir(repintar), []);
|
|
41
|
+
useEffect(() => cuandoCambieElPie(repintar), []);
|
|
42
|
+
useEffect(() => alCambiarElTurno((nuevo) => setTurno(nuevo)), []);
|
|
43
|
+
// Al empezar un turno se vuelve al final: lo interesante es lo que va a salir,
|
|
44
|
+
// no donde estabas mirando.
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (turno.esperando)
|
|
47
|
+
return;
|
|
48
|
+
setSubido(0);
|
|
49
|
+
}, [turno.esperando]);
|
|
50
|
+
const barraDeTrabajo = turno.esperando ? [] : lineasDelPie();
|
|
51
|
+
const altoBarra = turno.esperando ? 0 : barraDeTrabajo.length;
|
|
52
|
+
const altoAviso = subido > 0 ? 1 : 0;
|
|
53
|
+
// Cuando espera orden, el hueco de abajo lo ocupa el prompt y su alto lo
|
|
54
|
+
// decide él; se le pasa cuánto sitio hay para lo de arriba.
|
|
55
|
+
const altoDelTexto = Math.max(1, filas - altoBarra - altoAviso - (turno.esperando ? 5 : 0));
|
|
56
|
+
const visible = ventana(altoDelTexto, subido);
|
|
57
|
+
const huecos = Math.max(0, altoDelTexto - visible.length);
|
|
58
|
+
return (_jsxs(Box, { flexDirection: "column", height: filas, children: [Array.from({ length: huecos }, (_, i) => (_jsx(Text, { children: " " }, `hueco-${i}`))), visible.map((linea, i) => (_jsx(Text, { children: linea }, `h-${i}`))), subido > 0 && (_jsx(Text, { dimColor: true, children: ` ↑ ${subido} lineas mas arriba · Av Pag para volver al final` })), turno.esperando ? (_jsx(Prompt, { alEnviar: turno.responder, alCancelar: () => turno.responder("/exit"), cwd: turno.cwd, promptSymbol: turno.promptSymbol, avisos: [], sinHistorial: true, alDesplazar: (cuanto) => setSubido((n) => Math.max(0, Math.min(tope(altoDelTexto), n + cuanto))) })) : (barraDeTrabajo.map((linea, i) => _jsx(Text, { children: linea }, `t-${i}`)))] }));
|
|
59
|
+
}
|
package/dist/ui/ink/Prompt.d.ts
CHANGED
|
@@ -38,5 +38,13 @@ export interface PromptProps {
|
|
|
38
38
|
promptSymbol: string;
|
|
39
39
|
/** Mensajes que llegaron tarde y hay que dejar por encima del marco. */
|
|
40
40
|
avisos: string[];
|
|
41
|
+
/**
|
|
42
|
+
* El historial lo pinta otro (el arbol de App). Aqui solo la barra.
|
|
43
|
+
*
|
|
44
|
+
* Sin esto se pintaria dos veces: una desde App y otra desde aqui.
|
|
45
|
+
*/
|
|
46
|
+
sinHistorial?: boolean;
|
|
47
|
+
/** Re Pag / Av Pag cuando quien manda el scroll es el arbol de arriba. */
|
|
48
|
+
alDesplazar?: (cuanto: number) => void;
|
|
41
49
|
}
|
|
42
|
-
export declare function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }: PromptProps): React.ReactElement;
|
|
50
|
+
export declare function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, sinHistorial, alDesplazar, }: PromptProps): React.ReactElement;
|
package/dist/ui/ink/Prompt.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
|
4
4
|
import { buildPromptFrame } from "../marco.js";
|
|
5
5
|
import { cycleMode } from "../modes.js";
|
|
6
6
|
import { aplicarOpcion, archivosDelProyecto, leerHistorial, mencionEnCurso, opcionesDelDesplegable, } from "../entrada.js";
|
|
7
7
|
import { esGrande, guardarPegado, marcaQueTerminaEn } from "../pegados.js";
|
|
8
|
+
import { alEscribir, tope, ventana } from "../historial.js";
|
|
9
|
+
import { enPantallaFija } from "../pantalla.js";
|
|
8
10
|
/** Marca del cursor. Ink esconde el de verdad, así que este se dibuja. */
|
|
9
11
|
const CARET = "█";
|
|
10
|
-
export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
12
|
+
export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, sinHistorial = false, alDesplazar, }) {
|
|
11
13
|
const { stdout } = useStdout();
|
|
12
14
|
const { exit } = useApp();
|
|
13
15
|
const [texto, setTexto] = useState("");
|
|
@@ -17,6 +19,18 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
17
19
|
const [, setRedibujar] = useState(0);
|
|
18
20
|
const historial = useRef(leerHistorial());
|
|
19
21
|
const [posHistorial, setPosHistorial] = useState(historial.current.length);
|
|
22
|
+
// Cuanto se ha subido con Re Pag. Cero es el fondo, que es donde se esta
|
|
23
|
+
// mientras se trabaja. Solo se usa en pantalla fija.
|
|
24
|
+
const [subido, setSubido] = useState(0);
|
|
25
|
+
const fija = enPantallaFija();
|
|
26
|
+
// En pantalla fija el terminal ya no guarda nada: lo que sale lo pintamos
|
|
27
|
+
// nosotros, asi que hay que repintar en cada escritura del agente. El
|
|
28
|
+
// historial vive fuera de React y React no puede adivinar que ha crecido.
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!fija)
|
|
31
|
+
return;
|
|
32
|
+
return alEscribir(() => setRedibujar((n) => n + 1));
|
|
33
|
+
}, [fija]);
|
|
20
34
|
// Se escanea UNA vez por prompt, no en cada tecla: recorrer el proyecto entero
|
|
21
35
|
// por cada letra se nota en cuanto el proyecto pasa de mediano.
|
|
22
36
|
const archivos = useMemo(() => {
|
|
@@ -29,6 +43,27 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
29
43
|
}, [cwd]);
|
|
30
44
|
const opciones = opcionesDelDesplegable(texto, cursor, archivos);
|
|
31
45
|
const indice = opciones.length > 0 ? ((elegido % opciones.length) + opciones.length) % opciones.length : 0;
|
|
46
|
+
const cols = Math.max(20, stdout?.columns || 80);
|
|
47
|
+
const rows = stdout?.rows || 24;
|
|
48
|
+
// El cursor se dibuja: Ink esconde el del terminal.
|
|
49
|
+
const conCaret = texto.slice(0, cursor) + CARET + texto.slice(cursor);
|
|
50
|
+
const marco = buildPromptFrame({
|
|
51
|
+
cols,
|
|
52
|
+
rows,
|
|
53
|
+
promptSymbol,
|
|
54
|
+
input: conCaret,
|
|
55
|
+
cursorIndex: cursor,
|
|
56
|
+
items: opciones,
|
|
57
|
+
selectedIndex: indice,
|
|
58
|
+
});
|
|
59
|
+
// Filas que le quedan a la conversacion una vez puesta la barra. En pantalla
|
|
60
|
+
// fija es lo que se pinta; en la normal no se usa, que ahi el historial es del
|
|
61
|
+
// terminal.
|
|
62
|
+
// Cuando se ha subido, una fila se va en el aviso de que se esta mirando
|
|
63
|
+
// atras. Sin descontarla, el arbol mide una fila mas que la ventana y el
|
|
64
|
+
// terminal desplaza: la barra dejaria de estar clavada justo al usar el scroll,
|
|
65
|
+
// que es para lo que existe este modo.
|
|
66
|
+
const altoDelTexto = Math.max(1, rows - marco.lines.length - (subido > 0 ? 1 : 0));
|
|
32
67
|
function enviar() {
|
|
33
68
|
const orden = texto.trim();
|
|
34
69
|
if (!orden)
|
|
@@ -37,6 +72,23 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
37
72
|
exit();
|
|
38
73
|
}
|
|
39
74
|
useInput((entrada, tecla) => {
|
|
75
|
+
// ----------------------------------------------- recorrer lo que salio
|
|
76
|
+
//
|
|
77
|
+
// Solo Re Pag y Av Pag. Las flechas y los caracteres son para escribir:
|
|
78
|
+
// robarselos aqui dejaria al usuario sin poder teclear.
|
|
79
|
+
if (tecla.pageUp || tecla.pageDown) {
|
|
80
|
+
const salto = Math.max(1, Math.floor(altoDelTexto / 2));
|
|
81
|
+
// Con el arbol de App al mando, el scroll lo lleva el: aqui no se sabe
|
|
82
|
+
// cuanto sitio hay arriba, porque el prompt es solo la parte de abajo.
|
|
83
|
+
if (alDesplazar) {
|
|
84
|
+
alDesplazar(tecla.pageUp ? salto : -salto);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (fija) {
|
|
88
|
+
setSubido((n) => tecla.pageUp ? Math.min(tope(altoDelTexto), n + salto) : Math.max(0, n - salto));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
40
92
|
// ------------------------------------------------------------- salir
|
|
41
93
|
if (tecla.ctrl && entrada === "c") {
|
|
42
94
|
alCancelar();
|
|
@@ -171,18 +223,14 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
171
223
|
setElegido(0);
|
|
172
224
|
}
|
|
173
225
|
});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
items: opciones,
|
|
185
|
-
selectedIndex: indice,
|
|
186
|
-
});
|
|
187
|
-
return (_jsxs(Box, { flexDirection: "column", children: [avisos.map((a, i) => (_jsx(Text, { children: a }, `aviso-${i}`))), marco.lines.map((linea, i) => (_jsx(Text, { children: linea }, i)))] }));
|
|
226
|
+
if (!fija || sinHistorial) {
|
|
227
|
+
return (_jsxs(Box, { flexDirection: "column", children: [avisos.map((a, i) => (_jsx(Text, { children: a }, `aviso-${i}`))), marco.lines.map((linea, i) => (_jsx(Text, { children: linea }, i)))] }));
|
|
228
|
+
}
|
|
229
|
+
// PANTALLA FIJA: el arbol ocupa la ventana entera y la barra va la ultima, asi
|
|
230
|
+
// que no puede moverse. Lo de arriba se rellena con huecos cuando hay poca
|
|
231
|
+
// conversacion; sin eso la barra subiria a media pantalla, que es justo la
|
|
232
|
+
// queja que este modo viene a resolver.
|
|
233
|
+
const visible = ventana(altoDelTexto, subido);
|
|
234
|
+
const huecos = Math.max(0, altoDelTexto - visible.length);
|
|
235
|
+
return (_jsxs(Box, { flexDirection: "column", height: rows, children: [Array.from({ length: huecos }, (_, i) => (_jsx(Text, { children: " " }, `hueco-${i}`))), visible.map((linea, i) => (_jsx(Text, { children: linea }, `h-${i}`))), subido > 0 && (_jsx(Text, { dimColor: true, children: ` ↑ ${subido} lineas mas arriba · Av Pag para volver al final` })), marco.lines.map((linea, i) => (_jsx(Text, { children: linea }, `b-${i}`)))] }));
|
|
188
236
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EL PUENTE ENTRE EL BUCLE Y EL ÁRBOL
|
|
3
|
+
*
|
|
4
|
+
* El programa es un `while` que espera: `const orden = await
|
|
5
|
+
* askInteractivePrompt()`. El árbol de Ink, en cambio, vive todo el rato y se
|
|
6
|
+
* limita a dibujar el estado que haya.
|
|
7
|
+
*
|
|
8
|
+
* Aquí se casan las dos formas. `pedirOrden()` marca "esperando", devuelve una
|
|
9
|
+
* promesa y se queda quieto; el componente pinta el prompt, y cuando el usuario
|
|
10
|
+
* envía, resuelve esa promesa y el estado vuelve a "trabajando". El bucle no se
|
|
11
|
+
* entera de nada: sigue teniendo una función que devuelve un texto.
|
|
12
|
+
*
|
|
13
|
+
* POR QUE NO SE MONTA Y DESMONTA EL ÁRBOL EN CADA VUELTA
|
|
14
|
+
*
|
|
15
|
+
* Es lo que se hacía antes, y era la causa de fondo: mientras el agente
|
|
16
|
+
* trabajaba no había árbol, así que la barra la pintaba otro por su cuenta. Dos
|
|
17
|
+
* dueños de la misma pantalla turnándose. Con el árbol siempre vivo hay uno.
|
|
18
|
+
*/
|
|
19
|
+
export interface EstadoDelTurno {
|
|
20
|
+
/** ¿Está el programa esperando que el usuario escriba? */
|
|
21
|
+
esperando: boolean;
|
|
22
|
+
cwd: string;
|
|
23
|
+
promptSymbol: string;
|
|
24
|
+
/** Lo llama el prompt al enviar. Fuera de "esperando" no hace nada. */
|
|
25
|
+
responder: (orden: string) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare function estadoDelTurno(): EstadoDelTurno;
|
|
28
|
+
export declare function alCambiarElTurno(cb: (e: EstadoDelTurno) => void): () => void;
|
|
29
|
+
/**
|
|
30
|
+
* Pide una orden. Se resuelve cuando el usuario la envía.
|
|
31
|
+
*
|
|
32
|
+
* El guardián `entregado` no es paranoia: el componente puede llamar a
|
|
33
|
+
* `responder` desde dos caminos —enviar y cancelar— y resolver dos veces una
|
|
34
|
+
* promesa deja el bucle avanzando por su cuenta con una orden que nadie escribió.
|
|
35
|
+
*/
|
|
36
|
+
export declare function pedirOrden(promptSymbol: string, cwd: string): Promise<string>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
const TRABAJANDO = {
|
|
3
|
+
esperando: false,
|
|
4
|
+
cwd: process.cwd(),
|
|
5
|
+
promptSymbol: "❯",
|
|
6
|
+
responder: () => { },
|
|
7
|
+
};
|
|
8
|
+
let estado = TRABAJANDO;
|
|
9
|
+
const oyentes = [];
|
|
10
|
+
export function estadoDelTurno() {
|
|
11
|
+
return estado;
|
|
12
|
+
}
|
|
13
|
+
export function alCambiarElTurno(cb) {
|
|
14
|
+
oyentes.push(cb);
|
|
15
|
+
return () => {
|
|
16
|
+
const i = oyentes.indexOf(cb);
|
|
17
|
+
if (i >= 0)
|
|
18
|
+
oyentes.splice(i, 1);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function avisar() {
|
|
22
|
+
for (const cb of oyentes) {
|
|
23
|
+
try {
|
|
24
|
+
cb(estado);
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Pide una orden. Se resuelve cuando el usuario la envía.
|
|
31
|
+
*
|
|
32
|
+
* El guardián `entregado` no es paranoia: el componente puede llamar a
|
|
33
|
+
* `responder` desde dos caminos —enviar y cancelar— y resolver dos veces una
|
|
34
|
+
* promesa deja el bucle avanzando por su cuenta con una orden que nadie escribió.
|
|
35
|
+
*/
|
|
36
|
+
export function pedirOrden(promptSymbol, cwd) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
let entregado = false;
|
|
39
|
+
estado = {
|
|
40
|
+
esperando: true,
|
|
41
|
+
cwd,
|
|
42
|
+
promptSymbol,
|
|
43
|
+
responder: (orden) => {
|
|
44
|
+
if (entregado)
|
|
45
|
+
return;
|
|
46
|
+
entregado = true;
|
|
47
|
+
estado = TRABAJANDO;
|
|
48
|
+
avisar();
|
|
49
|
+
resolve(orden);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
avisar();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { App } from "./App.js";
|
|
5
|
+
/**
|
|
6
|
+
* MONTA EL ÁRBOL Y LO DEJA VIVO TODA LA SESIÓN
|
|
7
|
+
*
|
|
8
|
+
* Va en su propio archivo por una razón práctica: `pantalla.ts` no puede montar
|
|
9
|
+
* JSX sin arrastrarse a sí mismo. `pantalla` → `App` → `Prompt` → `pantalla` es
|
|
10
|
+
* un ciclo, y los ciclos en ESM funcionan hasta que uno de los módulos necesita
|
|
11
|
+
* un valor del otro antes de tiempo, y entonces fallan de una forma que no se
|
|
12
|
+
* parece a su causa. Con el montaje aparte, `index.ts` llama a los dos y no hay
|
|
13
|
+
* ciclo.
|
|
14
|
+
*
|
|
15
|
+
* `exitOnCtrlC: false` porque Ctrl+C ya lo trata el prompt: dejar que Ink cierre
|
|
16
|
+
* el proceso por su cuenta se salta el guardado de la sesión.
|
|
17
|
+
*/
|
|
18
|
+
let arbol = null;
|
|
19
|
+
export function montarArbol() {
|
|
20
|
+
if (arbol)
|
|
21
|
+
return;
|
|
22
|
+
arbol = render(_jsx(App, {}), { exitOnCtrlC: false });
|
|
23
|
+
}
|
|
24
|
+
export function desmontarArbol() {
|
|
25
|
+
if (!arbol)
|
|
26
|
+
return;
|
|
27
|
+
try {
|
|
28
|
+
arbol.unmount();
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
arbol = null;
|
|
32
|
+
}
|
|
33
|
+
// Si el proceso muere sin pasar por la salida ordenada, el árbol tiene que
|
|
34
|
+
// soltarse igual: un árbol vivo en un proceso que se cierra deja el terminal a
|
|
35
|
+
// medio restaurar.
|
|
36
|
+
process.on("exit", desmontarArbol);
|
|
@@ -7,6 +7,8 @@ import { expandirPegados, limpiarPegados } from "../pegados.js";
|
|
|
7
7
|
import { apuntarEnHistorial } from "../entrada.js";
|
|
8
8
|
import { soltarPie } from "../pieFijo.js";
|
|
9
9
|
import { clearTyped } from "../typeAhead.js";
|
|
10
|
+
import { enPantallaFija } from "../pantalla.js";
|
|
11
|
+
import { pedirOrden } from "./control.js";
|
|
10
12
|
/**
|
|
11
13
|
* EL PUENTE ENTRE INK Y EL BUCLE DE SIEMPRE
|
|
12
14
|
*
|
|
@@ -64,6 +66,16 @@ export async function preguntarConInk(promptSymbol = "❯", cwd = process.cwd())
|
|
|
64
66
|
// pisan, y el que pierde deja filas huérfanas.
|
|
65
67
|
soltarPie();
|
|
66
68
|
limpiarRestos();
|
|
69
|
+
// Con el arbol unico montado, aqui no se monta ni se desmonta nada: solo se
|
|
70
|
+
// dice "estoy esperando" y el arbol pinta el prompt. Ver ink/control.ts.
|
|
71
|
+
if (enPantallaFija()) {
|
|
72
|
+
const orden = await pedirOrden(promptSymbol, cwd);
|
|
73
|
+
const entero = expandirPegados(orden);
|
|
74
|
+
if (entero.trim())
|
|
75
|
+
apuntarEnHistorial(entero);
|
|
76
|
+
limpiarPegados();
|
|
77
|
+
return entero;
|
|
78
|
+
}
|
|
67
79
|
return new Promise((resolve) => {
|
|
68
80
|
let entregado = false;
|
|
69
81
|
let empujarAviso = null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fija POR DEFECTO.
|
|
3
|
+
*
|
|
4
|
+
* Estuvo detras de un interruptor un dia, y fue un error: el usuario pidio
|
|
5
|
+
* cuatro veces que la caja no se moviera y lo que recibio fue una opcion que
|
|
6
|
+
* habia que acordarse de encender. Una funcion que hay que activar a mano es,
|
|
7
|
+
* para quien la pidio, una funcion que no esta.
|
|
8
|
+
*
|
|
9
|
+
* `CHOCOLATITO_PANTALLA=normal` devuelve el comportamiento de siempre: el
|
|
10
|
+
* historial vuelve a ser del terminal y la rueda del raton a servir, a cambio de
|
|
11
|
+
* que la barra suba con el scroll.
|
|
12
|
+
*/
|
|
13
|
+
export declare function pantallaFijaPedida(): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Enciende o apaga el modo a mano, SIN tocar el terminal.
|
|
16
|
+
*
|
|
17
|
+
* Las pruebas lo necesitan: entrar de verdad escribiria la secuencia de la
|
|
18
|
+
* pantalla alternativa en la consola de quien corre las pruebas y le dejaria el
|
|
19
|
+
* informe en una pantalla que desaparece al acabar.
|
|
20
|
+
*/
|
|
21
|
+
export declare function forzarPantallaFija(valor: boolean | null): void;
|
|
22
|
+
export declare function enPantallaFija(): boolean;
|
|
23
|
+
export declare function entrarEnPantallaFija(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Devuelve el terminal como estaba.
|
|
26
|
+
*
|
|
27
|
+
* Se llama al salir del programa, y también si algo revienta: quedarse en la
|
|
28
|
+
* pantalla alternativa deja al usuario en una consola en blanco sin su prompt,
|
|
29
|
+
* y la única salida es cerrar la ventana.
|
|
30
|
+
*/
|
|
31
|
+
export declare function salirDePantallaFija(): void;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { redirigirDibujo } from "./salida.js";
|
|
3
|
+
import { apuntar } from "./historial.js";
|
|
4
|
+
import { habilitarPie } from "./pieFijo.js";
|
|
5
|
+
/**
|
|
6
|
+
* LA PANTALLA ALTERNATIVA
|
|
7
|
+
*
|
|
8
|
+
* La barra de abajo sube al hacer scroll porque ES una línea del historial del
|
|
9
|
+
* terminal, no una capa encima. Ninguna secuencia de escape la clava ahí; lo
|
|
10
|
+
* único que lo consigue es que el programa tome la pantalla entera, como hacen
|
|
11
|
+
* vim o htop.
|
|
12
|
+
*
|
|
13
|
+
* QUÉ CAMBIA AL ENTRAR
|
|
14
|
+
*
|
|
15
|
+
* El terminal deja de guardar historial: la rueda del ratón no sirve y al salir
|
|
16
|
+
* la sesión desaparece de la consola. Por eso, mientras dura, TODO lo que se
|
|
17
|
+
* imprime se guarda en memoria (historial.ts) y lo pinta el árbol de Ink.
|
|
18
|
+
*
|
|
19
|
+
* Y por eso hay que interceptar también `console.log`. Aquí no vale con desviar
|
|
20
|
+
* el conducto de dibujo: media docena de sitios —el arranque, la licencia, los
|
|
21
|
+
* avisos— siguen imprimiendo directo, y en la pantalla alternativa eso escribe
|
|
22
|
+
* encima de lo que Ink acaba de dibujar y descuadra el árbol entero.
|
|
23
|
+
*
|
|
24
|
+
* ES UN MODO, NO EL COMPORTAMIENTO NORMAL
|
|
25
|
+
*
|
|
26
|
+
* Cambiar el historial del terminal por uno propio es un intercambio de verdad,
|
|
27
|
+
* no una mejora: quien use mucho la rueda del ratón para releer sale perdiendo.
|
|
28
|
+
* Se activa con CHOCOLATITO_PANTALLA=fija.
|
|
29
|
+
*/
|
|
30
|
+
const ENTRAR = "\x1b[?1049h";
|
|
31
|
+
const SALIR = "\x1b[?1049l";
|
|
32
|
+
let dentro = false;
|
|
33
|
+
let logOriginal = null;
|
|
34
|
+
/**
|
|
35
|
+
* Fija POR DEFECTO.
|
|
36
|
+
*
|
|
37
|
+
* Estuvo detras de un interruptor un dia, y fue un error: el usuario pidio
|
|
38
|
+
* cuatro veces que la caja no se moviera y lo que recibio fue una opcion que
|
|
39
|
+
* habia que acordarse de encender. Una funcion que hay que activar a mano es,
|
|
40
|
+
* para quien la pidio, una funcion que no esta.
|
|
41
|
+
*
|
|
42
|
+
* `CHOCOLATITO_PANTALLA=normal` devuelve el comportamiento de siempre: el
|
|
43
|
+
* historial vuelve a ser del terminal y la rueda del raton a servir, a cambio de
|
|
44
|
+
* que la barra suba con el scroll.
|
|
45
|
+
*/
|
|
46
|
+
export function pantallaFijaPedida() {
|
|
47
|
+
if (process.env.CHOCOLATITO_PANTALLA === "normal")
|
|
48
|
+
return false;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
/** `null` = manda el estado real. Las pruebas lo fuerzan. */
|
|
52
|
+
let forzado = null;
|
|
53
|
+
/**
|
|
54
|
+
* Enciende o apaga el modo a mano, SIN tocar el terminal.
|
|
55
|
+
*
|
|
56
|
+
* Las pruebas lo necesitan: entrar de verdad escribiria la secuencia de la
|
|
57
|
+
* pantalla alternativa en la consola de quien corre las pruebas y le dejaria el
|
|
58
|
+
* informe en una pantalla que desaparece al acabar.
|
|
59
|
+
*/
|
|
60
|
+
export function forzarPantallaFija(valor) {
|
|
61
|
+
forzado = valor;
|
|
62
|
+
}
|
|
63
|
+
export function enPantallaFija() {
|
|
64
|
+
return forzado ?? dentro;
|
|
65
|
+
}
|
|
66
|
+
export function entrarEnPantallaFija() {
|
|
67
|
+
if (dentro || !process.stdout.isTTY)
|
|
68
|
+
return;
|
|
69
|
+
dentro = true;
|
|
70
|
+
process.stdout.write(ENTRAR);
|
|
71
|
+
// Lo que se dibujaba en el terminal pasa a ser historial nuestro.
|
|
72
|
+
redirigirDibujo((texto) => apuntar(texto));
|
|
73
|
+
// Y el pie deja de pintar. Sigue guardando sus secciones -el spinner y la
|
|
74
|
+
// linea de razonamiento publican ahi sin enterarse de nada- pero quien las
|
|
75
|
+
// dibuja pasa a ser el arbol. Dos dueños del mismo trozo de pantalla es
|
|
76
|
+
// exactamente el problema que esto viene a quitar.
|
|
77
|
+
habilitarPie(false);
|
|
78
|
+
logOriginal = console.log;
|
|
79
|
+
console.log = (...args) => {
|
|
80
|
+
apuntar(args.map((a) => (typeof a === "string" ? a : String(a))).join(" ") + "\n");
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Devuelve el terminal como estaba.
|
|
85
|
+
*
|
|
86
|
+
* Se llama al salir del programa, y también si algo revienta: quedarse en la
|
|
87
|
+
* pantalla alternativa deja al usuario en una consola en blanco sin su prompt,
|
|
88
|
+
* y la única salida es cerrar la ventana.
|
|
89
|
+
*/
|
|
90
|
+
export function salirDePantallaFija() {
|
|
91
|
+
if (!dentro)
|
|
92
|
+
return;
|
|
93
|
+
dentro = false;
|
|
94
|
+
if (logOriginal) {
|
|
95
|
+
console.log = logOriginal;
|
|
96
|
+
logOriginal = null;
|
|
97
|
+
}
|
|
98
|
+
redirigirDibujo(null);
|
|
99
|
+
habilitarPie(null);
|
|
100
|
+
try {
|
|
101
|
+
process.stdout.write(SALIR);
|
|
102
|
+
}
|
|
103
|
+
catch { }
|
|
104
|
+
}
|
|
105
|
+
process.on("exit", salirDePantallaFija);
|
package/dist/ui/pieFijo.d.ts
CHANGED
|
@@ -31,6 +31,16 @@ export declare function fijarSeccion(nombre: SeccionDelPie, lineas: string[]): v
|
|
|
31
31
|
* para el mismo resultado, y un parpadeo que se nota en un terminal lento.
|
|
32
32
|
*/
|
|
33
33
|
export declare function fijarSecciones(entradas: Array<[SeccionDelPie, string[]]>): void;
|
|
34
|
+
export declare function cuandoCambieElPie(cb: () => void): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Las lineas que el pie tiene puestas ahora mismo, en orden.
|
|
37
|
+
*
|
|
38
|
+
* La necesita el arbol de Ink cuando manda el: ahi el pie no pinta nada -pintar
|
|
39
|
+
* seria un segundo dueño del mismo trozo de pantalla- pero el spinner y la
|
|
40
|
+
* linea de razonamiento siguen publicando aqui, que es lo que hace que ese
|
|
41
|
+
* cambio no toque ni al spinner ni al bucle.
|
|
42
|
+
*/
|
|
43
|
+
export declare function lineasDelPie(): string[];
|
|
34
44
|
export declare function quitarSeccion(nombre: SeccionDelPie): void;
|
|
35
45
|
/**
|
|
36
46
|
* Escribe texto permanente sin que el pie se lo lleve por delante.
|
package/dist/ui/pieFijo.js
CHANGED
|
@@ -233,15 +233,51 @@ export function fijarSeccion(nombre, lineas) {
|
|
|
233
233
|
* para el mismo resultado, y un parpadeo que se nota en un terminal lento.
|
|
234
234
|
*/
|
|
235
235
|
export function fijarSecciones(entradas) {
|
|
236
|
-
if (!pieUsable())
|
|
237
|
-
return;
|
|
238
236
|
let cambio = false;
|
|
239
237
|
for (const [nombre, lineas] of entradas) {
|
|
240
238
|
if (anotar(nombre, lineas))
|
|
241
239
|
cambio = true;
|
|
242
240
|
}
|
|
243
|
-
if (cambio)
|
|
241
|
+
if (!cambio)
|
|
242
|
+
return;
|
|
243
|
+
// Con el pie apagado -que es lo que pasa cuando manda Ink- las secciones se
|
|
244
|
+
// siguen guardando y se avisa, pero no se pinta nada aqui: pintar seria un
|
|
245
|
+
// segundo dueño del mismo trozo de pantalla.
|
|
246
|
+
if (pieUsable())
|
|
244
247
|
repintar("");
|
|
248
|
+
for (const cb of alCambiarElPie) {
|
|
249
|
+
try {
|
|
250
|
+
cb();
|
|
251
|
+
}
|
|
252
|
+
catch { }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/** Quien pinta el pie desde fuera se entera por aqui. */
|
|
256
|
+
const alCambiarElPie = [];
|
|
257
|
+
export function cuandoCambieElPie(cb) {
|
|
258
|
+
alCambiarElPie.push(cb);
|
|
259
|
+
return () => {
|
|
260
|
+
const i = alCambiarElPie.indexOf(cb);
|
|
261
|
+
if (i >= 0)
|
|
262
|
+
alCambiarElPie.splice(i, 1);
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Las lineas que el pie tiene puestas ahora mismo, en orden.
|
|
267
|
+
*
|
|
268
|
+
* La necesita el arbol de Ink cuando manda el: ahi el pie no pinta nada -pintar
|
|
269
|
+
* seria un segundo dueño del mismo trozo de pantalla- pero el spinner y la
|
|
270
|
+
* linea de razonamiento siguen publicando aqui, que es lo que hace que ese
|
|
271
|
+
* cambio no toque ni al spinner ni al bucle.
|
|
272
|
+
*/
|
|
273
|
+
export function lineasDelPie() {
|
|
274
|
+
const salida = [];
|
|
275
|
+
for (const nombre of ORDEN) {
|
|
276
|
+
const trozo = secciones.get(nombre);
|
|
277
|
+
if (trozo && trozo.length > 0)
|
|
278
|
+
salida.push(...trozo);
|
|
279
|
+
}
|
|
280
|
+
return salida;
|
|
245
281
|
}
|
|
246
282
|
export function quitarSeccion(nombre) {
|
|
247
283
|
fijarSeccion(nombre, []);
|
package/extension/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"minimum_chrome_version": "102",
|
|
4
4
|
"name": "Chocolatito Code",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.6.0",
|
|
6
6
|
"description": "Deja que Chocolatito Code trabaje dentro de tu Chrome, en segundo plano y con tus sesiones ya iniciadas.",
|
|
7
7
|
"permissions": [
|
|
8
8
|
"tabs",
|
package/package.json
CHANGED