Usando técnicas de programación funcional, podemos construir fácilmente terminales sofisticados con componentes dinámicos en C++. RxTerm es una biblioteca de C++ que proporciona algunos de los componentes básicos necesarios para implementar este concepto.
Aplicamos las mismas ideas en Buckaroo . Este es el resultado:
Imagine que queremos crear una aplicación basada en texto que actualice la consola a medida que cambia su estado. Un gran ejemplo de esto es Curl, que ofrece una barra de progreso en vivo para las descargas. Prueba esto en tu terminal:
Estas interfaces se implementan mediante códigos de escape ANSI . Estos son caracteres invisibles que tienen efectos secundarios, como borrar caracteres y mover el cursor.
Podemos usar estos códigos de escape para crear interfaces de texto en vivo. Una implementación simple podría actualizar una barra de progreso como esta:
Hasta aquí todo bien, pero ¿y si tenemos un caso más complicado? Idealmente, aprovecharíamos una biblioteca que resuelva estas cosas por nosotros. Solo deberíamos tener que especificar cómo debería verse la salida del terminal, y las funciones de la biblioteca descubrirían los caracteres que se imprimirán para llevarnos allí.
Entonces, a un alto nivel, necesitamos tres cosas:
1. Una variable para rastrear el estado anterior de la consola 2. Una función para representar el estado actual de la aplicación 3. Una función para transformar la consola del estado anterior al siguiente estado
Los desarrolladores de React estarán familiarizados con este patrón. ¡Es una estrategia inteligente que en realidad se puede aplicar a cualquier dispositivo de E/S!
Además, queremos poder aprovechar los componentes de la interfaz de usuario reutilizables para cosas como barras de progreso, listas, etc. Algo como HTML, pero más simple, sería ideal. Un componente sería cualquier objeto que se pueda representar en la salida de la consola.
Para ver hacia dónde vamos, echemos un vistazo a un ejemplo en RxTerm . Con RxTerm, podemos convertir los componentes básicos de la terminal en componentes más complejos mediante la composición. Si el estado de la aplicación cambia, calculamos una nueva vista para el terminal y reemplazamos la salida visible actualmente.
Este ejemplo muestra cómo podemos diseñar un nuevo componente llamado fancyCounter
, que imprime marcos como este:
Aquí está el código:
Como puede ver, la interfaz es de muy alto nivel.
Empecemos con lo básico. ¿Cómo podemos usar los códigos de escape ANSI para cambiar el color y eliminar una línea?
Esta función imprime Hello
en letra roja seguida de World
en el color predeterminado. Las secuencias de escape mágicas ( \e[31m
y \e[0m
) modifican la forma en que la terminal muestra los caracteres.
Se introduce una secuencia de escape con \e[
seguida de una lista de modificadores separados por punto y coma, que termina con m
. Por ejemplo, \e[3;31;42mTEXT
imprimiría TEXT
en cursiva roja sobre un fondo azul.
También podemos imprimir \e[0m
para restablecer el terminal a su estado predeterminado.
Puede encontrar una lista completa en bash-hackers.org .
Para poder componer componentes, necesitamos una representación de alto nivel del estado de la consola. Como queremos admitir colores, una representación intuitiva de esto es un mapa de coordenadas a píxeles:
Una vez que tengamos la abstracción básica para los componentes, podemos aprovechar el borrado de tipos para mantener la semántica de valores y hacer que la herencia sea un detalle de implementación:
Ahora, podemos construir componentes de orden superior como un objeto de Text
:
Puede encontrar la implementación real aquí .
Imagina que queremos hacer la transición de esto:
… a esto:
La forma más sencilla sería eliminar las últimas 3 líneas e imprimir las nuevas líneas. Podemos eliminar la última línea imprimiendo \e[2K\r\e[1A
( delete line
; move cursor to the start of the line
; move cursor up one line
).
Un enfoque más sofisticado sería calcular la diferencia y moverse a la posición de destino y editar solo los píxeles terminales que cambiaron. Para simplificar, nos ceñiremos al primer enfoque y combinaremos las partes móviles en una sola clase:
La implementación real está alojada en GitHub .
¡Vimos lo fácil que es escribir un marco de terminal reactivo y administrar las transiciones de estado sin demasiados dolores de cabeza!
Puede encontrar la implementación de algunos componentes básicos en nuestro repositorio en GitHub . ¡Nos encantaría ver a más personas haciendo hermosas interfaces de terminal!
Nuestro próximo artículo tratará sobre cómo podemos aprovechar RxCpp para escribir aplicaciones altamente simultáneas con una gestión de estado compleja.
Creamos Buckaroo para facilitar la reutilización de código C++. Lea más sobre esto en Medium :
7 razones para usar Buck Build _Buck es un sistema de compilación multiplataforma y multilenguaje creado para la compilación a gran escala en Facebook. Todo Buckaroo…_hackernoon.com
Enfoques de la gestión de dependencias de C++, o por qué construimos Buckaroo _C++ es un lenguaje inusual en el sentido de que todavía no tiene un administrador de paquetes dominante (¡estamos trabajando en ello!). Como resultado... _hackernoon.com
6 razones por las que distribuimos bibliotecas C++ como código fuente _Al escribir aplicaciones C++, inevitablemente hará uso de bibliotecas externas. ¡Ésto es una cosa buena! Reutilización de código…_hackernoon.com