chocolatito-code 1.5.0 → 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 +7 -1
- 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 +13 -5
- 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 +12 -0
- package/dist/ui/pantalla.js +22 -1
- 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
|
@@ -16,6 +16,7 @@ import { showBanner, animateStartupBanner, showHelp, showEffortMenu } from "./ui
|
|
|
16
16
|
import { fijarMotor } from "./ui/motorActual.js";
|
|
17
17
|
import { elegirDeLista } from "./ui/selector.js";
|
|
18
18
|
import { entrarEnPantallaFija, pantallaFijaPedida } from "./ui/pantalla.js";
|
|
19
|
+
import { montarArbol } from "./ui/ink/montarApp.js";
|
|
19
20
|
import { reafirmarModoCrudo } from "./ui/keyboardGuard.js";
|
|
20
21
|
import { askInteractivePrompt, SLASH_COMMANDS } from "./ui/prompt.js";
|
|
21
22
|
import { changeDir } from "./tools/changeDir.js";
|
|
@@ -239,8 +240,13 @@ ${nodeViejo}
|
|
|
239
240
|
// La barra de abajo solo puede quedarse clavada si el programa toma la
|
|
240
241
|
// pantalla entera. Se pide con CHOCOLATITO_PANTALLA=fija y se paga con el
|
|
241
242
|
// historial del terminal: ver ui/pantalla.ts.
|
|
242
|
-
if (pantallaFijaPedida())
|
|
243
|
+
if (pantallaFijaPedida()) {
|
|
243
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
|
+
}
|
|
244
250
|
let currentModel = DEFAULT_ESPECTRO;
|
|
245
251
|
// La barra de estado lo lee de aqui. Fijarlo al arrancar y no solo al
|
|
246
252
|
// cambiarlo: si no, hasta el primer /effort la barra no dice nada.
|
|
@@ -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
|
@@ -9,7 +9,7 @@ import { alEscribir, tope, ventana } from "../historial.js";
|
|
|
9
9
|
import { enPantallaFija } from "../pantalla.js";
|
|
10
10
|
/** Marca del cursor. Ink esconde el de verdad, así que este se dibuja. */
|
|
11
11
|
const CARET = "█";
|
|
12
|
-
export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
12
|
+
export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, sinHistorial = false, alDesplazar, }) {
|
|
13
13
|
const { stdout } = useStdout();
|
|
14
14
|
const { exit } = useApp();
|
|
15
15
|
const [texto, setTexto] = useState("");
|
|
@@ -76,10 +76,18 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
76
76
|
//
|
|
77
77
|
// Solo Re Pag y Av Pag. Las flechas y los caracteres son para escribir:
|
|
78
78
|
// robarselos aqui dejaria al usuario sin poder teclear.
|
|
79
|
-
if (
|
|
79
|
+
if (tecla.pageUp || tecla.pageDown) {
|
|
80
80
|
const salto = Math.max(1, Math.floor(altoDelTexto / 2));
|
|
81
|
-
|
|
82
|
-
|
|
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
|
+
}
|
|
83
91
|
}
|
|
84
92
|
// ------------------------------------------------------------- salir
|
|
85
93
|
if (tecla.ctrl && entrada === "c") {
|
|
@@ -215,7 +223,7 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
|
|
|
215
223
|
setElegido(0);
|
|
216
224
|
}
|
|
217
225
|
});
|
|
218
|
-
if (!fija) {
|
|
226
|
+
if (!fija || sinHistorial) {
|
|
219
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)))] }));
|
|
220
228
|
}
|
|
221
229
|
// PANTALLA FIJA: el arbol ocupa la ventana entera y la barra va la ultima, asi
|
|
@@ -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;
|
package/dist/ui/pantalla.d.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
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
|
+
*/
|
|
1
13
|
export declare function pantallaFijaPedida(): boolean;
|
|
2
14
|
/**
|
|
3
15
|
* Enciende o apaga el modo a mano, SIN tocar el terminal.
|
package/dist/ui/pantalla.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { redirigirDibujo } from "./salida.js";
|
|
3
3
|
import { apuntar } from "./historial.js";
|
|
4
|
+
import { habilitarPie } from "./pieFijo.js";
|
|
4
5
|
/**
|
|
5
6
|
* LA PANTALLA ALTERNATIVA
|
|
6
7
|
*
|
|
@@ -30,8 +31,22 @@ const ENTRAR = "\x1b[?1049h";
|
|
|
30
31
|
const SALIR = "\x1b[?1049l";
|
|
31
32
|
let dentro = false;
|
|
32
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
|
+
*/
|
|
33
46
|
export function pantallaFijaPedida() {
|
|
34
|
-
|
|
47
|
+
if (process.env.CHOCOLATITO_PANTALLA === "normal")
|
|
48
|
+
return false;
|
|
49
|
+
return true;
|
|
35
50
|
}
|
|
36
51
|
/** `null` = manda el estado real. Las pruebas lo fuerzan. */
|
|
37
52
|
let forzado = null;
|
|
@@ -55,6 +70,11 @@ export function entrarEnPantallaFija() {
|
|
|
55
70
|
process.stdout.write(ENTRAR);
|
|
56
71
|
// Lo que se dibujaba en el terminal pasa a ser historial nuestro.
|
|
57
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);
|
|
58
78
|
logOriginal = console.log;
|
|
59
79
|
console.log = (...args) => {
|
|
60
80
|
apuntar(args.map((a) => (typeof a === "string" ? a : String(a))).join(" ") + "\n");
|
|
@@ -76,6 +96,7 @@ export function salirDePantallaFija() {
|
|
|
76
96
|
logOriginal = null;
|
|
77
97
|
}
|
|
78
98
|
redirigirDibujo(null);
|
|
99
|
+
habilitarPie(null);
|
|
79
100
|
try {
|
|
80
101
|
process.stdout.write(SALIR);
|
|
81
102
|
}
|
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