<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[Libre como en libertad]]></title>
<description><![CDATA[Libre como en libertad]]></description>
<link>https://www.finaprosadigital.com</link>
<atom:link href="https://www.finaprosadigital.com/rss.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Sat, 02 May 2026 19:34:13 +0200</lastBuildDate>
<item>
  <title><![CDATA[May Emacs Carnival]]></title>
  <description><![CDATA[
<div id="outline-container-org5ee95b6" class="outline-2">
<h2 id="org5ee95b6">May I recommend&#x2026; / En mayo recomiendo&#x2026;</h2>
<div class="outline-text-2" id="text-org5ee95b6">
<p>
Nota: Este post tiene una versión en inglés para participar en el
<a href="https://www.emacswiki.org/emacs/CarnivalMay2026">Emacs Carnival</a>. La versión en castellano está tras la inglesa.
</p>
</div>
</div>
<div id="outline-container-org3d1a573" class="outline-2">
<h2 id="org3d1a573">May I recommend</h2>
<div class="outline-text-2" id="text-org3d1a573">
<p>
For this month Emacs Carnival I've thought of two types of
recommendations. First some amusements inside Emacs, and then some
things I liked when skimming through the Emacs 31 NEWS file.
</p>
</div>
<ul class="org-ul">
<li><a id="orgc049641"></a>Amusements<br>
<div class="outline-text-5" id="text-orgc049641">
<p>
I think nowadays some extra features of Emacs like the games are
considered "bloat", but for me these types of things are the ones that
make me happy.
</p>

<p>
I recommend to evaluate <code>(info "(emacs) Amusements")</code> inside Emacs and
take a look at the amusements section. It has a lot of games to play
with. I have yet to find out how to finish the text-adventure game
Dunnet. There is also the classic Conway's Game of Life, pong,
snake&#x2026;
</p>

<p>
And of course we have <code>M-x tetris</code>, which being inside Emacs is deeply
customizable. In fact, I even <a href="https://www.finaprosadigital.com/2024-01-23-tetris.html">implemented</a> a very primitive way of
holding pieces the way the modern version of Tetris does.
</p>
</div>
</li>
<li><a id="org537569c"></a>Emacs 31 NEWS<br>
<div class="outline-text-5" id="text-org537569c">
<p>
First of all, I recommend using <code>C-h n</code> to see the latest news for
your Emacs version. It's really incredible the vast amount of
improvements each new release brings. I am not a very advanced Emacs
user but still I always find a couple of things that help me improve
my workflow.
</p>

<p>
In this occasion I have found <code>(setq elisp-fontify-semantically t)</code>,
which analyses your Elisp code and highlight some definitions and
variables. For example, I can write in the scratch buffer the name of
some function of mine, and it would let me see the definition by simply
hovering the mouse over the name.
</p>
</div>
</li>
</ul>
</div>
<div id="outline-container-orgde52f2f" class="outline-2">
<h2 id="orgde52f2f">En mayo recomiendo</h2>
<div class="outline-text-2" id="text-orgde52f2f">
<p>
Para el Emacs Carnival de este mes he pensado en dos tipos de
recomendaciones. Primero algunas para pasatiempos dentro de Emacs y
luego otras relacionadas con el archivo NEWS de Emacs 31.
</p>
</div>
<ul class="org-ul">
<li><a id="orge80f0d2"></a>Pasatiempos<br>
<div class="outline-text-5" id="text-orge80f0d2">
<p>
Hoy en día quizás se considera un desperdicio de espacio los juegos
que trae Emacs integrados, pero a mi me encantan estos detalles que se
incluían antiguamente en los programas.
</p>

<p>
Para empezar, recomiendo evaluar <code>(info "(emacs) Amusements")</code> dentro
de Emacs para leer el manual de los pasatiempos. Ahí vienen detallados
todos los juegos que trae Emacs, que son un montón. Todavía no he
conseguido pasarme la aventura gráfica Dunnet. Además está el clásico
Juego de la vida de Conway, el pong, el snake etc.
</p>

<p>
Y por supuesto tenemos el <code>M-x tetris</code>, que como todo lo que está
dentro de Emacs es altamente personalizable. Yo incluso <a href="https://www.finaprosadigital.com/2024-01-23-tetris.html">implementé</a>
hace unos años el modo para guardar piezas típico de los tetrises
modernos.
</p>
</div>
</li>
<li><a id="org08e0f04"></a>Noticias de Emacs 31<br>
<div class="outline-text-5" id="text-org08e0f04">
<p>
Para empezar, recomiendo usar <code>C-h n</code> para ver las últimas noticias
para tu versión de Emacs. Es apabullante la cantidad de mejores que
introducen en cada versión. Yo no soy un usuario demasiado avanzado de
Emacs, pero aún así siempre encuentro un par de cosas que me ayudan a
mejorar mi flujo de trabajo.
</p>

<p>
En esta ocasión he encontrado <code>(setq elisp-fontify-semantically t)</code>,
que analiza el código de Elisp que escribes y te resalta funciones o
variables. Además, pasando el ratón por encima puedes ver la
definición de tus propias funciones, y te dice dónde están definidas
por si no te acuerdas.
</p>
</div>
</li>
</ul>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html"><span class="tag-label">Tags</span></a><span class="tag-separator">: </span><span class="taglist__tags"><a href="https://www.finaprosadigital.com/tag-emacs,.html" class="tag" data-tag="emacs," data-index="0">emacs,</a> <a href="https://www.finaprosadigital.com/tag-carnival.html" class="tag" data-tag="carnival" data-index="1">carnival</a> </span></div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[carnival]]></category>
  <link>https://www.finaprosadigital.com/2026-05-02-may-emacs-carnival.html</link>
  <guid>https://www.finaprosadigital.com/2026-05-02-may-emacs-carnival.html</guid>
  <pubDate>Sat, 02 May 2026 19:33:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Starter kits (kits de inicio)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el <a href="https://www.emacswiki.org/emacs/Carnival">Emacs Carnival</a>. La versión en castellano está tras la inglesa. 
</p>
<div id="outline-container-orgc84d14b" class="outline-2">
<h2 id="orgc84d14b">Starter kits</h2>
<div class="outline-text-2" id="text-orgc84d14b">
</div>
<div id="outline-container-org6fb3ea4" class="outline-3">
<h3 id="org6fb3ea4">Emacs Prelude</h3>
<div class="outline-text-3" id="text-org6fb3ea4">
<p>
I started my Emacs config file from scratch because I didn't know that
starter kits existed. But a couple of years after using Emacs I found
Emacs Prelude and migrated my configuration to use Prelude.
</p>

<p>
With Prelude I learnt a lot of things (avy, completion frameworks,
flymake&#x2026;). Emacs Prelude was like a different editor compared to my
orginal configuration.
</p>

<p>
Eventually, I stopped using Prelude because there were a lot of things
I didn't understand at the moment (like the whitespace-mode or
flymake) and wanted to learn using them one by one in my own
configuration. But it was wonderful to rediscover Emacs through
Prelude, and it improved my Emacs knowledge a lot.
</p>
</div>
</div>
</div>
<div id="outline-container-org8a2739d" class="outline-2">
<h2 id="org8a2739d">Kits de inicio</h2>
<div class="outline-text-2" id="text-org8a2739d">
</div>
<div id="outline-container-orgbe1f1d7" class="outline-3">
<h3 id="orgbe1f1d7">Emacs Prelude</h3>
<div class="outline-text-3" id="text-orgbe1f1d7">
<p>
Cuando empecé a usar Emacs, partí de un fichero de configuración
vacío, porque no sabía ni que existían distintas "distros" de Emacs
preconfiguradas.
</p>

<p>
Pero tras unos dos años de usar Emacs descubrí Emacs Prelude, y migré
mi configuración para usarlo. Gracias a Prelude descubrí un montón de
cosas que desconocía (como avy, los motores de búsqueda, flymake
etc.). Con Prelude, Emacs parecía un editor completamente distinto al
Emacs que tenía con mi propia configuración.
</p>

<p>
Con el paso del tiempo dejé de usar Prelude porque había demasiadas
cosas que no entendía (como los colores de whitespace-mode o
flymake), y prefería ir probándolas poco a poco en mi propia
configuración para entederlas mejor. Pero fue realmente increíble
redescubrir Emacs gracias a Prelude. Gracias a eso conseguí pasar de
ser un novato a ser un usuario con bastante conocimiento de Emacs.
</p>
</div>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-carnival,.html">carnival,</a> <a href="https://www.finaprosadigital.com/tag-gnu/linux,.html">gnu/linux,</a> <a href="https://www.finaprosadigital.com/tag-english.html">english</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[carnival,]]></category>
  <category><![CDATA[gnu/linux,]]></category>
  <category><![CDATA[english]]></category>
  <link>https://www.finaprosadigital.com/2026-04-13-starter-kits.html</link>
  <guid>https://www.finaprosadigital.com/2026-04-13-starter-kits.html</guid>
  <pubDate>Mon, 13 Apr 2026 00:00:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Hola mundo en Emacs Lisp]]></title>
  <description><![CDATA[
<p>
Llevo mucho tiempo queriendo mejorar mi conocimiento de Emacs
Lisp, pero al final nunca tengo hueco para aprenderlo en profundidad.
</p>

<p>
De momento he hecho una especie de "Hola mundo" un poco más complejo,
usando la función <code>let</code> de Elisp para declarar variables.
</p>

<p>
Es una función muy sencilla, que pide al usuario el nombre, y luego le
da los buenos días y la fecha. Con esta función he usado por primera
vez <code>let</code>, y además he descubierto la distintas formas en las que se
puede conseguir una fecha con la función <code>format-time-string</code>.
</p>

<p>
A continuación dejo el código y un ejemplo de uso cuando el usuario
introduce la cadena "Carlos" por teclado.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">  (<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">holamundo</span>()
  (<span style="color: #b6a0ff;">interactive</span>)
  <span style="color: #79a8ff;">"Hola mundo interactivo que pide el nombre del usuario y dice la fecha de hoy."</span>
  (<span style="color: #b6a0ff;">let</span> ((nombre (read-string <span style="color: #79a8ff;">"Introduce tu nombre: "</span>))
    (diasem (format-time-string <span style="color: #79a8ff;">"%A"</span>))
    (dia (format-time-string <span style="color: #79a8ff;">"%d"</span>))
    (mes (format-time-string <span style="color: #79a8ff;">"%B"</span>)))
    (message <span style="color: #79a8ff;">"Buenos d&#237;as %s, hoy es %s %s de %s"</span> nombre diasem dia mes)))

(holamundo)

  <span style="color: #79a8ff;">"Buenos d&#237;as Carlos, hoy es domingo 22 de marzo"</span> 

</pre>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,gnulinux.html">emacs,gnulinux</a> </div>]]></description>
  <category><![CDATA[emacs,gnulinux]]></category>
  <link>https://www.finaprosadigital.com/2026-03-28-hola-mundo-en-emacs-lisp.html</link>
  <guid>https://www.finaprosadigital.com/2026-03-28-hola-mundo-en-emacs-lisp.html</guid>
  <pubDate>Sat, 28 Mar 2026 18:58:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[LLM]]></title>
  <description><![CDATA[
<p>
Inspirado por el post de <a href="https://sive.rs/ai">Derek Sivers</a> he decidido crear una entrada
sobre cómo uso los modelos de lenguaje en este blog y en general.
</p>

<p>
En los posts que tengo en español que yo recuerde no los he usado para
nada, y en los que tengo en inglés alguna vez le he pasado alguna
frase para que me revisara la gramática.
</p>

<p>
Aparte de eso, igual en el futuro hago algún experimento con Gemini,
ChatGPT, Grok o el modelo que sea, pero en principio no me apoyo en
LLMs para escribir.
</p>

<p>
En mi día a día a veces uso Gemini sobre todo si veo que me puede
ahorrar tiempo para buscar algo, o para preguntar alguna curiosidad
que me surja.
</p>

<p>
También he probado algunos modelos locales con ollama, pero como no
tengo mucha potencia de cálculo local eran modelos muy sencillos.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-llm,ai,blog.html">llm,ai,blog</a> </div>]]></description>
  <category><![CDATA[llm,ai,blog]]></category>
  <link>https://www.finaprosadigital.com/2026-02-12-llm.html</link>
  <guid>https://www.finaprosadigital.com/2026-02-12-llm.html</guid>
  <pubDate>Thu, 12 Feb 2026 18:35:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[The people of Emacs]]></title>
  <description><![CDATA[
<p>
The philosophy behind Emacs fosters a really wonderful community. There are tons of people that have helped me learn and improve my Emacs configuration and knowledge, but in order to write this post I've chosen three.
</p>
<div id="outline-container-orgc89dc81" class="outline-2">
<h2 id="orgc89dc81">Mickey Petersen</h2>
<div class="outline-text-2" id="text-orgc89dc81">
<p>
When I finished the Emacs tutorial, I was wondering how I could improve my skills. I knew about Planet Emacs, but I didn't have the knowledge to understand the majority of the posts written there. Although I knew the basics of Emacs, I wanted to advance to the next level.
</p>

<p>
Then I discovered "Mastering Emacs". It was through reading that book that I really went from noob to grasping the more advanced capabilities of the text editor. I became able to skim through other people's posts in Planet Emacs and test their Elisp snippets, programs or configurations.
</p>

<p>
I have to thank Mickey because it was a really enjoyable read. I could understand every bit of the book without making any effort at all, which finally helped me to learn to use M-x, install and configure packages and evaluate Elisp code.
</p>
</div>
</div>
<div id="outline-container-orgb04d723" class="outline-2">
<h2 id="orgb04d723">Sacha Chua</h2>
<div class="outline-text-2" id="text-orgb04d723">
<p>
I think it was after reading "Mastering Emacs" that I started looking at Sacha Chua's posts. Sacha Chua is, of course, one of the main pillars of the Emacs community, and in fact Planet Emacs is run by her.
</p>

<p>
The first configuration that I cloned with git was Sacha's. I learnt a lot by skimming through her quasi-infinite Sacha.org. I started to discover a lot of Emacs packages that I have used every day since.
</p>

<p>
And of course there is the Emacs News and the Emacs Conf. Sacha is the one who gathers a lot of people around Emacs.
</p>
</div>
</div>
<div id="outline-container-org7e5adb1" class="outline-2">
<h2 id="org7e5adb1">Protesilaos Stavrou</h2>
<div class="outline-text-2" id="text-org7e5adb1">
<p>
My next step in the Emacs Way is to properly learn Elisp. Here I think Prot is the king, with his affordable coaching lessons. I can't think of a better way to learn. He is patient, knows how to adapt to every person and is a very good teacher. With his help, you can start to craft your very own Emacs configuration including macros and other advanced Elisp stuff.
</p>

<p>
Then of course there are the Modus themes, which are now part of Emacs itself. There are also a lot of packages written by Prot, accompanied by top-notch documentation. His code is also very clear and easy to read. Perfect for learning.
</p>

<p>
Prot has also his fantastic "Prot Asks" series of videos, in which he talks with people about a lot of different topics. I was lucky to inaugurate the series of videos and it was a pleasure to chat for one hour with him. Of course, the common denominator of all the people around Prot is the love for Emacs and in general libre software.
</p>
</div>
</div>
<div id="outline-container-org774b488" class="outline-2">
<h2 id="org774b488">Conclusion</h2>
<div class="outline-text-2" id="text-org774b488">
<p>
Emacs is more than the flagship of the libre software movement. It is a way of life. I think the best way to conclude this post is with a quote from Prot himself:
</p>

<p>
"Choosing Emacs is not just a matter of
deciding how to edit text. It largely is about what kind of person one wants to be."
</p>
<ul class="org-ul">
<li>Protesilaos (<a href="https://www.syntopikon.com/workflows/protesilaos-stavrou/">https://www.syntopikon.com/workflows/protesilaos-stavrou/</a>)</li>
</ul>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-carnival,.html">carnival,</a> <a href="https://www.finaprosadigital.com/tag-people.html">people</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[carnival,]]></category>
  <category><![CDATA[people]]></category>
  <link>https://www.finaprosadigital.com/2025-12-31-the-people-of-emacs.html</link>
  <guid>https://www.finaprosadigital.com/2025-12-31-the-people-of-emacs.html</guid>
  <pubDate>Wed, 31 Dec 2025 14:42:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Ahora]]></title>
  <description><![CDATA[
<p>
El otro día me encontré un post de <a href="https://michal.sapka.pl/2025/now/">Michał M. Sapka</a> sobre las
cosas que está haciendo ahora y me pareció curioso replicarlo aquí:
</p>

<ul class="org-ul">
<li>Programando: Aplicación Economía Circular con Xcrud</li>
<li>Leyendo: Circo Máximo de Santiago Posteguillo</li>
<li>Leyendo: JavaScript: The Definitive Guide, 7th Edition de David
Flanagan</li>
<li>Jugando: Pokémon Leyendas Z-A</li>
<li>Jugando: Nethack (tnnt.org)</li>
<li>Viendo: Stranger Things</li>
</ul>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-ahora.html">ahora</a> </div>]]></description>
  <category><![CDATA[ahora]]></category>
  <link>https://www.finaprosadigital.com/2025-11-30-ahora.html</link>
  <guid>https://www.finaprosadigital.com/2025-11-30-ahora.html</guid>
  <pubDate>Sun, 30 Nov 2025 12:25:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Maintenance (Mantenimiento)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el
<a href="https://plaindrops.de/blog/2025/emacscarnival/">Emacs Carnival</a>. La versión en castellano está tras la inglesa.
</p>

<p>
While maintenance sometimes is seen as something boring, I think
it's the perfect way to start learning things. First, you have to
know how things work in order to change and improve them. Thus,
if I spent more time maintaining my Emacs configuration, I would
surely learn enough Emacs Lisp to write more complex functions
and be able to improve my config a lot.
</p>

<p>
So, while a lot of people spend more time tweaking their Emacs
configuration file than actually using Emacs, for me it's just the
opposite. I wish I spent more time tweaking my Emacs setup.
</p>

<p>
El mantenimiento normalmente se ve como una tarea aburrida o
secundaria, pero yo creo que es la base para entender cómo funcionan
los sistemas. Primero tienes que saber de qué forma está algo montado
para luego poder cambiarlo o mejorarlo. Por eso creo que el primer
paso para aprender más Emacs Lisp sería pasar más tiempo manteniendo
mi configuración, y esto me permitiría escribir funciones más
complejas que harían que mi configuración mejorase un montón.
</p>

<p>
Así que, mientras que la mayoría de gente que leo en blogs se suele
quejar de que pasa más tiempo configurando Emacs que usándolo, para mí
es justo al revés, creo que debería pasar más tiempo revisando y
manteniendo mi configuración.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-carnival,.html">carnival,</a> <a href="https://www.finaprosadigital.com/tag-maintenance.html">maintenance</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[carnival,]]></category>
  <category><![CDATA[maintenance]]></category>
  <link>https://www.finaprosadigital.com/2025-10-12-maintenance-(mantenimiento).html</link>
  <guid>https://www.finaprosadigital.com/2025-10-12-maintenance-(mantenimiento).html</guid>
  <pubDate>Sun, 12 Oct 2025 13:25:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[El libro del sol nuevo]]></title>
  <description><![CDATA[
<p>
La primera vez que me leí "La sombra del torturador", el primer libro
de los cuatro que forman El libro del sol nuevo, no me enteré de
nada. De hecho, no me enteré de nada hasta tal punto que no tenía
intención de volver a leerlo nunca más. No me pareció un mal libro, me
pareció entretenido y disfruté su lectura, pero noté que la historia
que contaba se me escapaba, que no entendía qué estaba pasando.
</p>

<p>
Me dio por leer algunas reseñas en varios blogs y vi que Gene Wolfe no
era un escritor cualquiera. Además de ser un ingeniero mecánico que
había colaborado en el diseño de la máquina que hace las patatas
Pringles, también diseñaba sus libros como si fueran un auténtico
rompecabezas.
</p>

<p>
No enterarse de nada cuando lees por primera vez un libro de Gene
Wolfe no es algo raro, es lo normal. Son libros que están diseñados
para releerse, con infinidad de matices y capas ocultas. Si bien en
una primera lectura atenta se pueden unir muchas piezas, es imposible
armar todo el puzzle sin volver a leer su obra varias veces.
</p>

<p>
Lo mágico de estas relecturas es cómo va cambiando la novela a medida
que el lector se va introduciendo en el mundo. La segunda vez que me
leí "La sombra del torturador" me pareció que me estaba leyendo otro
libro distinto. No sólo le presté mucha más atención, si no que ya
conocía aunque fuera de refilón el mundo y sus personajes, y ya estaba
preparado para empezar a entender la historia. Y sin embargo, la
tercera vez que me lo leí disfruté infinitamente más que las dos
primeras, porque ya me sentía como alguien que conocía a Severian (el
protagonista), y estaba empezando a unir los hilos de todos los
pequeños detalles que van apareciendo por la novela.
</p>

<p>
Leer a Gene Wolfe no es algo fácil, hace falta concentración. Sus
novelas no tratan al lector como un ente sin inteligencia que sólo
quiere echar el rato. Hace falta esfuerzo para sacarle el jugo a sus
obras. Pero la recompensa merece la pena. Es muy gratificante ir
viendo cómo se forma el mundo que en un primer momento ni siquiera te
habías dado cuenta de que estaba ahí.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-gene,.html">gene,</a> <a href="https://www.finaprosadigital.com/tag-wolfe,.html">wolfe,</a> <a href="https://www.finaprosadigital.com/tag-literatura.html">literatura</a> </div>]]></description>
  <category><![CDATA[gene,]]></category>
  <category><![CDATA[wolfe,]]></category>
  <category><![CDATA[literatura]]></category>
  <link>https://www.finaprosadigital.com/2025-10-05-el-libro-del-sol-nuevo.html</link>
  <guid>https://www.finaprosadigital.com/2025-10-05-el-libro-del-sol-nuevo.html</guid>
  <pubDate>Sun, 05 Oct 2025 18:37:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Obscure packages (Paquetes raros)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el
<a href="https://goritskov.com/posts/obscure_packages.html">Emacs Carnival</a>. La versión en castellano está tras la inglesa.
</p>
<div id="outline-container-org5f5a1b3" class="outline-2">
<h2 id="org5f5a1b3">Obscure packages</h2>
<div class="outline-text-2" id="text-org5f5a1b3">
<p>
This month Emacs Carnival is about obscure packages. Since I have not
met anyone in real life using Emacs, I would say Emacs itself it's
quite obscure, but there are some packages that everyone using Emacs
know, like Vertico, Helm, Magit, Company, etc.
</p>

<p>
So I've selected three packages which I think are obscure enough.
</p>
</div>
<div id="outline-container-orgc99c791" class="outline-3">
<h3 id="orgc99c791">vhdl-mode</h3>
<div class="outline-text-3" id="text-orgc99c791">
<p>
The first one is vhdl-mode. VHDL is a hardware design language, which
by itself is not known to a lot of people outside the electronic
engeenering world, so the intersection of both VHDL and Emacs worlds
must be tiny. I have a <a href="https://www.finaprosadigital.com/2024-02-17-vhdl-en-emacs.html">post</a> about VHDL on Emacs, but in short it's
just a mode to write VHDL code inside Emacs. It has a beautify command
that makes your code really clean in a moment, and of course you can
use all the commands that you use normally in Emacs. It's awesome!
</p>
</div>
</div>
<div id="outline-container-org78735fa" class="outline-3">
<h3 id="org78735fa">nethack-el</h3>
<div class="outline-text-3" id="text-org78735fa">
<p>
The second one is <a href="https://www.nongnu.org/nethack-el/">nethack-el</a>. This one is sadly not maintained anymore,
but it must be really great to be able to play Nethack inside
Emacs. It would make very easy to take notes while playing, copy the
levels to a file (since is all ASCII) or whatever you want to do.
</p>
</div>
</div>
<div id="outline-container-org87367b8" class="outline-3">
<h3 id="org87367b8">spanish-holidays</h3>
<div class="outline-text-3" id="text-org87367b8">
<p>
The third one is my own Emacs package, <code>spanish-holidays.el</code>. I found
really useful the Emacs calendar, and I wanted to use it to know the
holidays in my country at a glance. I saw that there were various
holidays packages for different countries, but none for Spain, so I
just copied the mexican-holidays package but changing the dates for
the ones in Spain. At the moment it has over one hundred downloads in
melpa, so it's obscure enough to close this packages' list!
</p>

<p>
El tema de este mes para el Festival de Emacs son paquetes poco
conocidos, así que he seleccionado algunos paquetes que creo que son
bastante raros.
</p>

<p>
Como no conozco a nadie en persona que use Emacs, diría que Emacs en
sí ya es bastante raro. No obstante, hay paquetes que todo el mundo
conoce como Vertico, Helm, Magit, Company&#x2026;
</p>
</div>
</div>
</div>
<div id="outline-container-org8071ab6" class="outline-2">
<h2 id="org8071ab6">Paquetes raros</h2>
<div class="outline-text-2" id="text-org8071ab6">
<p>
En esta entrada he seleccionado tres paquetes que creo que son
bastante raros para el tema de este mes de "Emacs Carnival", que trata
sobre paquetes poco conocidos.
</p>
</div>
<div id="outline-container-org1b1d384" class="outline-3">
<h3 id="org1b1d384">vhdl-mode</h3>
<div class="outline-text-3" id="text-org1b1d384">
<p>
El primero es vhdl-mode. VHDL es un lenguaje de descripción de
hardware, cosa que ya es bastante rara de por sí fuera del mundo de la
ingeniería electrónica, así que la intersección entre la gente que
programe VHDL y además use Emacs tiene que ser bastante pequeña.
</p>

<p>
Tengo un <a href="https://www.finaprosadigital.com/2024-02-17-vhdl-en-emacs.html">post</a> sobre VHDL en Emacs, pero en resumen es simplemente un
modo para programar en VHDL usando Emacs. Hasta tiene un comando
"beautify" que te pone el búfer mucho más bonito, es muy útil y cómodo.
</p>
</div>
</div>
<div id="outline-container-org0d13cc1" class="outline-3">
<h3 id="org0d13cc1">nethack-el</h3>
<div class="outline-text-3" id="text-org0d13cc1">
<p>
El segundo es <a href="https://www.nongnu.org/nethack-el/">nethack-el</a>. Por desgracia no se sigue manteniendo a día
de hoy, pero debe de ser increíble poder jugar al Nethack dentro de
Emacs. Haría trivial el hecho de tomar notas jugando, así como copiar
niveles enteros de un solo atajo de teclado.
</p>
</div>
</div>
<div id="outline-container-org3892ff7" class="outline-3">
<h3 id="org3892ff7">spanish-holidays</h3>
<div class="outline-text-3" id="text-org3892ff7">
<p>
El último paquete es el más raro de todos, spanish-holidays. El
calendario integrado de Emacs es el que más uso, y siempre había
querido poder marcar las vacaciones de España en él. Había visto
varios paquetes que incluían vacaciones nacionales para otros países,
pero no encontré ninguno para España, así que lo hice yo. Simplemente
vi la estructura del paquete mexican-holidays y sustituí las fechas
por los festivos españoles. Ahora mismo tiene unas cien descargas en
melpa, así que es lo bastante extraño como para cerrar esta lista.
</p>
</div>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-carnival,.html">carnival,</a> <a href="https://www.finaprosadigital.com/tag-obscure,.html">obscure,</a> <a href="https://www.finaprosadigital.com/tag-packages,.html">packages,</a> <a href="https://www.finaprosadigital.com/tag-english.html">english</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[carnival,]]></category>
  <category><![CDATA[obscure,]]></category>
  <category><![CDATA[packages,]]></category>
  <category><![CDATA[english]]></category>
  <link>https://www.finaprosadigital.com/2025-09-14-obscure-packages-(paquetes-raros).html</link>
  <guid>https://www.finaprosadigital.com/2025-09-14-obscure-packages-(paquetes-raros).html</guid>
  <pubDate>Sun, 14 Sep 2025 16:39:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Elevator pitch for Emacs (Discurso de ascensor para Emacs)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el <a href="https://takeonrules.com/2025/08/01/emacs-carnival-2025-08-your-elevator-pitch-for-emacs/">Emacs Carnival</a>.
La versión en castellano está tras la inglesa.
</p>

<p>
Emacs is an extensible text editor. You can configure it beyond your imagination. It adapts to your needs, and you can mold it to your liking. With Emacs you can discover the beauty of plain text. You can start doing simple things and gradually build your perfect setup. Whether it's mailing, writing, journaling, taking notes, programming or even making books, Emacs has you covered.
</p>

<p>
Emacs es un editor de texto totalmente personalizable. Lo puedes
configurar más allá de tu imaginación. Se adapta como un guante a tus
necesidades, y lo puedes moldear a tu gusto. Con Emacs, descubrirás la
belleza del texto plano. Puedes empezar haciendo cosas simples, y poco
a poco ir construyendo tu configuración perfecta. Ya sea escribir
correos, textos, diarios, tomar notas, programar o inculuso editar
libros, Emacs tiene todo lo que necesitas.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-english.html">english</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[english]]></category>
  <link>https://www.finaprosadigital.com/2025-08-06-elevator-pitch-for-emacs-(discurso-de-ascensor-para-emacs).html</link>
  <guid>https://www.finaprosadigital.com/2025-08-06-elevator-pitch-for-emacs-(discurso-de-ascensor-para-emacs).html</guid>
  <pubDate>Wed, 06 Aug 2025 23:04:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Prot asks Carlos]]></title>
  <description><![CDATA[
<p>
Hace un par de días grabé con <a href="https://protesilaos.com/">Protesilaos</a> el primer vídeo de su serie
"Prot asks". Es una serie de vídeos que se ha propuesto hacer en los
que simplemente charla durante una hora con gente sobre cosas
relacionadas con Emacs y con la vida en general.
</p>

<p>
En el vídeo que ha hecho conmigo hablamos sobre Emacs en la
ingeniería, fútbol, España y la libertad de acceso a las publicaciones
en el mundo académico, entre otras cosas.
</p>

<p>
El enlace al vídeo está <a href="https://protesilaos.com/codelog/2025-07-12-prot-asks-carlos-emacs-engineering-life-spain/">aquí</a>.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-protesilaos,.html">protesilaos,</a> <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-charla,.html">charla,</a> <a href="https://www.finaprosadigital.com/tag-english.html">english</a> </div>]]></description>
  <category><![CDATA[protesilaos,]]></category>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[charla,]]></category>
  <category><![CDATA[english]]></category>
  <link>https://www.finaprosadigital.com/2025-07-15-prot-asks-carlos.html</link>
  <guid>https://www.finaprosadigital.com/2025-07-15-prot-asks-carlos.html</guid>
  <pubDate>Tue, 15 Jul 2025 18:06:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Writing on Emacs (Escribiendo en Emacs)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el  <a href="https://gregnewman.io/blog/emacs-carnival-2025-07-writing-experience/">Emacs Carnival</a>.
La versión en castellano está tras la inglesa.
</p>
<div id="outline-container-org6b1f19b" class="outline-2">
<h2 id="org6b1f19b">Writing on Emacs</h2>
<div class="outline-text-2" id="text-org6b1f19b">
</div>
<div id="outline-container-orga062c83" class="outline-3">
<h3 id="orga062c83">Org-mode</h3>
<div class="outline-text-3" id="text-orga062c83">
<p>
Everything I write in Emacs I write it in org-mode. It's core is very
simple, but is very powerful. At first, I used just the bullets to
create hierarchical texts, but step by step I discovered all the
things that org-mode can do.
</p>

<p>
Now I use it to track time, write journals, take notes, write blog posts&#x2026;
</p>
</div>
</div>
<div id="outline-container-orgde42a37" class="outline-3">
<h3 id="orgde42a37">Journal</h3>
<div class="outline-text-3" id="text-orgde42a37">
<p>
I keep a register of what I do every day. For this, I just simply use
an org template, and then, when I'm done, I encrypt the file just
naming it with a .org.gpg extension and Emacs take care of the rest.
</p>
</div>
</div>
<div id="outline-container-org5093b49" class="outline-3">
<h3 id="org5093b49">Notes</h3>
<div class="outline-text-3" id="text-org5093b49">
<p>
I use the org-roam package to take notes. Again, I use a template, but
instead of writing everything to the same file as in the journal,
org-roam is best suited to take short notes and then connect them,
just like in the Zettelkasten method.
</p>

<p>
I can then search for my notes with org-roam-node-find, visualize a
graph with org-roam-graph and do a lot of things.
</p>
</div>
</div>
<div id="outline-container-org9e3332c" class="outline-3">
<h3 id="org9e3332c">Blog</h3>
<div class="outline-text-3" id="text-org9e3332c">
<p>
For my blog I use org-blog-static. I write an org file, and when the
post is finished I publish it with org-static-blog-publish. The
process of publishing exports the org file to an html with the css
that I have for my blog.
</p>

<p>
That's it, very simple, so that I can focus on writing.
</p>
</div>
</div>
<div id="outline-container-org5f9e181" class="outline-3">
<h3 id="org5f9e181">Conclusion</h3>
<div class="outline-text-3" id="text-org5f9e181">
<p>
Writing on Emacs is a very pleasant experience. With org-mode, I have
all I need to write (links, export options, templates, organization)
and with Emacs I have the keybindings to move through the text, the
dictionary, and the same workflow that I have for the rest of things
that are not writing.
</p>
</div>
</div>
</div>
<div id="outline-container-org6eb4189" class="outline-2">
<h2 id="org6eb4189">Escribiendo en Emacs</h2>
<div class="outline-text-2" id="text-org6eb4189">
</div>
<div id="outline-container-org877d6fc" class="outline-3">
<h3 id="org877d6fc">Modo Org</h3>
<div class="outline-text-3" id="text-org877d6fc">
<p>
Todo lo que escribo en Emacs lo hago con el modo Org. Su base es muy
simple, pero aún así es muy potente. Empecé usando sólo lo básico, la
estructura de asteriscos que tiene Org que te permite crear diferentes
apartados dentro de un mismo archivo (sería lo análogo a crear una
jerarquía tipo 1.2.3 pero sustituyendo los números por asteriscos),
pero poco a poco fui descubriendo el resto de cosas que tiene este
paquete de Emacs.
</p>

<p>
Ahora lo uso para prácticamente todo lo que sea escribir en Emacs:
entradas de notas, archivos de blog, registros&#x2026;
</p>
</div>
</div>
<div id="outline-container-orga9da4d6" class="outline-3">
<h3 id="orga9da4d6">Diario</h3>
<div class="outline-text-3" id="text-orga9da4d6">
<p>
Llevo un registro diario de lo que hago cada día. Para automatizarlo,
uso una plantilla de Org, y luego, cuando he terminado de escribirlo,
lo guardo con extensión .org.gpg para que Emacs lo encripte.
</p>
</div>
</div>
<div id="outline-container-orga687ce7" class="outline-3">
<h3 id="orga687ce7">Notas</h3>
<div class="outline-text-3" id="text-orga687ce7">
<p>
Para tomar notas uso el paquete org-roam, con otra plantilla, sólo que
esta vez está configurada para que cada nota la meta en un archivo
distinto, y el paquete org-roam se encarga de crear enlaces entre
los distintos archivos de forma sencilla.
</p>

<p>
Cuando he terminado le puedo echar un vistazo a mis notas con
org-roam-node-find, o incluso crear un diagrama de bolas con
org-roam-graph, para ver todas mis notas de un vistazo de forma
gráfica.
</p>
</div>
</div>
<div id="outline-container-org7bbb6fd" class="outline-3">
<h3 id="org7bbb6fd">Blog</h3>
<div class="outline-text-3" id="text-org7bbb6fd">
<p>
Para el blog uso org-blog-static. Simplemente escribo un archivo .org
normal, y luego lo publico con org-static-blog-publish. Al hacer la
publicación, el archivo .org se convierte en .html y coge el css que
tengo para mi blog.
</p>

<p>
Es todo muy sencillo, así me puedo centrar en escribir sin preocuparme
de nada más.
</p>
</div>
</div>
<div id="outline-container-orgb191764" class="outline-3">
<h3 id="orgb191764">Conclusión</h3>
<div class="outline-text-3" id="text-orgb191764">
<p>
Escribir en Emacs es muy agradable. Con el modo Org, tengo todo lo que
necesito (enlaces, exportación a otros formatos, plantillas,
organización&#x2026;) y con Emacs tengo los atajos de teclado que me
permiten editar texto fácilmente, además de las demás facilidades que
proporciona Emacs.
</p>
</div>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-writing,.html">writing,</a> <a href="https://www.finaprosadigital.com/tag-escribiendo,.html">escribiendo,</a> <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-org.html">org</a> </div>]]></description>
  <category><![CDATA[writing,]]></category>
  <category><![CDATA[escribiendo,]]></category>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[org]]></category>
  <link>https://www.finaprosadigital.com/2025-07-13-writing-on-emacs-(escribiendo-en-emacs).html</link>
  <guid>https://www.finaprosadigital.com/2025-07-13-writing-on-emacs-(escribiendo-en-emacs).html</guid>
  <pubDate>Sun, 13 Jul 2025 15:26:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Elfeed]]></title>
  <description><![CDATA[
<p>
Mi forma preferida de leer los blogs y páginas que sigo es <a href="https://es.wikipedia.org/wiki/RSS">RSS</a>. Con un lector de RSS, se puede estar al tanto de un montón de páginas sin tener que estar visitándolas a diario. Simplemente las entradas nuevas aparecen en la portada del lector RSS y así se pueden ver todas de un vistazo, para luego leerlas o visitar el sitio original.
</p>

<p>
En Emacs, el lector de RSS que uso se llama Elfeed. Su configuración y uso es muy simple, pero a la vez es muy potente. Permite etiquetar las diversas entradas de forma automática o manual, y usar filtros para ocultar o mostrar lo que nos interese.
</p>

<p>
Una de las ventajas de RSS es que se pueden generar fácilmente los archivos xml que usan los lectores como Elfeed. Por ejemplo, se pueden sacar xml de canales de Youtube, y así se puede estar al tanto de los vídeos nuevos sin tener que visitar Youtube.
</p>

<p>
Como ejemplo, dejo mi lista de feeds, parte de mi <a href="https://gitlab.com/gnuhack/dotfiles/-/blob/master/.emacs.d/custom.el?ref_type=heads">configuración de Emacs</a>:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(elfeed-feeds
   '((<span style="color: #79a8ff;">"https://yewtu.be/feed/channel/UCDy1lHSVGBDL0d2_C5NZNJw"</span> Themaoisha
      Video)
     (<span style="color: #79a8ff;">"http://antirez.com/rss"</span> Antirez Blog)
     (<span style="color: #79a8ff;">"https://stallman.org/rss/rss.xml"</span> RMS)
     (<span style="color: #79a8ff;">"https://notxor.nueva-actitud.org/rss.xml"</span> Noxtor Blog)
     (<span style="color: #79a8ff;">"http://finaprosadigital.com/publish/blog/rss.xml"</span> CPR)
     (<span style="color: #79a8ff;">"https://taonaw.com/index.xml"</span> Emacs TAONAW)
     (<span style="color: #79a8ff;">"http://feeds.feedburner.com/uGeekBlog"</span> Emacs uGeek)
     (<span style="color: #79a8ff;">"https://daemons.it/posts/index.xml"</span> Emacs daemon)
     (<span style="color: #79a8ff;">"https://lukesmith.xyz/rss.xml"</span> Luke)
     (<span style="color: #79a8ff;">"https://videos.lukesmith.xyz/feeds/videos.xml?sort=-publishedAt&amp;filter=local"</span>
      Video)
     (<span style="color: #79a8ff;">"https://www.youtube.com/feeds/videos.xml?channel_id=UCaifrB5IrvGNPJmPeVOcqBA"</span>
      Kruggsmash Video)
     (<span style="color: #79a8ff;">"https://www.bay12games.com/dwarves/dev_now.rss"</span> Dwarf Fortress
      Video)
     (<span style="color: #79a8ff;">"https://www.youtube.com/feeds/videos.xml?channel_id=UCD6VugMZKRhSyzWEWA9W2fg"</span>
      Video)
     (<span style="color: #79a8ff;">"https://karl-voit.at/feeds/lazyblorg-all.atom_1.0.links-only.xml"</span>
      Blog Voit)
     (<span style="color: #79a8ff;">"https://planet.emacslife.com/atom.xml"</span> Emacs)
     (<span style="color: #79a8ff;">"https://protesilaos.com/master.xml"</span> Prot Blog)
     (<span style="color: #79a8ff;">"https://greenwald.substack.com/feed"</span> Glenn Blog)
     (<span style="color: #79a8ff;">"https://victorhckinthefreeworld.com/feed/"</span> Victr Blog)
     (<span style="color: #79a8ff;">"https://sachachua.com/blog/feed/"</span> Sacha Blog)
     (<span style="color: #79a8ff;">"https://www.danielclemente.com/cambios/cambios.xml"</span> Blog)
     (<span style="color: #79a8ff;">"https://edwardsnowden.substack.com/feed.xml"</span> Snowden Blog)
     (<span style="color: #79a8ff;">"https://twobithistory.org/feed.xml"</span> 2bit Blog)))
</pre>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-elfeed,.html">elfeed,</a> <a href="https://www.finaprosadigital.com/tag-rss,.html">rss,</a> <a href="https://www.finaprosadigital.com/tag-emacs.html">emacs</a> </div>]]></description>
  <category><![CDATA[elfeed,]]></category>
  <category><![CDATA[rss,]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://www.finaprosadigital.com/2025-07-01-elfeed.html</link>
  <guid>https://www.finaprosadigital.com/2025-07-01-elfeed.html</guid>
  <pubDate>Tue, 01 Jul 2025 18:37:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Acerca de]]></title>
  <description><![CDATA[
<div id="outline-container-org3785b4c" class="outline-2">
<h2 id="org3785b4c">Contacto</h2>
<div class="outline-text-2" id="text-org3785b4c">
<ul class="org-ul">
<li>email: carlos@pajuelo.com</li>
<li>email alternativo: carlospajuelo_@hotmail.com</li>
</ul>
</div>
</div>
<div id="outline-container-orgbcd8529" class="outline-2">
<h2 id="orgbcd8529">Acerca del blog</h2>
<div class="outline-text-2" id="text-orgbcd8529">
<p>
Me llamo Carlos, soy un apasionado del software libre y empecé este
blog para aprender mejor cómo funcionaba internet; qué era un dominio,
qué era un servidor, qué es el html y el css, y en general todo lo que
hace posible que naveguemos por internet.
</p>

<p>
El blog está alojado en una Raspberry Pi 2, y en un principio mi idea
era escribir sobre software libre, aunque al final he acabado
escribiendo sobre cualquier cosa que se me pase por la cabeza
(literatura, videojuegos, lenguages de programación&#x2026;).
</p>

<p>
Por último, me gusta la idea de tener un rincón personal en internet fuera
del alcance de las grandes corporaciones, tener el control sobre mis
publicaciones y hacer una web simple, sin anuncios ni rastreos.
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-contacto,.html">contacto,</a> <a href="https://www.finaprosadigital.com/tag-sobre.html">sobre</a> <a href="https://www.finaprosadigital.com/tag-mi,.html">mi,</a> <a href="https://www.finaprosadigital.com/tag-acerca.html">acerca</a> <a href="https://www.finaprosadigital.com/tag-de.html">de</a> </div>]]></description>
  <category><![CDATA[contacto,]]></category>
  <category><![CDATA[sobre]]></category>
  <category><![CDATA[mi,]]></category>
  <category><![CDATA[acerca]]></category>
  <category><![CDATA[de]]></category>
  <link>https://www.finaprosadigital.com/2025-06-25-acerca-de.html</link>
  <guid>https://www.finaprosadigital.com/2025-06-25-acerca-de.html</guid>
  <pubDate>Wed, 25 Jun 2025 18:17:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Take two on Emacs (Toma dos de Emacs)]]></title>
  <description><![CDATA[
<p>
Nota: Este post tiene una versión en inglés para participar en el "Emacs Carnival" (<code>https://christiantietze.de/posts/2025/06/emacs-carnival-2025-06-take-two/</code>). La versión en castellano está tras la inglesa.
</p>
<div id="outline-container-org59684d5" class="outline-2">
<h2 id="org59684d5">Take Two on Emacs</h2>
<div class="outline-text-2" id="text-org59684d5">
<p>
I first discovered Emacs back at middle school, because it was installed on the school's computers. I have no idea what Emacs was, and the description on the splash screen wasn't really helpful for me.
</p>

<p>
I find it weird, the mouse experience was not smooth, and every time I wanted to closed it, it said something about "modified buffers". What is a buffer? Why was it modified if I hadn't not touched anything?
</p>

<p>
It wasn't until several years later, in a conference that Richard Stallman gave in Seville, that I discovered what Emacs was. I was then decided to try again Emacs, and find out whether it was worth it or not.
</p>

<p>
I really didn't like that you have to learn yet another programming language to really dive into Emacs, but when I discovered Emacs Lisp I was really impressed. Today is one of my favorite computer languages, and it is really a pleasure to play with Elisp.
</p>

<p>
My first steps with Emacs were magical. When I started the tutorial and scrolled to the next screen with C-v I discovered a whole new world. From there, the omnipresence of the terminal and keyboard-driven UI was born for me. I no longer looked backwards. I moved from a normal desktop environment to a tiling window manager (i3wm), and hopefully some day I will move into EXWM, if only to try it when I have time.
</p>

<p>
I struggle a little bit to become a proficient Emacs user. At first I saw all the wonderful Planet Emacs posts, but I didn't even know how to install packages or try the things the different posts explained.
</p>

<p>
But after reading the fine manual (and also after discovering info, which is now my favorite program to read manuals) a little bit, I started to grow confidence and started to understand the language in which the "Emacs people" talk.
</p>

<p>
From that point, the rest was very enjoyable, and I am still a noob in the Emacs world but I learn a little every day, and now I use Emacs for almost everything.
</p>
</div>
</div>
<div id="outline-container-orgcbc0451" class="outline-2">
<h2 id="orgcbc0451">Toma dos de Emacs</h2>
<div class="outline-text-2" id="text-orgcbc0451">
<p>
Descubrí Emacs en el instituto, porque era parte de la distribución de Guadalinex que tenían todos los ordenadores. Cuando lo abrí por primera vez no tenía ni idea de qué era, simplemente vi un icono que no sabía qué era en el menú de aplicaciones y pinché sobre él.
</p>

<p>
Me pareció bastante feo a primera vista, además el ratón no funcionaba como yo esperaba, y encima cada vez que lo quería cerrar me decía algo de "existen búfers modificados". Pero yo no tenía ni idea de qué era un búfer y además ni siquiera había modificado nada, ¿por qué salía esa advertencia?
</p>

<p>
Hasta varios años después, en una conferencia de Richard Stallman en la Escuela Técnica Superior de Ingeniería Informática de Sevilla, no descubrí realmente qué era Emacs. Después de la magistral charla de Stallman decidí que tenía que probarlo y ver si realmente merecía la pena.
</p>

<p>
No me gustó lo de tener que aprender otro lenguaje de programación más para poder sacarle todo el partido a Emacs, pero cuando descubrí Emacs Lisp me quedé alucinado. Hoy es uno de mis lenguajes de programación favoritos, y es una experiencia muy placentera jugar con Elisp.
</p>

<p>
Mis primeros pasos con Emacs fueron algo mágico. Cuando empecé el tutorial integrado y pasé a la siguiente pantalla con C-v algo dentro de mi cabeza hizo clic, y a partir de ahí mi visión sobre la informática cambió. Empecé a hacerlo todo con la terminal y a manejar el ordenador casi exclusivamente con el teclado. Nunca más volví a usar interfaces gráficas como opción predeterminada. Pasé de usar un entorno de escritorio normal y corriente a un gestor de ventanas tipo i3wm, y espero algún día tener tiempo de probar EXWM.
</p>

<p>
Me costó un poco aprender a ser un usuario en condiciones de Emacs. Al principio veía los posts de webs como <code>https://planet.emacslife.com/</code> y no entendía nada, no sabía cómo aplicar las configuraciones que ponía la gente o cómo probar los consejos que daban.
</p>

<p>
Pero después de leer el manual un poco (y de paso descubrir info, mi forma favorita de ver manuales), empecé a soltarme más y a entender la jerga de Emacs en la que hablan los que lo usan.
</p>

<p>
A partir de ahí, como ya tenía la base, aprender el resto ya fue mucho más divertido, y, aunque sigo siendo un principiante en el mundo de Emacs, ya lo uso casi para todo.
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-gnu,.html">gnu,</a> <a href="https://www.finaprosadigital.com/tag-linux,.html">linux,</a> <a href="https://www.finaprosadigital.com/tag-english.html">english</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[gnu,]]></category>
  <category><![CDATA[linux,]]></category>
  <category><![CDATA[english]]></category>
  <link>https://www.finaprosadigital.com/2025-06-12-take-two-on-emacs-(toma-dos-de-emacs).html</link>
  <guid>https://www.finaprosadigital.com/2025-06-12-take-two-on-emacs-(toma-dos-de-emacs).html</guid>
  <pubDate>Thu, 12 Jun 2025 00:05:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Calendarios en pdf]]></title>
  <description><![CDATA[
<p>
En Emacs hay varias formas de organizar las tareas usando
calendarios. Por un lado está el calendario ya integrado (<code>M-x
calendar</code>), en el que podemos señalar fechas con ayuda de un fichero
de texto que hace de diario. Por otro lado está el calendario que nos
crea la <code>org-agenda</code>, el cual podremos visualizar en forma de calendario
con el paquete <code>cfw:calendar</code>.
</p>

<p>
Sin embargo, a la hora de exportar a pdf un calendario para
imprimirlo, la mejor opción que he descubierto es el comando "t m" una
vez dentro del calendario integrado que se invoca con <code>M-x calendar</code>
(también está la opción H m para exportar a html).
</p>

<p>
Una vez exportado el calendario, podemos usar el comando <code>C-c C-b</code>
dentro del archivo .tex exportado, y esto nos generará un archivo
.dvi. Con la orden dvi2pdf podemos convertir finalmente el .dvi a pdf
para después imprimirlo.
</p>

<p>
Según el manual de Emacs, también se puede exportar el calendario de
la org-agenda pero el proceso parece bastante más complicado.
</p>

<p>
Antes de exportar el calendario, sobre el mismo archivo .tex, podemos
modificar las diferentes fechas para incluir los eventos que
queramos. De momento no he encontrado la forma de incluir los eventos
del archivo diario para integrarlos automáticamente, pero si no son
muchos no es difícil hacerlo a mano.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-org-mode,.html">org-mode,</a> <a href="https://www.finaprosadigital.com/tag-calendario.html">calendario</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[org-mode,]]></category>
  <category><![CDATA[calendario]]></category>
  <link>https://www.finaprosadigital.com/2025-06-01-calendarios-en-pdf.html</link>
  <guid>https://www.finaprosadigital.com/2025-06-01-calendarios-en-pdf.html</guid>
  <pubDate>Sun, 01 Jun 2025 19:05:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[MinUI]]></title>
  <description><![CDATA[
<div id="outline-container-org5a08f9b" class="outline-2">
<h2 id="org5a08f9b">MinUI</h2>
<div class="outline-text-2" id="text-org5a08f9b">
<p>
Aprovechando que me compré una RG28XX, he estado probando MinUI.
</p>

<p>
Este sistema operativo como su nombre indica es mínimo, y está pensado para jugar sin distracciones de ningún tipo, ni siquiera las típicas portadas o capturas de pantalla que aparecen en otros sistemas operativo cuando navegamos por la lista de juegos.
</p>

<p>
Por ello en principio no tiene soporte para Wifi o PortMaster, aunque creo que se le puede añadir con plugins o extras.
</p>

<p>
La interfaz minimalista es muy agradable y sencilla, y en una consola pequeña y pensada para partidas rápidas como la RG28XX encaja como un guante. El menú consiste tan solo en una lista con los diferentes sistemas que tengamos instalados, y en cada sistema podemos o bien empezar una partida nueva pulsando el botón "A" o bien cargar una ranura de guardado que tengamos con el botón "X".
</p>

<p>
Dentro del propio juego podemos configurar con un menú muy intuitivo y cómodo de usar tanto los ajustes básicos, así como los atajos de teclado. Por otro lado podemos tocar opciones más avanzadas de configuración del emulador que estemos usando o del "frontend" gráfico.
</p>

<p>
Así pues, cumple a la perfección su función de sistema simple para jugar, pero no por ello nos deja sin poder tocar opciones de configuración de los emuladores.
</p>

<p>
Como punto negativo, el sistema ahorra batería de forma muy agresiva, apagando la consola si no se usa en dos minutos, y este intervalo de tiempo no es configurable. Sin embargo, hay forks de MinUI que incrementan este tiempo por si lo preferimos.
</p>

<p>
En conclusión, un sistema que a día de hoy me ha parecido muy pulido, que cumple sobradamente su objetivo y cuyo único punto negativo que le he encontrado ha sido la ausencia de configuración en el sistema de serie de cosas como el tiempo de apagado o el LED de la consola, aunque todo esto se puede solucionar con forks o plugins.
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-minui,.html">minui,</a> <a href="https://www.finaprosadigital.com/tag-gnu/linux,.html">GNU/Linux,</a> <a href="https://www.finaprosadigital.com/tag-anbernic.html">Anbernic</a> </div>]]></description>
  <category><![CDATA[minui,]]></category>
  <category><![CDATA[GNU/Linux,]]></category>
  <category><![CDATA[Anbernic]]></category>
  <link>https://www.finaprosadigital.com/2025-05-01-minui.html</link>
  <guid>https://www.finaprosadigital.com/2025-05-01-minui.html</guid>
  <pubDate>Thu, 01 May 2025 11:52:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Knulli OS]]></title>
  <description><![CDATA[
<p>
Uno de los sistemas operativos alternativos para la RG40XXH es Knulli OS. Es un sistema basado en Batocera, que a su vez está basado en Arch Linux, pero todo esto es completamente invisible para el usuario.
</p>

<p>
La interfaz es muy agradable, e incluso incluye música de fondo en el menú principal por defecto. Además se puede conectar a diversas web para recolectar las carátulas, sinopsis y varios meta datos más sobre todos los juegos que tengamos con sólo pulsar un botón.
</p>

<p>
Sin embargo, a diferencia del sistema operativo por defecto de Anbernic, hay que configurar un poco diferentes aspectos para poder tener la misma experiencia de juego que nos ofrece Anbernic, que a día de hoy es bastante completa.
</p>

<p>
En primer lugar hay que configurar los shaders o efectos gráficos, si queremos que los juegos se vean como en las consolas originales. Tampoco están por defecto los marcos de diferentes consolas que rellenan el espacio en negro que se queda en pantalla si la relación de aspecto del sistema que estemos jugando no es exactamente 4:3.
</p>

<p>
En general, a día de hoy es un sistema muy completo y bonito, pero si sólo nos interesa encender y jugar con todo ya listo creo que es mejor opción el sistema operativo por defecto de Anbernic.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-gnu/linux,.html">GNU/Linux,</a> <a href="https://www.finaprosadigital.com/tag-knulli,.html">knulli,</a> <a href="https://www.finaprosadigital.com/tag-retro.html">retro</a> </div>]]></description>
  <category><![CDATA[GNU/Linux,]]></category>
  <category><![CDATA[knulli,]]></category>
  <category><![CDATA[retro]]></category>
  <link>https://www.finaprosadigital.com/2025-04-01-knulli-os.html</link>
  <guid>https://www.finaprosadigital.com/2025-04-01-knulli-os.html</guid>
  <pubDate>Tue, 01 Apr 2025 09:53:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Anbernic RG40XXH]]></title>
  <description><![CDATA[
<p>
La consola de Anbernic RG40XXH es una portátil estilo PSP pero con
relación de pantalla 4:3 y 4". Se pueden emular juegos hasta PSX sin
ningún problema, e incluso soporta bastantes de PSP y Dreamcast.
</p>

<p>
Como sistema operativo trae un Ubuntu 22.04, modificado por Anbernic
y listo para jugar con una buena interfaz y varias opciones para
emular.
</p>

<p>
Por un lado tiene Retroarch con varios cores disponibles, y por otro
los emuladores sueltos. Además se puede activar SSH para meter juegos
en la microSD de la consola por SFTP.
</p>

<p>
Para ello basta con ejecutar un script (por ejemplo:
<a href="https://github.com/xgbox/rg35xxsp-ssh-samba/blob/main/scripts/ssh_enable.sh">https://github.com/xgbox/rg35xxsp-ssh-samba/blob/main/scripts/ssh_enable.sh</a>)
que tendremos que colocar previamente en la carpeta de APPS de la
microSD de la consola para luego poder ejecutarlo desde la propia
Anbernic. Una vez ejecutado, podemos ver la ip de la consola en la
configuración del sistema y acceder por ssh.
</p>

<p>
A falta de probar otros sistemas operativos disponibles como Knulli,
de momento estoy muy contento con el sistema que trae de serie. Sólo
he encontrado problemas al intentar conectar mandos por Bluetooth o
stremear con Moonlight, pero por lo demás funciona perfecto.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-consola,.html">consola,</a> <a href="https://www.finaprosadigital.com/tag-gnu/linux.html">GNU/Linux</a> </div>]]></description>
  <category><![CDATA[consola,]]></category>
  <category><![CDATA[GNU/Linux]]></category>
  <link>https://www.finaprosadigital.com/2025-03-01-anbernic-rg40xxh.html</link>
  <guid>https://www.finaprosadigital.com/2025-03-01-anbernic-rg40xxh.html</guid>
  <pubDate>Sat, 01 Mar 2025 17:59:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Calendario para la org-agenda]]></title>
  <description><![CDATA[
<p>
La agenda del org-mode de Emacs muestra por defecto una lista diaria,
semanal o mensual de las citas o tareas que tengamos en nuestro
archivo de agenda. Sin embargo no tiene una vista tipo calendario por
defecto. Para ello se puede usar el paquete <code>calfw-org</code>, disponible en
MELPA.
</p>

<p>
Después de instalarlo sólo hay que cargarlo con <code>(require 'calfw-org)</code>
y ejecutar la orden <code>M-x cfw:open-org-calendar</code> para ver nuestra
agenda en formato calendario.
</p>

<p>
Además, aprovechando que el x270 que tengo tiene pantalla táctil he
decidido probar a asignarle esta orden a un toque de la pantalla para
que aparezca la agenda en modo calendario.
</p>

<p>
Para la asignación en vez de código he usado Embark. Una vez abierto
el menú de Emacs con <code>M-x</code>, y estando sobre la orden
<code>cfw:open-org-calendar</code>, invoco Embark con <code>C-.</code> y luego pulso <code>g</code>
para asignar un atajo de teclado global. Después pulso la pantalla y
ya tengo configurado todo para poder ver mi agenda al toque.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-org-mode,.html">org-mode,</a> <a href="https://www.finaprosadigital.com/tag-org-agenda.html">org-agenda</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[org-mode,]]></category>
  <category><![CDATA[org-agenda]]></category>
  <link>https://www.finaprosadigital.com/2025-02-02-calendario-para-la-org-agenda.html</link>
  <guid>https://www.finaprosadigital.com/2025-02-02-calendario-para-la-org-agenda.html</guid>
  <pubDate>Sun, 02 Feb 2025 19:20:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[2FA en i3wm]]></title>
  <description><![CDATA[
<p>
En la entrada <a href="http://www.finaprosadigital.com/publish/blog/2024-03-11-2fa-en-eshell.html">2FA en eshell</a> expliqué cómo configurar la identificación
en dos pasos en eshell, asignándole una tecla que podemos pulsar
estando en Emacs para copiar el codigo al portapapeles.
</p>

<p>
Sin embargo, no funciona si no estamos dentro de Emacs. Para que
funcione globalmente usando el gestor de ventanas i3 windows manager,
podemos añadir la siguiente línea al archivo config situado
normalmente en <code>~/.config/i3/config</code>:
</p>

<p>
<code>bindsym XF86AudioMicMute exec emacsclient --eval "(eshell2fa)"</code>
</p>

<p>
He usado un atajo de teclado un poco raro, pero es que el Thinkpad
X230 que uso tiene un botón de fácil acceso de silenciar el micrófono
que nunca uso, y me viene perfecto para tener el 2FA a mano. Por
supuesto se puede cambiar por cualquier otra tecla.
</p>

<p>
Con esto ya podemos tener acceso al código 2FA cómodamente pulsando un botón.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-i3,.html">i3,</a> <a href="https://www.finaprosadigital.com/tag-2fa,.html">2FA,</a> <a href="https://www.finaprosadigital.com/tag-emacs.html">Emacs</a> </div>]]></description>
  <category><![CDATA[i3,]]></category>
  <category><![CDATA[2FA,]]></category>
  <category><![CDATA[Emacs]]></category>
  <link>https://www.finaprosadigital.com/2025-01-01-2fa-en-i3wm.html</link>
  <guid>https://www.finaprosadigital.com/2025-01-01-2fa-en-i3wm.html</guid>
  <pubDate>Wed, 01 Jan 2025 12:36:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Programación del ESP8266 D1 R2 de WeMos]]></title>
  <description><![CDATA[
<p>
El D1 R2 es una placa compatible con Arduino de bajo coste que incluye Wi-Fi. Se puede programar usando el IDE de Arduino añadiendo las librerías del chip ESP8266 y seleccionando como placa la LOLIN(Wemos) D1 R2. Para ello previamente hay que ir a la pestaña de "Archivo &gt; Preferencias" del IDE e introducir la siguiente URL en el gestor de tarjetas adicionales: "<a href="http://arduino.esp8266.com/stable/package_esp8266com_index.json">http://arduino.esp8266.com/stable/package_esp8266com_index.json</a>".
</p>

<p>
Una vez hecho esto, cuando se hayan descargado las librerías, nos saldrá un submenú que contiene las placas de la familia ESP8266 en la pestaña de "Herramientas &gt; Placa" del IDE. Ahí ya podemos seleccionar la placa D1 R2.
</p>

<p>
Con todo esto configurado, ya se puede programar como si fuera cualquier otra placa de Arduino.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-arduino,.html">Arduino,</a> <a href="https://www.finaprosadigital.com/tag-esp8266,.html">ESP8266,</a> <a href="https://www.finaprosadigital.com/tag-d1r2.html">D1R2</a> </div>]]></description>
  <category><![CDATA[Arduino,]]></category>
  <category><![CDATA[ESP8266,]]></category>
  <category><![CDATA[D1R2]]></category>
  <link>https://www.finaprosadigital.com/2024-12-01-programaci%C3%B3n-del-esp8266-d1-r2-de-wemos.html</link>
  <guid>https://www.finaprosadigital.com/2024-12-01-programaci%C3%B3n-del-esp8266-d1-r2-de-wemos.html</guid>
  <pubDate>Sun, 01 Dec 2024 19:27:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[GNU Screen]]></title>
  <description><![CDATA[
<p>
Normalmente uso Emacs para gestionar las diferentes sesiones de
terminal que tengo abiertas, pero a veces también uso un emulador de
terminal fuera de Emacs.
</p>

<p>
Como echaba en falta poder gestionar distintas terminales sin tener
que estar abriendo y cerrando un montón de ventanas, estuve
aprendiendo lo básico de GNU Screen, un multiplexor de terminales.
</p>

<p>
En Debian se puede instalar desde los repositorios fácilmente con un
<code>sudo apt install screen</code>. Una vez instalado, se puede iniciar con la
orden <code>screen</code>, y nos saldrá un mensaje de bienvenida que se puede
saltar pulsando intro.
</p>

<p>
La forma básica de interactuar con Screen es pulsando <code>Control + a</code>
y después la orden correspondiente. Para ver todos los atajos de
teclado se puede pulsar <code>Control + a + ?</code>.
</p>

<p>
La interfaz de Screen es muy minimalista por defecto, tanto que de
hecho es difícil saber si estás o no dentro de Screen. Para salir del
programa basta con escribir <code>exit</code> y nos saldrá un mensaje
informándonos que la sesión de Screen ha terminado.
</p>

<p>
Dentro de Screen podemos crear terminales con <code>Control + a + c</code>,
cerrarlos con <code>Control + a + k</code> o cambiar entre terminales con
<code>Control + a + n</code> o <code>Control + a + p</code>.
</p>

<p>
Además de este uso básico, también se pueden crear distintas ventanas
dentro de una misma terminal, o crear un archivo de configuración que
ejecute scripts o configure las teclas de configuración de Screen.
</p>

<p>
Por ejemplo, para cambiar <code>Control + a</code> por <code>Control + t</code> como tecla
principal de Screen podemos incluir la siguiente línea en un archivo
llamado <code>.screenrc</code> en nuestro directorio personal:
</p>

<p>
<code>escape ^Tt</code>
</p>

<p>
En <code>/etc/screenrc</code> si estamos en Debian podemos encontrar un archivo
de configuración base para Screen para no empezar la configuración de
cero.
</p>

<p>
Con este uso básico de un multiplexor es mucho más fácil trabajar con distintas
terminales de forma cómoda y rápida.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-gnu/linux.html">GNU/Linux</a> </div>]]></description>
  <category><![CDATA[GNU/Linux]]></category>
  <link>https://www.finaprosadigital.com/2024-10-28-gnu-screen.html</link>
  <guid>https://www.finaprosadigital.com/2024-10-28-gnu-screen.html</guid>
  <pubDate>Mon, 28 Oct 2024 23:23:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Tablas en org-mode]]></title>
  <description><![CDATA[
<p>
En el modo Org de Emacs se pueden hacer muchísimas cosas, y una de
ellas es la creación de tablas. Sin embargo, al exportarlas, por
defecto se omiten las separaciones verticales entre columnas, según
el manual por claridad visual.
</p>

<p>
En mi caso prefiero tener separación vertical entre cada columna, así
que miré el manual para ver cómo solucionarlo. Hay que insertar una
fila vacía con el carácter de control <code>/</code> y luego un carácter menor
que seguido de uno mayor que <code>&lt;&gt;</code> en cada columna de la tabla.
</p>

<p>
Ahora al exportar el archivo <code>.org</code> a html o pdf ya tendremos nuestra
tabla correctamente formateada.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">Emacs,</a> <a href="https://www.finaprosadigital.com/tag-org.html">Org</a> <a href="https://www.finaprosadigital.com/tag-mode.html">mode</a> </div>]]></description>
  <category><![CDATA[Emacs,]]></category>
  <category><![CDATA[Org]]></category>
  <category><![CDATA[mode]]></category>
  <link>https://www.finaprosadigital.com/2024-09-08-tablas-en-org-mode.html</link>
  <guid>https://www.finaprosadigital.com/2024-09-08-tablas-en-org-mode.html</guid>
  <pubDate>Sun, 08 Sep 2024 19:21:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[2FA en Eshell]]></title>
  <description><![CDATA[
<p>
Ahora que la universidad pide el código de verificación en dos pasos
hasta para respirar, decidí hacer una función en Eshell que me
facilitara la obtención de dicho código.
</p>

<p>
Tenía una función básica, que no recuerdo dónde la saqué, pero
requería tener un búfer de Eshell en segundo plano para que
funcionara.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">eshell2fa</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    <span style="color: #79a8ff;">"Devuelve el id del 2FA en el portapapeles."</span>
    (<span style="color: #b6a0ff;">with-current-buffer</span> <span style="color: #79a8ff;">"*eshell*"</span>
    (eshell-return-to-prompt)
    (insert <span style="color: #79a8ff;">"id &gt; /dev/kill"</span>)
    (eshell-send-input))
    )
</pre>
</div>
<p>
La línea del <code>insert</code> es la que se encarga de obtener la clave a
través del alias <code>id</code>, que usa <code>oathtool</code> para obtener el
código. Luego se redirige al portapapeles con <code>&gt; /dev/kill</code>.
</p>

<p>
El alias se define de la siguiente forma:
<code>alias id oathtool --counter=30 --totp=SHA1 -d 6 -b "clave-de-2FA"</code>
</p>

<p>
Para mejorarla he añadido una línea que crea el búfer de Eshell si no
ha sido creado anteriormente, con un <code>unless</code>
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">eshell2fa</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    <span style="color: #79a8ff;">"Devuelve el id del 2FA en el portapapeles."</span>
    (<span style="color: #b6a0ff;">unless</span> (gnus-buffer-live-p <span style="color: #79a8ff;">"*eshell*"</span>) (eshell) (switch-to-prev-buffer))
    (<span style="color: #b6a0ff;">with-current-buffer</span> <span style="color: #79a8ff;">"*eshell*"</span>
    (eshell-return-to-prompt)
    (insert <span style="color: #79a8ff;">"id &gt; /dev/kill"</span>)
    (eshell-send-input))
    )
</pre>
</div>

<p>
Y luego sólo queda asignarla (por ejemplo a <code>f12</code>) para poder tener el
código pulsando un botón.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(global-set-key (kbd <span style="color: #79a8ff;">"&lt;f12&gt;"</span>) 'eshell2fa)
</pre>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-eshell,.html">eshell,</a> <a href="https://www.finaprosadigital.com/tag-2fa.html">2FA</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[eshell,]]></category>
  <category><![CDATA[2FA]]></category>
  <link>https://www.finaprosadigital.com/2024-03-11-2fa-en-eshell.html</link>
  <guid>https://www.finaprosadigital.com/2024-03-11-2fa-en-eshell.html</guid>
  <pubDate>Mon, 11 Mar 2024 15:03:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[VHDL en Emacs]]></title>
  <description><![CDATA[
<p>
Emacs tiene un modo para programar en VHDL sin necesidad de instalar
paquetes externos, pero como además quería tener un corrector de
sintaxis, estuve mirando algunas soluciones.
</p>

<p>
Decidí instalar <a href="https://www.flycheck.org/">Flycheck</a>, y lo configuré según la web de forma muy
sencilla. Lo que más me costó fue dar con el motor para comprobar la
sintaxis, pero al final lo único que hay que instalar es <a href="https://github.com/ghdl/ghdl">ghdl</a> (en
Debian viene en los repositorios). Una vez instalado y activado el
modo con <code>M-x flycheck-mode</code>, seleccioné el motor de sintaxis en un
búfer con el modo VHDL pulsando <code>C-c ! v</code>.
</p>

<p>
Por último me instalé el paquete <a href="https://github.com/nex3/perspective-el">Perspective</a> para poder tener todo lo
relacionado con VHDL en un espacio de trabajo aparte, y que no se
mezcle con el resto de mis búferes de Emacs.
</p>

<p>
En menos de 5 minutos ya tenía todo funcionando, y así evito tener que
usar el horrible editor de texto de ISE, el entorno propietario para
programar FPGAs de Xilinx.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-vhdl.html">vhdl</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[vhdl]]></category>
  <link>https://www.finaprosadigital.com/2024-02-17-vhdl-en-emacs.html</link>
  <guid>https://www.finaprosadigital.com/2024-02-17-vhdl-en-emacs.html</guid>
  <pubDate>Sat, 17 Feb 2024 00:04:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Temporizador]]></title>
  <description><![CDATA[
<p>
Ayer estaba en el césped de la Escuela en un tiempo muerto entre
clases y se me ocurrió practicar un poco con el cubo 3x3 que tengo (un
Yuxin Little Magic magnético, si no recuerdo mal), cronometrando mis tiempos.
</p>

<p>
Pero desde hace un tiempo no consigo que me funcione la red de la
universidad, y, como hace relativamente poco que me instalé Debian 12
en mi Thinkpad X230, no tenía ningún programa para cronometrar el
tiempo que tardo en hacer el cubo.
</p>

<p>
Miré el manual de Elisp, pero los temporizadores que hay sólo llegan a
precisión de segundos, y yo necesitaba hasta las centésimas de
segundo. Recordé que en informática de cuarto dimos temporizadores
POSIX, pero no tenía ganas de ponerme a hacer un programa en C y tener
que mirarme el estándar sólo para hacer un pequeño programa.
</p>

<p>
Me acordé de que existe un programa en GNU/Linux que se llama <code>time</code>,
que cronometra el tiempo que tarda en ejecutarse un comando. Estuve
mirando entre los programas en C que tenía de informática hechos por
el profesor, y había uno que se llamaba <code>pierde_tiempo.c</code>.
</p>

<p>
El programa es tan sólo un bucle infinito, y sirve para demostrar el
funcionamiento de los hilos y los procesos en C + POSIX. Pero lo
interesante es que al combinarlo con time puedo saber con precisión
de milésimas de segundo cuánto tiempo ha estado ejecutándose el
programa hasta que lo pare con <code>C-c</code>.
</p>

<p>
Así, con una sola línea en la terminal, improvisé un cronómetro casero
para poder cronometrarme con una precisión de centésimas de
segundo. Añadí una macro de Emacs para poder pausar el programa con
F12 y no perder tiempo pulsando <code>C-c</code>, y ya tenía todo listo, y sin
usar internet en ningún momento.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-rubik,.html">rubik,</a> <a href="https://www.finaprosadigital.com/tag-gnu/linux.html">GNU/Linux</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[rubik,]]></category>
  <category><![CDATA[GNU/Linux]]></category>
  <link>https://www.finaprosadigital.com/2024-02-06-temporizador.html</link>
  <guid>https://www.finaprosadigital.com/2024-02-06-temporizador.html</guid>
  <pubDate>Tue, 06 Feb 2024 20:08:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Tetris]]></title>
  <description><![CDATA[
<div id="outline-container-org8f85dea" class="outline-2">
<h2 id="org8f85dea">Introducción</h2>
<div class="outline-text-2" id="text-org8f85dea">
<p>
Últimamente le he echado muchas horas al Tetris 99 en la Switch, y,
aunque parezca mentira, las distintas versiones del Tetris que existen
en el mundo pueden llegar a ser muy diferentes. Hay incluso una serie
de <a href="https://tetris.wiki/Tetris_Guideline">normas estándar</a> para poder homogeneizar los distintos juegos.
</p>

<p>
En Emacs hay una implementación del Tetris (<code>tetris.el</code>), pero le
falta la mecánica de reservar una pieza y algunos pequeños detalles
para que se parezca más al resto de versiones.
</p>
</div>
</div>
<div id="outline-container-org94fe6dd" class="outline-2">
<h2 id="org94fe6dd">Configurando <code>tetris.el</code></h2>
<div class="outline-text-2" id="text-org94fe6dd">
<p>
En primer lugar, tocando opciones de <code>tetris.el</code> se puede hacer que la
generación de piezas sea tal que nunca se puedan repetir las piezas
más de dos veces (se van creando bolsas de 7 piezas).
</p>

<p>
Desactivando la opción de permitir repeticiones de piezas tenemos ya
un generador de piezas aleatorio estándar.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #b6a0ff;">setq</span> tetris-allow-repetitions nil)
</pre>
</div>

<p>
Los colores de las piezas también siguen un estándar.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #989898;">;;</span><span style="color: #989898;">Shape 1 (O) Yellow</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 2 (L) Orange</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 3 (J) Dark blue</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 4 (S) Green</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 5 (Z) Red</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 6 (T) Magenta</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 7 (I) Light blue</span>

  (<span style="color: #b6a0ff;">setq</span> tetris-x-colors [[1 1 0]
   [1 0.27 0]
   [0 0 0.55]
   [1 0 0]
   [0 1 0]
   [1 0 1]
   [0 0.86 0.9]]
  )
</pre>
</div>

<p>
Con estos dos cambios podemos usar el <code>tetris.el</code> de Emacs y jugar con
los colores estándar y la generación de piezas, pero queda por
implementar la funcionalidad de reservar piezas.
</p>
</div>
</div>
<div id="outline-container-orga63f911" class="outline-2">
<h2 id="orga63f911">Reservar piezas</h2>
<div class="outline-text-2" id="text-orga63f911">
<p>
Como quiero aprender Emacs Lisp y poder jugar al Tetris en Emacs con
la reserva de piezas, he improvisado sobre la marcha una solución
chapucera y rápida para poder jugar a mi manera.
</p>
</div>
<div id="outline-container-orgc5e9f61" class="outline-3">
<h3 id="orgc5e9f61">Funciones modificadas</h3>
<div class="outline-text-3" id="text-orgc5e9f61">
<p>
Lamentablemente ni la librería que usa <code>tetris.el</code> (<code>gamegrid.el</code>), ni
el propio <code>tetris.el</code> están bien documentados. Así que me miré el
código por encima, y con ayuda de una explicación de la librería que
encontré en <a href="https://vannilla.org/write/1533394929/article.html">internet</a>, me puse a toquetear cosas hasta conseguir lo que
quería.
</p>

<p>
En primer lugar, estuve probando funciones que cogí del código y las
fui probando y modificando en el búfer de <b>Scratch</b> para que fueran
haciendo lo que quería.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-hold-shape</span> ()
  <span style="color: #9ac8e0;">"Con esta funci&#243;n se puede dibujar una pieza cualquiera por la cara en el tetris. Pones setq tetris-shape al n&#250;mero de la pieza que quieras y listo."</span>
  (<span style="color: #b6a0ff;">interactive</span>)
  (<span style="color: #b6a0ff;">setq</span> tetris-next-holded-piece tetris-shape)
  (<span style="color: #b6a0ff;">setq</span> tetris-shape tetris-holded-piece)
  (<span style="color: #b6a0ff;">setq</span> tetris-rot 0)
  (<span style="color: #b6a0ff;">setq</span> tetris-next-shape (<span style="color: #b6a0ff;">if</span> tetris-allow-repetitions
                              (random 7)
                            (tetris--seven-bag)))
  (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (/ (- tetris-width (tetris-shape-width)) 2))
  (<span style="color: #b6a0ff;">setq</span> tetris-pos-y 0)
  (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
      (tetris-end-game)
    (tetris-draw-shape)
    (tetris-draw-next-shape)
    (tetris-update-score))
  (<span style="color: #b6a0ff;">setq</span> tetris-holded-piece tetris-next-holded-piece))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-erase-shape</span> ()
  <span style="color: #9ac8e0;">"Con esta funci&#243;n se puede eliminar una pieza cualquiera del juego."</span>
  (<span style="color: #b6a0ff;">interactive</span>)
  (<span style="color: #b6a0ff;">dotimes</span> (i 4)
    (<span style="color: #b6a0ff;">let</span> ((c (tetris-get-shape-cell i)))
      (gamegrid-set-cell (+ tetris-top-left-x
                            tetris-pos-x
                            (aref c 0))
                         (+ tetris-top-left-y
                            tetris-pos-y
                            (aref c 1))
                         tetris-blank))))
(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-reserva</span>()
  <span style="color: #9ac8e0;">"Funci&#243;n para implementar la reserva de piezas en el tetris."</span>
  (<span style="color: #b6a0ff;">interactive</span>)
  (<span style="color: #b6a0ff;">progn</span>
    (tetris-erase-shape)
    (tetris-hold-shape)
    (tetris-update-score)
    )
  )

(global-set-key (kbd <span style="color: #79a8ff;">"C-&#241;"</span>) 'tetris-reserva)
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 0 (O) Yellow</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 1 (L) Orange</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 2 (J) Dark Blue</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 3 (S) Green</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 4 (Z) Red</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 5 (T) Magenta</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">Shape 6 (I) Light Blue</span>

</pre>
</div>

<p>
Estuve probando cómo se ponen y se quitan piezas y luego hice una
función más simple que hacía todo lo necesario para implementar la
mecánica de reserva.
</p>
</div>
</div>
<div id="outline-container-org7107d60" class="outline-3">
<h3 id="org7107d60">Modificación del archivo <code>tetris.el</code></h3>
<div class="outline-text-3" id="text-org7107d60">
<p>
Además, cogí el código original, y lo copié en otro archivo,
<code>mitetris.el</code>, y sobre este archivo definí algunas nuevas variables y
creé la "previsualización" en ASCII de la pieza en reserva, ya que era
lo más rápido.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><span style="color: #989898;">;;; </span><span style="color: #989898;">&#7;etris.el ---&#7;implementation of Tetris for Emacs  -*- lexical-binding:t -*-</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">Copyright (C) 1997, 2001-2024 Free Software Foundation, Inc.</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">Author: Glynn Clements <a href="mailto:glynn%40sensei.co.uk">&lt;glynn@sensei.co.uk&gt;</a></span>
<span style="color: #989898;">;; </span><span style="color: #989898;">Old-Version: 2.01</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">Created: 1997-08-13</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">Keywords: games</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">This file is part of GNU Emacs.</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">GNU Emacs is free software: you can redistribute it and/or modify</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">it under the terms of the GNU General Public License as published by</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">the Free Software Foundation, either version 3 of the License, or</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">(at your option) any later version.</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">GNU Emacs is distributed in the hope that it will be useful,</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">GNU General Public License for more details.</span>

<span style="color: #989898;">;; </span><span style="color: #989898;">You should have received a copy of the GNU General Public License</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">along with GNU Emacs.  If not, see <a href="https://www.gnu.org/licenses/">&lt;https://www.gnu.org/licenses/&gt;</a>.</span>

<span style="color: #989898;">;;; </span><span style="color: #989898;">Commentary:</span>

<span style="color: #989898;">;;; </span><span style="color: #989898;">Code:</span>

(<span style="color: #b6a0ff;">eval-when-compile</span> (<span style="color: #b6a0ff;">require</span> '<span style="color: #00bcff;">cl-lib</span>))

(<span style="color: #b6a0ff;">require</span> '<span style="color: #00bcff;">gamegrid</span>)

<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;; customization variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defgroup</span> <span style="color: #6ae4b9;">tetris</span> nil
  <span style="color: #9ac8e0;">"Play a game of Tetris."</span>
  <span style="color: #f78fe7;">:prefix</span> <span style="color: #79a8ff;">"tetris-"</span>
  <span style="color: #f78fe7;">:group</span> 'games)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-use-glyphs</span> t
  <span style="color: #9ac8e0;">"Non-nil means use glyphs when available."</span>
  <span style="color: #f78fe7;">:type</span> 'boolean)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-use-color</span> t
  <span style="color: #9ac8e0;">"Non-nil means use color when available."</span>
  <span style="color: #f78fe7;">:type</span> 'boolean)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-draw-border-with-glyphs</span> t
  <span style="color: #9ac8e0;">"Non-nil means draw a border even when using glyphs."</span>
  <span style="color: #f78fe7;">:type</span> 'boolean)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-default-tick-period</span> 0.3
  <span style="color: #9ac8e0;">"The default time taken for a shape to drop one row."</span>
  <span style="color: #f78fe7;">:type</span> 'number)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-update-speed-function</span>
  'tetris-default-update-speed-function
  <span style="color: #9ac8e0;">"Function run whenever the Tetris score changes.</span>
<span style="color: #9ac8e0;">Called with two arguments: (SHAPES ROWS)</span>
<span style="color: #9ac8e0;">SHAPES is the number of shapes which have been dropped.</span>
<span style="color: #9ac8e0;">ROWS is the number of rows which have been completed.</span>

<span style="color: #9ac8e0;">If the return value is a number, it is used as the timer period."</span>
  <span style="color: #f78fe7;">:type</span> 'function)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-mode-hook</span> nil
  <span style="color: #9ac8e0;">"Hook run upon starting Tetris."</span>
  <span style="color: #f78fe7;">:type</span> 'hook)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-tty-colors</span>
  [<span style="color: #79a8ff;">"blue"</span> <span style="color: #79a8ff;">"white"</span> <span style="color: #79a8ff;">"yellow"</span> <span style="color: #79a8ff;">"magenta"</span> <span style="color: #79a8ff;">"cyan"</span> <span style="color: #79a8ff;">"green"</span> <span style="color: #79a8ff;">"red"</span>]
  <span style="color: #9ac8e0;">"Vector of colors of the various shapes in text mode."</span>
  <span style="color: #f78fe7;">:type</span> '(vector (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 1"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 2"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 3"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 4"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 5"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 6"</span>)
                 (color <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 7"</span>)))

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-x-colors</span>
  [[0 0 1] [0.7 0 1] [1 1 0] [1 0 1] [0 1 1] [0 1 0] [1 0 0]]
  <span style="color: #9ac8e0;">"Vector of RGB colors of the various shapes."</span>
  <span style="color: #f78fe7;">:type</span> '(vector (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 1"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 2"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 3"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 4"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 5"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 6"</span> number number number)
                 (vector <span style="color: #f78fe7;">:tag</span> <span style="color: #79a8ff;">"Shape 7"</span> number number number)))

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-buffer-name</span> <span style="color: #79a8ff;">"*Tetris*"</span>
  <span style="color: #9ac8e0;">"Name used for Tetris buffer."</span>
  <span style="color: #f78fe7;">:type</span> 'string)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-buffer-width</span> 30
  <span style="color: #9ac8e0;">"Width of used portion of buffer."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-buffer-height</span> 22
  <span style="color: #9ac8e0;">"Height of used portion of buffer."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-width</span> 10
  <span style="color: #9ac8e0;">"Width of playing area."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-height</span> 20
  <span style="color: #9ac8e0;">"Height of playing area."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-top-left-x</span> 3
  <span style="color: #9ac8e0;">"X position of top left of playing area."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-top-left-y</span> 1
  <span style="color: #9ac8e0;">"Y position of top left of playing area."</span>
  <span style="color: #f78fe7;">:type</span> 'natnum)

(<span style="color: #b6a0ff;">defcustom</span> <span style="color: #00d3d0;">tetris-allow-repetitions</span> t
  <span style="color: #9ac8e0;">"If non-nil, use a random selection for each shape.</span>
<span style="color: #9ac8e0;">If nil, put the shapes into a bag and select without putting</span>
<span style="color: #9ac8e0;">back (until empty, when the bag is repopulated."</span>
  <span style="color: #f78fe7;">:type</span> 'boolean
  <span style="color: #f78fe7;">:version</span> <span style="color: #79a8ff;">"29.1"</span>)

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-next-x</span> (+ (* 2 tetris-top-left-x) tetris-width)
  <span style="color: #9ac8e0;">"X position of next shape."</span>)

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-next-y</span> tetris-top-left-y
  <span style="color: #9ac8e0;">"Y position of next shape."</span>)

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-score-x</span> tetris-next-x
  <span style="color: #9ac8e0;">"X position of score."</span>)

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-score-y</span> (+ tetris-next-y 6)
  <span style="color: #9ac8e0;">"Y position of score."</span>)

<span style="color: #989898;">;; </span><span style="color: #989898;">It is not safe to put this in /tmp.</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">Someone could make a symlink in /tmp</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">pointing to a file you don't want to clobber.</span>
(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-score-file</span> <span style="color: #79a8ff;">"tetris-scores"</span>
<span style="color: #989898;">;; </span><span style="color: #989898;">anybody with a well-connected server want to host this?</span>
<span style="color: #989898;">;</span><span style="color: #989898;">(defvar tetris-score-file "/anonymous@ftp.pgt.com:/pub/cgw/tetris-scores"</span>
  <span style="color: #9ac8e0;">"File for holding high scores."</span>)

<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;; display options ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-blank-options</span>
  '(((glyph colorize)
     (t ?\040))
    ((color-x color-x)
     (mono-x grid-x)
     (color-tty color-tty))
    (((glyph color-x) [0 0 0])
     (color-tty <span style="color: #79a8ff;">"black"</span>))))

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-cell-options</span>
  '(((glyph colorize)
     (emacs-tty ?O)
     (t ?\040))
    ((color-x color-x)
     (mono-x mono-x)
     (color-tty color-tty)
     (mono-tty mono-tty))
    <span style="color: #989898;">;; </span><span style="color: #989898;">color information is taken from tetris-x-colors and tetris-tty-colors</span>
    ))

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-border-options</span>
  '(((glyph colorize)
     (t ?\+))
    ((color-x color-x)
     (mono-x grid-x)
     (color-tty color-tty))
    (((glyph color-x) [0.5 0.5 0.5])
     (color-tty <span style="color: #79a8ff;">"white"</span>))))

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetris-space-options</span>
  '(((t ?\040))
    nil
    nil))

<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;; constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-shapes</span>
  [[[[0  0] [1  0] [0  1] [1  1]]]

   [[[0  0] [1  0] [2  0] [2  1]]
    [[1 -1] [1  0] [1  1] [0  1]]
    [[0 -1] [0  0] [1  0] [2  0]]
    [[1 -1] [2 -1] [1  0] [1  1]]]

   [[[0  0] [1  0] [2  0] [0  1]]
    [[0 -1] [1 -1] [1  0] [1  1]]
    [[2 -1] [0  0] [1  0] [2  0]]
    [[1 -1] [1  0] [1  1] [2  1]]]

   [[[0  0] [1  0] [1  1] [2  1]]
    [[1  0] [0  1] [1  1] [0  2]]]

   [[[1  0] [2  0] [0  1] [1  1]]
    [[0  0] [0  1] [1  1] [1  2]]]

   [[[1  0] [0  1] [1  1] [2  1]]
    [[1  0] [1  1] [2  1] [1  2]]
    [[0  1] [1  1] [2  1] [1  2]]
    [[1  0] [0  1] [1  1] [1  2]]]

   [[[0  0] [1  0] [2  0] [3  0]]
    [[1 -1] [1  0] [1  1] [1  2]]]]
  <span style="color: #9ac8e0;">"Each shape is described by a vector that contains the coordinates of</span>
<span style="color: #9ac8e0;">each one of its four blocks."</span>)

<span style="color: #989898;">;;</span><span style="color: #989898;">the scoring rules were taken from "xtetris".  Blocks score differently</span>
<span style="color: #989898;">;;</span><span style="color: #989898;">depending on their rotation</span>

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-shape-scores</span>
  [[6] [6 7 6 7] [6 7 6 7] [6 7] [6 7] [5 5 6 5] [5 8]] )

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-shape-dimensions</span>
  [[2 2] [3 2] [3 2] [3 2] [3 2] [3 2] [4 1]])

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-blank</span> 7)

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-border</span> 8)

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris-space</span> 9)

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-default-update-speed-function</span> (_shapes rows)
  (/ 20.0 (+ 50.0 rows)))

<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;; variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-shape</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-rot</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-next-shape</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-n-shapes</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-n-rows</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-score</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-pos-x</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-pos-y</span> 0)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris-paused</span> nil)
(<span style="color: #b6a0ff;">defvar-local</span> <span style="color: #00d3d0;">tetris--bag</span> nil)

<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;; keymaps ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defvar-keymap</span> tetris-mode-map
  <span style="color: #f78fe7;">:doc</span> <span style="color: #9ac8e0;">"Keymap for Tetris games."</span>
  <span style="color: #f78fe7;">:name</span> 'tetris-mode-map
  <span style="color: #79a8ff;">"n"</span>       #'tetris-start-game
  <span style="color: #79a8ff;">"q"</span>       #'tetris-end-game
  <span style="color: #79a8ff;">"p"</span>       #'tetris-pause-game

  <span style="color: #79a8ff;">"SPC"</span>     #'tetris-move-bottom
  <span style="color: #79a8ff;">"&lt;left&gt;"</span>  #'tetris-move-left
  <span style="color: #79a8ff;">"&lt;right&gt;"</span> #'tetris-move-right
  <span style="color: #79a8ff;">"&lt;up&gt;"</span>    #'tetris-rotate-prev
  <span style="color: #79a8ff;">"&lt;down&gt;"</span>  #'tetris-move-down)

(<span style="color: #b6a0ff;">defvar-keymap</span> tetris-null-map
  <span style="color: #f78fe7;">:doc</span> <span style="color: #9ac8e0;">"Keymap for finished Tetris games."</span>
  <span style="color: #f78fe7;">:name</span> 'tetris-null-map
  <span style="color: #79a8ff;">"n"</span>       #'tetris-start-game
  <span style="color: #79a8ff;">"q"</span>       #'quit-window)

(<span style="color: #b6a0ff;">defconst</span> <span style="color: #00d3d0;">tetris--menu-def</span>
  '(<span style="color: #79a8ff;">"Tetris"</span>
    [<span style="color: #79a8ff;">"Start new game"</span>    tetris-start-game
     <span style="color: #f78fe7;">:help</span> <span style="color: #79a8ff;">"Start a new Tetris game"</span>]
    [<span style="color: #79a8ff;">"End game"</span>          tetris-end-game
     <span style="color: #f78fe7;">:active</span> (tetris-active-p)
     <span style="color: #f78fe7;">:help</span> <span style="color: #79a8ff;">"End the current Tetris game"</span>]
    <span style="color: #989898;">;; </span><span style="color: #989898;">FIXME: Pause and resume from the menu currently doesn't work</span>
    <span style="color: #989898;">;;        </span><span style="color: #989898;">very well and is therefore disabled.  The game continues</span>
    <span style="color: #989898;">;;        </span><span style="color: #989898;">running while navigating the menu.  See also</span>
    <span style="color: #989898;">;;        </span><span style="color: #989898;">`</span><span style="color: #00bcff;">snake--menu-def</span><span style="color: #989898;">' which has the same problem.</span>
    <span style="color: #989898;">;; </span><span style="color: #989898;">["Pause"             tetris-pause-game</span>
    <span style="color: #989898;">;;  </span><span style="color: #989898;">:active (and (tetris-active-p) (not tetris-paused))</span>
    <span style="color: #989898;">;;  </span><span style="color: #989898;">:help "Pause running Tetris game"]</span>
    <span style="color: #989898;">;; </span><span style="color: #989898;">["Resume"            tetris-pause-game</span>
    <span style="color: #989898;">;;  </span><span style="color: #989898;">:active (and (tetris-active-p) tetris-paused)</span>
    <span style="color: #989898;">;;  </span><span style="color: #989898;">:help "Resume paused Tetris game"]</span>
    )
  <span style="color: #9ac8e0;">"Menu for `</span><span style="color: #00bcff;">tetris</span><span style="color: #9ac8e0;">'.  Used to initialize menus."</span>)

(<span style="color: #b6a0ff;">easy-menu-define</span>
  tetris-mode-menu tetris-mode-map
  <span style="color: #9ac8e0;">"Menu for running Tetris games."</span>
  tetris--menu-def)

(<span style="color: #b6a0ff;">easy-menu-define</span>
  tetris-null-menu tetris-null-map
  <span style="color: #9ac8e0;">"Menu for finished Tetris games."</span>
  tetris--menu-def)
(<span style="color: #b6a0ff;">setq</span> tetris-holded-piece 1)
(<span style="color: #b6a0ff;">setq</span> tetris-next-holded-piece 1)
(<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"s"</span>)
<span style="color: #989898;">;; </span><span style="color: #989898;">;;;;;;;;;;;;;;;; game functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-display-options</span> ()
  (<span style="color: #b6a0ff;">let</span> ((options (make-vector 256 nil)))
    (<span style="color: #b6a0ff;">dotimes</span> (c 256)
      (aset options c
            (<span style="color: #b6a0ff;">cond</span> ((= c tetris-blank)
                   tetris-blank-options)
                  ((<span style="color: #b6a0ff;">and</span> (&gt;= c 0) (&lt;= c 6))
                   (append
                    tetris-cell-options
                    `((((glyph color-x) ,(aref tetris-x-colors c))
                       (color-tty ,(aref tetris-tty-colors c))
                       (t nil)))))
                  ((= c tetris-border)
                   tetris-border-options)
                  ((= c tetris-space)
                   tetris-space-options)
                  (t
                   '(nil nil nil)))))
    options))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-get-tick-period</span> ()
  (<span style="color: #b6a0ff;">let</span> ((period (apply tetris-update-speed-function
                       tetris-n-shapes
                       tetris-n-rows nil)))
    (<span style="color: #b6a0ff;">and</span> (numberp period) period)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-get-shape-cell</span> (block)
  (aref (aref  (aref tetris-shapes
                     tetris-shape) <span style="color: #fec43f;">tetris-rot)</span>
        block))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-shape-width</span> ()
  (aref (aref tetris-shape-dimensions tetris-shape) 0))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-shape-rotations</span> ()
  (length (aref tetris-shapes tetris-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-draw-score</span> ()
  (<span style="color: #b6a0ff;">let</span> ((strings (vector (format <span style="color: #79a8ff;">"Shapes: %05d"</span> tetris-n-shapes)
                         (format <span style="color: #79a8ff;">"Rows:   %05d"</span> tetris-n-rows)
                         (format <span style="color: #79a8ff;">"Score:  %05d"</span> tetris-score))))
    (<span style="color: #b6a0ff;">dotimes</span> (y 3)
      (<span style="color: #b6a0ff;">let*</span> ((string (aref strings y))
             (len (length string)))
        (<span style="color: #b6a0ff;">dotimes</span> (x len)
          (gamegrid-set-cell (+ tetris-score-x x)
                             (+ tetris-score-y y)
                             (aref string x)))))))
(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-draw-hold</span> ()
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 0)
      (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"O"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 1)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"J"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 2)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"L"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 3)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"Z"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 4)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"S"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 5)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"T"</span>)
      )
  (<span style="color: #b6a0ff;">if</span> (eq tetris-holded-piece 6)
          (<span style="color: #b6a0ff;">setq</span> tetris-holded-siguiente <span style="color: #79a8ff;">"I"</span>)
      )

  (<span style="color: #b6a0ff;">let</span> ((strings (vector (format <span style="color: #79a8ff;">"Shapes: %05d"</span> tetris-n-shapes)
                         (format <span style="color: #79a8ff;">"Rows:   %05d"</span> tetris-n-rows)
                         (format <span style="color: #79a8ff;">"Hodl:  %05s"</span> tetris-holded-siguiente))))
    (<span style="color: #b6a0ff;">dotimes</span> (y 3)
      (<span style="color: #b6a0ff;">let*</span> ((string (aref strings y))
             (len (length string)))
        (<span style="color: #b6a0ff;">dotimes</span> (x len)
          (gamegrid-set-cell (+ 15 x)
                             (+ 15 y)
                             (aref string x)))))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-update-score</span> ()
  (tetris-draw-score)
  (tetris-draw-hold)
  (<span style="color: #b6a0ff;">let</span> ((period (tetris-get-tick-period)))
    (<span style="color: #b6a0ff;">if</span> period (gamegrid-set-timer period))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris--shuffle</span> (sequence)
  (<span style="color: #b6a0ff;">cl-loop</span> for i from (length sequence) downto 2
           do (<span style="color: #b6a0ff;">cl-rotatef</span> (elt sequence (random i))
                          (elt sequence (1- i))))
  sequence)

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris--seven-bag</span> ()
  (<span style="color: #b6a0ff;">when</span> (not tetris--bag)
    (<span style="color: #b6a0ff;">setq</span> tetris--bag (tetris--shuffle (list 0 1 2 3 4 5 6))))
  (<span style="color: #b6a0ff;">pop</span> tetris--bag))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-new-shape</span> ()
  (<span style="color: #b6a0ff;">setq</span> tetris-shape tetris-next-shape)
  (<span style="color: #b6a0ff;">setq</span> tetris-rot 0)
  (<span style="color: #b6a0ff;">setq</span> tetris-next-shape (<span style="color: #b6a0ff;">if</span> tetris-allow-repetitions
                              (random 7)
                            (tetris--seven-bag)))
  (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (/ (- tetris-width (tetris-shape-width)) 2))
  (<span style="color: #b6a0ff;">setq</span> tetris-pos-y 0)
  (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
      (tetris-end-game)
    (tetris-draw-shape)
    (tetris-draw-next-shape)
    (tetris-update-score)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-draw-next-shape</span> ()
  (<span style="color: #b6a0ff;">dotimes</span> (x 4)
    (<span style="color: #b6a0ff;">dotimes</span> (y 4)
      (gamegrid-set-cell (+ tetris-next-x x)
                         (+ tetris-next-y y)
                         tetris-blank)))
  (<span style="color: #b6a0ff;">dotimes</span> (i 4)
    (<span style="color: #b6a0ff;">let</span> ((tetris-shape tetris-next-shape)
          (tetris-rot 0))
      (gamegrid-set-cell (+ tetris-next-x
                            (aref (tetris-get-shape-cell i) 0))
                         (+ tetris-next-y
                            (aref (tetris-get-shape-cell i) 1))
                         tetris-shape))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-draw-shape</span> ()
  (<span style="color: #b6a0ff;">dotimes</span> (i 4)
    (<span style="color: #b6a0ff;">let</span> ((c (tetris-get-shape-cell i)))
      (gamegrid-set-cell (+ tetris-top-left-x
                            tetris-pos-x
                            (aref c 0))
                         (+ tetris-top-left-y
                            tetris-pos-y
                            (aref c 1))
                         tetris-shape))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-erase-shape</span> ()
  (<span style="color: #b6a0ff;">interactive</span>)
  (<span style="color: #b6a0ff;">dotimes</span> (i 4)
    (<span style="color: #b6a0ff;">let</span> ((c (tetris-get-shape-cell i)))
      (gamegrid-set-cell (+ tetris-top-left-x
                            tetris-pos-x
                            (aref c 0))
                         (+ tetris-top-left-y
                            tetris-pos-y
                            (aref c 1))
                         tetris-blank))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-test-shape</span> ()
  (<span style="color: #b6a0ff;">let</span> ((hit nil))
    (<span style="color: #b6a0ff;">dotimes</span> (i 4)
      (<span style="color: #b6a0ff;">unless</span> hit
        (<span style="color: #b6a0ff;">setq</span> hit
              (<span style="color: #b6a0ff;">let*</span> ((c (tetris-get-shape-cell i))
                     (xx (+ tetris-pos-x
                            (aref c 0)))
                     (yy (+ tetris-pos-y
                            (aref c 1))))
                (<span style="color: #b6a0ff;">or</span> (&gt;= xx tetris-width)
                    (&gt;= yy tetris-height)
                    (/= (gamegrid-get-cell
                         (+ xx tetris-top-left-x)
                         (+ yy tetris-top-left-y))
                        tetris-blank))))))
    hit))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-full-row</span> (y)
  (<span style="color: #b6a0ff;">let</span> ((full t))
    (<span style="color: #b6a0ff;">dotimes</span> (x tetris-width)
      (<span style="color: #b6a0ff;">if</span> (= (gamegrid-get-cell (+ tetris-top-left-x x)
                                (+ tetris-top-left-y y))
             tetris-blank)
          (<span style="color: #b6a0ff;">setq</span> full nil)))
    full))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-shift-row</span> (y)
  (<span style="color: #b6a0ff;">if</span> (= y 0)
      (<span style="color: #b6a0ff;">dotimes</span> (x tetris-width)
        (gamegrid-set-cell (+ tetris-top-left-x x)
                           (+ tetris-top-left-y y)
                           tetris-blank))
    (<span style="color: #b6a0ff;">dotimes</span> (x tetris-width)
      (<span style="color: #b6a0ff;">let</span> ((c (gamegrid-get-cell (+ tetris-top-left-x x)
                                  (+ tetris-top-left-y y -1))))
        (gamegrid-set-cell (+ tetris-top-left-x x)
                           (+ tetris-top-left-y y)
                           c)))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-shift-down</span> ()
  (<span style="color: #b6a0ff;">dotimes</span> (y0 tetris-height)
    (<span style="color: #b6a0ff;">when</span> (tetris-full-row y0)
      (<span style="color: #b6a0ff;">setq</span> tetris-n-rows (1+ tetris-n-rows))
      (<span style="color: #b6a0ff;">cl-loop</span> for y from y0 downto 0 do
               (tetris-shift-row y)))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-draw-border-p</span> ()
  (<span style="color: #b6a0ff;">or</span> (not (eq gamegrid-display-mode 'glyph))
      tetris-draw-border-with-glyphs))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-init-buffer</span> ()
  (gamegrid-init-buffer tetris-buffer-width
                        tetris-buffer-height
                        tetris-space)
  (<span style="color: #b6a0ff;">let</span> ((buffer-read-only nil))
    (<span style="color: #b6a0ff;">if</span> (tetris-draw-border-p)
        (<span style="color: #b6a0ff;">cl-loop</span> for y from -1 to tetris-height do
                 (<span style="color: #b6a0ff;">cl-loop</span> for x from -1 to tetris-width do
                          (gamegrid-set-cell (+ tetris-top-left-x x)
                                             (+ tetris-top-left-y y)
                                             tetris-border))))
    (<span style="color: #b6a0ff;">dotimes</span> (y tetris-height)
      (<span style="color: #b6a0ff;">dotimes</span> (x tetris-width)
        (gamegrid-set-cell (+ tetris-top-left-x x)
                           (+ tetris-top-left-y y)
                           tetris-blank)))
    (<span style="color: #b6a0ff;">if</span> (tetris-draw-border-p)
        (<span style="color: #b6a0ff;">cl-loop</span> for y from -1 to 4 do
                 (<span style="color: #b6a0ff;">cl-loop</span> for x from -1 to 4 do
                          (gamegrid-set-cell (+ tetris-next-x x)
                                             (+ tetris-next-y y)
                                             tetris-border))))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-reset-game</span> ()
  (gamegrid-kill-timer)
  (tetris-init-buffer)
  (<span style="color: #b6a0ff;">setq</span> tetris-next-shape (random 7))
  (<span style="color: #b6a0ff;">setq</span> tetris-shape    0
        tetris-rot      0
        tetris-pos-x    0
        tetris-pos-y    0
        tetris-n-shapes 0
        tetris-n-rows   0
        tetris-score    0
        tetris-paused   nil)
  (tetris-new-shape))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-shape-done</span> ()
  (tetris-shift-down)
  (<span style="color: #b6a0ff;">setq</span> tetris-n-shapes (1+ tetris-n-shapes))
  (<span style="color: #b6a0ff;">setq</span> tetris-score
        (+ tetris-score
           (aref (aref tetris-shape-scores tetris-shape) tetris-rot)))
  (tetris-update-score)
  (tetris-new-shape))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-update-game</span> (tetris-buffer)
  <span style="color: #9ac8e0;">"Called on each clock tick.</span>
<span style="color: #9ac8e0;">Drops the shape one square, testing for collision."</span>
  (<span style="color: #b6a0ff;">if</span> (<span style="color: #b6a0ff;">and</span> (not tetris-paused)
           (eq (current-buffer) tetris-buffer))
      (<span style="color: #b6a0ff;">let</span> (hit)
        (tetris-erase-shape)
        (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1+ tetris-pos-y))
        (<span style="color: #b6a0ff;">setq</span> hit (tetris-test-shape))
        (<span style="color: #b6a0ff;">if</span> hit
            (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1- tetris-pos-y)))
        (tetris-draw-shape)
        (<span style="color: #b6a0ff;">if</span> hit
            (tetris-shape-done)))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-move-bottom</span> ()
  <span style="color: #9ac8e0;">"Drop the shape to the bottom of the playing area."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
    (<span style="color: #b6a0ff;">let</span> ((hit nil))
      (tetris-erase-shape)
      (<span style="color: #b6a0ff;">while</span> (not hit)
        (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1+ tetris-pos-y))
        (<span style="color: #b6a0ff;">setq</span> hit (tetris-test-shape)))
      (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1- tetris-pos-y))
      (tetris-draw-shape)
      (tetris-shape-done))))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-move-left</span> ()
  <span style="color: #9ac8e0;">"Move the shape one square to the left."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
    (tetris-erase-shape)
    (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (1- tetris-pos-x))
    (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
        (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (1+ tetris-pos-x)))
    (tetris-draw-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-move-right</span> ()
  <span style="color: #9ac8e0;">"Move the shape one square to the right."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
    (tetris-erase-shape)
    (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (1+ tetris-pos-x))
    (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
        (<span style="color: #b6a0ff;">setq</span> tetris-pos-x (1- tetris-pos-x)))
    (tetris-draw-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-move-down</span> ()
  <span style="color: #9ac8e0;">"Move the shape one square to the bottom."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
    (tetris-erase-shape)
    (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1+ tetris-pos-y))
    (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
        (<span style="color: #b6a0ff;">setq</span> tetris-pos-y (1- tetris-pos-y)))
    (tetris-draw-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-rotate-prev</span> ()
  <span style="color: #9ac8e0;">"Rotate the shape clockwise."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
      (tetris-erase-shape)
      (<span style="color: #b6a0ff;">setq</span> tetris-rot (% (+ 1 tetris-rot)
                          (tetris-shape-rotations)))
      (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
          (<span style="color: #b6a0ff;">setq</span> tetris-rot (% (+ 3 tetris-rot)
                              (tetris-shape-rotations))))
      (tetris-draw-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-rotate-next</span> ()
  <span style="color: #9ac8e0;">"Rotate the shape anticlockwise."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">unless</span> tetris-paused
        (tetris-erase-shape)
        (<span style="color: #b6a0ff;">setq</span> tetris-rot (% (+ 3 tetris-rot)
                            (tetris-shape-rotations)))
        (<span style="color: #b6a0ff;">if</span> (tetris-test-shape)
            (<span style="color: #b6a0ff;">setq</span> tetris-rot (% (+ 1 tetris-rot)
                                (tetris-shape-rotations))))
        (tetris-draw-shape)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-end-game</span> ()
  <span style="color: #9ac8e0;">"Terminate the current game."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (gamegrid-kill-timer)
  (use-local-map tetris-null-map)
  (gamegrid-add-score tetris-score-file tetris-score))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-start-game</span> ()
  <span style="color: #9ac8e0;">"Start a new game of Tetris."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (tetris-reset-game)
  (use-local-map tetris-mode-map)
  (<span style="color: #b6a0ff;">let</span> ((period (<span style="color: #b6a0ff;">or</span> (tetris-get-tick-period)
                    tetris-default-tick-period)))
    (gamegrid-start-timer period 'tetris-update-game)))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-pause-game</span> ()
  <span style="color: #9ac8e0;">"Pause (or resume) the current game."</span>
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
  (<span style="color: #b6a0ff;">setq</span> tetris-paused (not tetris-paused))
  (message (<span style="color: #b6a0ff;">and</span> tetris-paused <span style="color: #79a8ff;">"Game paused (press p to resume)"</span>)))

(<span style="color: #b6a0ff;">setq</span> tetris-current-shape nil
      tetris-hold-shape nil)

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-hold-piece</span> ()
  (<span style="color: #b6a0ff;">interactive</span> nil tetris-mode)
    (<span style="color: #b6a0ff;">let</span> ((current-shape tetris-current-shape)
          (current-rot tetris-rot))
      (<span style="color: #b6a0ff;">if</span> tetris-hold-shape
          (<span style="color: #b6a0ff;">progn</span>
            (<span style="color: #b6a0ff;">setq</span> tetris-current-shape tetris-hold-shape
                  tetris-rot 0)
            (<span style="color: #b6a0ff;">setq</span> tetris-hold-shape current-shape
                  tetris-piece-held t))
          (<span style="color: #b6a0ff;">progn</span>
            (tetris-draw-next-shape)
            (<span style="color: #b6a0ff;">setq</span> tetris-hold-shape current-shape
                  tetris-rot 0
                  tetris-piece-held t))))
)

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetris-active-p</span> ()
  (eq (current-local-map) tetris-mode-map))

(put 'tetris-mode 'mode-class 'special)

(<span style="color: #b6a0ff;">define-derived-mode</span> <span style="color: #feacd0;">tetris-mode</span> nil <span style="color: #79a8ff;">"Tetris"</span>
  <span style="color: #9ac8e0;">"A mode for playing Tetris."</span>
  <span style="color: #f78fe7;">:interactive</span> nil

  (add-hook 'kill-buffer-hook 'gamegrid-kill-timer nil t)

  (use-local-map tetris-null-map)

  (<span style="color: #b6a0ff;">setq</span> show-trailing-whitespace nil)

  (<span style="color: #b6a0ff;">setq</span> gamegrid-use-glyphs tetris-use-glyphs)
  (<span style="color: #b6a0ff;">setq</span> gamegrid-use-color tetris-use-color)

  (gamegrid-init (tetris-display-options)))

<span style="color: #989898;">;;;</span><span style="color: #989898;">###</span><span style="color: #fec43f;">autoload</span>
(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">mitetris</span> ()
  <span style="color: #9ac8e0;">"Play the Tetris game.</span>
<span style="color: #9ac8e0;">Shapes drop from the top of the screen, and the user has to move and</span>
<span style="color: #9ac8e0;">rotate the shape to fit in with those at the bottom of the screen so</span>
<span style="color: #9ac8e0;">as to form complete rows.</span>

<span style="color: #9ac8e0;">`</span><span style="color: #00bcff;">tetris-mode</span><span style="color: #9ac8e0;">' keybindings:</span>
<span style="color: #9ac8e0;">\\&lt;</span><span style="color: #00d3d0;">tetris-mode-map</span><span style="color: #9ac8e0;">&gt;</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-start-game</span><span style="color: #9ac8e0;">]   Start a new game of Tetris</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-end-game</span><span style="color: #9ac8e0;">]     Terminate the current game</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-pause-game</span><span style="color: #9ac8e0;">]   Pause (or resume) the current game</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-move-left</span><span style="color: #9ac8e0;">]    Move the shape one square to the left</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-move-right</span><span style="color: #9ac8e0;">]   Move the shape one square to the right</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-rotate-prev</span><span style="color: #9ac8e0;">]  Rotate the shape clockwise</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-rotate-next</span><span style="color: #9ac8e0;">]  Rotate the shape anticlockwise</span>
<span style="color: #9ac8e0;">\\[</span><span style="color: #00bcff;">tetris-move-bottom</span><span style="color: #9ac8e0;">]  Drop the shape to the bottom of the playing area"</span>
  (<span style="color: #b6a0ff;">interactive</span>)

  (select-window (<span style="color: #b6a0ff;">or</span> (get-buffer-window tetris-buffer-name)
                     (selected-window)))
  (switch-to-buffer tetris-buffer-name)
  (gamegrid-kill-timer)
  (tetris-mode)
  (tetris-start-game))

(<span style="color: #b6a0ff;">provide</span> '<span style="color: #00bcff;">mitetris</span>)

<span style="color: #989898;">;;; </span><span style="color: #989898;">tetris.el ends here</span>

</pre>
</div>
</div>
</div>
</div>
<div id="outline-container-orgf1f5cdd" class="outline-2">
<h2 id="orgf1f5cdd">Conclusión</h2>
<div class="outline-text-2" id="text-orgf1f5cdd">
<p>
Finalmente, para poder probarlo todo, basta con evaluar los trozos de
Elisp que he ido poniendo a lo largo del post, y ejecutar <code>M-x
mitetris</code>. Funciona por lo menos en las versiones 29.1.9 y 29.2 de Emacs, que
son en las que lo he probado.
</p>

<p>
Así que, en tan sólo un rato, y sin tener mucha idea de Elisp, he conseguido
hacer una solución chapucera que me permite jugar con una
funcionalidad extra al Tetris de Emacs.
</p>

<p>
Me he divertido mucho haciéndolo, y además tengo muchas ideas de cómo
mejorarlo para poder convertirlo en código en condiciones. Junto con
mi <a href="http://www.finaprosadigital.com/publish/blog/2023-01-12-creando-un-modo-menor-en-emacs.html">modo menor</a>, ya tengo una experiencia de juego completamente
personalizada :).
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-software.html">software</a> <a href="https://www.finaprosadigital.com/tag-libre,.html">libre,</a> <a href="https://www.finaprosadigital.com/tag-tetris.html">tetris</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[software]]></category>
  <category><![CDATA[libre,]]></category>
  <category><![CDATA[tetris]]></category>
  <link>https://www.finaprosadigital.com/2024-01-23-tetris.html</link>
  <guid>https://www.finaprosadigital.com/2024-01-23-tetris.html</guid>
  <pubDate>Tue, 23 Jan 2024 22:29:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Nethack]]></title>
  <description><![CDATA[
<p>
La primera vez que jugué al <a href="https://www.thegreatestgameyouwilleverplay.com/">Nethack</a> lo hice simplemente por
curiosidad. Quería ver si era posible hacer un juego cuyos gráficos
fueran tan solo caracteres ASCII. También estaba interesado en ver
cómo era el primer <i>roguelike</i>, ya que Nethack deriva del Hack que a
su vez es una evolución de Rogue, que fue el primer juego del género
al que da nombre.
</p>

<p>
No sé si fue porque ya estaba acostumbrado por el Dwarf Fortress a ver
gráficos en ASCII, pero no me costó empezar a jugar, y para mi
sorpresa, descubrí que era un juego increíblemente entretenido, que
era algo más que una simple curiosidad.
</p>

<p>
El objetivo del juego es de lo más simple. Tienes que bajar a las
mazmorras para conseguir el amuleto de Yendor y entregárselo a tu
Dios.
</p>

<p>
Pero realmente en una partida de Nethack puede suceder de todo, y para
muestra dejo un resumen de algunas de mis muertes favoritas en el juego.
</p>
<div id="outline-container-orgb6f6e8b" class="outline-2">
<h2 id="orgb6f6e8b">La de los hombres-rata</h2>
<div class="outline-text-2" id="text-orgb6f6e8b">
<p>
Mi camino quedó bloqueado por una piedra enorme. Me estaban acosando
unos hombres rata, así que me dejé morder por uno de ellos, me
transformé en rata, pasé por el hueco entre la piedra y la pared y
luego usé la habilidad que tienen los hombres rata de llamar a una
jauría de ratas. Me enfrenté con mi equipo de ratas contra el del otro
hombre rata, pero desafortunadamente perdí y morí.
</p>
</div>
</div>
<div id="outline-container-org970b1aa" class="outline-2">
<h2 id="org970b1aa">La de la ninfa <del>de los cojones</del></h2>
<div class="outline-text-2" id="text-org970b1aa">
<p>
Conseguí un amuleto al inicio de la partida, lo identifiqué con un
pergamino de identificación y vi que era un amuleto de reflejo, un
objeto extremadamente valioso y raro. Al instante me lo puse, deseoso
de estrenarlo contra algún hechizo enemigo.
</p>

<p>
Mi perro se cargó a un monstruo que al morir explotó dejándome ciego,
y mientras estaba ciego una ninfa me quitó el amuleto y una varita que
no había identificado, así que no sabía qué hacía.
</p>

<p>
Cuando recuperé la vista, fui en busca de la ninfa a recuperar mi
preciado amuleto, para acabar muerto a manos de mi varita, que la ninfa
(con mi amuleto puesto) había agitado, y había resultado ser una varita
de fuego que me chamuscó, y morí.
</p>
</div>
</div>
<div id="outline-container-org2d068d3" class="outline-2">
<h2 id="org2d068d3">La cocatriz</h2>
<div class="outline-text-2" id="text-org2d068d3">
<p>
Si una cocatriz te ataca puedes convertirte en piedra, pero si las
coges con guantes y las usas como arma puedes convertir en piedra a los
enemigos. Yo iba muy contento aporreando enemigos con mi cocatriz. De
hecho estaba tan contento que se me olvidó comer, me desmayé por el
hambre, caí sobre la cocatriz y me convertí en piedra.
</p>
</div>
</div>
<div id="outline-container-org30df253" class="outline-2">
<h2 id="org30df253">Y muchas otras más&#x2026;</h2>
<div class="outline-text-2" id="text-org30df253">
<p>
He mencionado algunas de mis partidas, pero en los años que he jugado
he tenido una gran variedad de muertes, por cosas tan variadas como un
abrelatas maldito o equivocarme de tecla y beber la poción que no era.
</p>

<p>
Así que, por ser un juego tremendamente entretenido, por condensarlo
todo en poco más de 1 megabyte, por ser software libre, y por muchas
otras cosas, creo que Nethack es el mejor juego que existe.
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-nethack,.html">nethack,</a> <a href="https://www.finaprosadigital.com/tag-juegos,.html">juegos,</a> <a href="https://www.finaprosadigital.com/tag-software.html">software</a> <a href="https://www.finaprosadigital.com/tag-libre.html">libre</a> </div>]]></description>
  <category><![CDATA[nethack,]]></category>
  <category><![CDATA[juegos,]]></category>
  <category><![CDATA[software]]></category>
  <category><![CDATA[libre]]></category>
  <link>https://www.finaprosadigital.com/2024-01-13-nethack.html</link>
  <guid>https://www.finaprosadigital.com/2024-01-13-nethack.html</guid>
  <pubDate>Sat, 13 Jan 2024 19:14:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Poniendo en marcha el Pinephone]]></title>
  <description><![CDATA[
<p>
Actualmente en el mundo GNU/Linux, hay 3 opciones destacadas para
tener un móvil: Fairphone, Librem y Pinephone.
</p>

<p>
Con un precio de alrededor de 700€ y 1000€ para los dos primeros, no
son opciones que estén al alcance de todos los bolsillos. Así que como
opción económica sólo queda el Pinephone, que incluso en su versión
Pro cuesta 400€, muy por debajo del Fairphone.
</p>

<p>
El Pinephone normal se puede adquirir por 150€ o 200€ a día de hoy,
así que es la única opción de bajo presupuesto actualmente.
</p>

<p>
Debido a eso me lo he comprado, y como viene con un sistema operativo
basado en Arch Linux, nada más encenderlo e intentarlo actualizar ya
empezó a dar fallos.
</p>

<p>
Así que como no tenía tiempo que perder, decidí meterle Mobian y
dejarme de líos. Desde hace ya muchos años uso Debian como sistema
operativo principal, y como es la distribución más robusta que hay es
difícil que falle.
</p>

<p>
Lo primero que vi que había que hacer según la documentación del
Pinephone es instalar Towboot. Siguiendo los pasos de la propia web de
Towboot es muy fácil de hacer, sólo hace falta una microSD y un lector
de microSD. Una vez bajada la imagen no hay más que ejecutar el
comando dd para grabarla en la sd.
</p>

<p>
Luego, otra vez con dd, copié una imagen de Mobian en la microSD. Al
encender el Pinephone ya tenía Mobian instalado y lo configuré en un momento.
</p>

<p>
Me funcionan los datos, las llamadas, el wifi y la cámara. Ahora mismo
no he visto que falle nada. Si bien es un prototipo y no es fiable,
para el uso que le doy hasta ahora me ha ido todo perfectamente.
</p>

<p>
Alguna vez se me ha reiniciado, y si no se suspende la batería se
acaba en un par de horas por un problema del módem EG25. Por lo demás,
lo uso acompañado de una batería externa por si se me olvida
suspenderlo.
</p>

<p>
Obviamente no tiene apps porque es un sistema GNU/Linux, no Android,
pero es una pasada poder tener un ordenador de verdad en el
bolsillo. Además mi edición venía con un dock USB tipo C para poder
conectarlo por HDMI, y también tiene varios USB normales.
</p>

<p>
Con todo esto se puede montar en un momento un ordenador de sobremesa
en cualquier lado, y llevártelo en el bolsillo a donde quieras. Espero
que los móviles GNU/Linux sigan en desarrollo y se puedan ver en el
futuro en las tiendas, de momento como opción económica y de prueba el
Pinephone es un buen sustituto.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-pinephone,.html">Pinephone,</a> <a href="https://www.finaprosadigital.com/tag-gnu/linux.html">GNU/Linux</a> </div>]]></description>
  <category><![CDATA[Pinephone,]]></category>
  <category><![CDATA[GNU/Linux]]></category>
  <link>https://www.finaprosadigital.com/2024-01-05-poniendo-en-marcha-el-pinephone.html</link>
  <guid>https://www.finaprosadigital.com/2024-01-05-poniendo-en-marcha-el-pinephone.html</guid>
  <pubDate>Fri, 05 Jan 2024 19:24:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Tabla de etiquetas en Emacs]]></title>
  <description><![CDATA[
<p>
Hoy estaba en una práctica de informática intentando comprender un código bastante ilegible de un profesor, y me acordé de que con Emacs se puede construir un archivo de etiquetas para poder consultar rápidamente algunas definiciones.
</p>

<p>
En concreto es bastante útil si hay cabeceras personalizadas con funciones y estructuras predefinidas y no quieres estar todo el rato de un lado para otro mirando definiciones.
</p>

<p>
Por suerte me acordaba de dónde tenía que consultar cómo crear el archivo para poner en funcionamiento el sistema y lo hice sobre la marcha, pero por si acaso no me acuerdo en el futuro lo voy a dejar aquí documentado.
</p>

<p>
La característica a la que me refiero se llama <code>TAGS</code> en el manual de Emacs, y se puede consultar más sobre su funcionamiento en el nodo <code>Tags tables</code>, que a fecha de este post es el punto 29.4.2 del manual.
</p>

<p>
Si no entendido mal todo consiste en crear un archivo al que Emacs pueda acudir para mirar las definiciones correspondientes y saltar hacia donde sea necesario. Para crear este archivo basta con ejecutar por ejemplo <code>find . -name "*.[chCH]" -print | etags -</code> en el directorio base del proyecto y luego pulsar <code>M-.</code> en la definición que queramos mirar.
</p>

<p>
A pesar de no tener internet en el momento de la práctica pude consultar todo esto con tan sólo un <code>C-h i</code>, y montar el archivo aunque no me acordaba de como se hacía. Y como resultado pude comprender la práctica de forma mucho más fácil y conseguí hacerla sin desesperarme, todo gracias a Emacs :).
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-tags,.html">TAGS,</a> <a href="https://www.finaprosadigital.com/tag-emacs.html">Emacs</a> </div>]]></description>
  <category><![CDATA[TAGS,]]></category>
  <category><![CDATA[Emacs]]></category>
  <link>https://www.finaprosadigital.com/2023-12-20-tabla-de-etiquetas-en-emacs.html</link>
  <guid>https://www.finaprosadigital.com/2023-12-20-tabla-de-etiquetas-en-emacs.html</guid>
  <pubDate>Wed, 20 Dec 2023 09:27:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Cambio de dominio]]></title>
  <description><![CDATA[
<p>
Ahora que se me ha acabado la oferta que tenía del dominio
"unavidalibre.xyz", como me cuesta casi lo mismo que un dominio
".com", he decidido renombrar el blog a "finaprosadigital.com".
</p>

<p>
El nuevo nombre es una referencia un poco oscura a un capítulo de
"Aquí no hay quien viva", pero también he pensado en escribir sobre
otros temas además del software libre, como libros o cubos de Rubik,
así que es un buen nombre por partida doble.
</p>

<p>
Además del cambio de nombre me queda pendiente arreglar algunas
cuestiones técnicas del blog, como los enlaces a entradas antiguas que
siguen teniendo el nombre del dominio anterior. Espero poder ir
arreglándolo poco a poco.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-dominio,.html">dominio,</a> <a href="https://www.finaprosadigital.com/tag-blog.html">blog</a> </div>]]></description>
  <category><![CDATA[dominio,]]></category>
  <category><![CDATA[blog]]></category>
  <link>https://www.finaprosadigital.com/2023-10-18-cambio-de-dominio.html</link>
  <guid>https://www.finaprosadigital.com/2023-10-18-cambio-de-dominio.html</guid>
  <pubDate>Wed, 18 Oct 2023 21:35:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Configuración de Emacs con macros]]></title>
  <description><![CDATA[
<p>
Este verano tuve un par de sesiones de "coaching" con Protesilaos
(<a href="https://www.protesilaos.com/">https://www.protesilaos.com/</a>). Aprendí varias cosas sobre elisp, y además creé mi
propia macro para configurar Emacs.
</p>

<p>
El problema que estaba teniendo es que siempre que intentaba instalar
Emacs desde cero en otro ordenador, la gestión de paquetes me daba
problemas, y tenía que reiniciar Emacs varias veces para completar la
instalación.
</p>

<p>
Mi objetivo es que con mi archivo de configuración pueda coger un
ordenador cualquiera, iniciar Emacs y tenerlo todo configurado y listo,
como si estuviera en mi propio ordenador (excepto en lo referente a archivos
personales, claro).
</p>

<p>
Así que la solución a la que llegué con Prot fue hacerme mi propia
macro, para gestionar así todo lo que tenga que ver con los paquetes,
y saber qué está pasando en cada momento. La macro a la que he llegado
es:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span style="color: #b6a0ff;">defmacro</span> <span style="color: #feacd0;">my-package-install</span> (package <span style="color: #6ae4b9;">&amp;rest</span> body)
  <span style="color: #9ac8e0;">"Installs PACKAGE.</span>
<span style="color: #9ac8e0;">If the package cannot be installed, remind the user to add the package-archives. Then, the user can configure the PACKAGE."</span>
  `(<span style="color: #b6a0ff;">progn</span>
     <span style="color: #989898;">;;</span><span style="color: #989898;">First stage; package installation</span>
     (<span style="color: #b6a0ff;">unless</span> (package-installed-p ,package)
       (<span style="color: #b6a0ff;">unless</span> package-archive-contents
  (package-refresh-contents))
       (<span style="color: #b6a0ff;">or</span> (<span style="color: #b6a0ff;">ignore-errors</span> (package-install ,package))
    (message <span style="color: #79a8ff;">"Did you add MELPA to the `</span><span style="color: #00bcff;">package-archives</span><span style="color: #79a8ff;">'"</span>)))
     <span style="color: #989898;">;;</span><span style="color: #989898;">Second stage; package configuration</span>
     (<span style="color: #b6a0ff;">require</span> ,package)
     ,@body
     )
  )
</pre>
</div>

<p>
Básicamente lo que hace es comprobar si un paquete está instalado, y si
lo está, lo configura con los argumentos que se le pasen. Además para
evitar el error que tenía anteriormente, la macro te da una posible
solución al error.
</p>

<p>
Con todo esto listo, ahora sólo tengo que implementar la macro con los
paquetes de mi configuración. Una vez lo tenga todo hecho, debería
poder usar Emacs en cualquier ordenador con sólo pulsar un botón.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-macros,.html">macros,</a> <a href="https://www.finaprosadigital.com/tag-elisp.html">elisp</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[macros,]]></category>
  <category><![CDATA[elisp]]></category>
  <link>https://www.finaprosadigital.com/2023-09-09-configuraci%C3%B3n-de-emacs-con-macros.html</link>
  <guid>https://www.finaprosadigital.com/2023-09-09-configuraci%C3%B3n-de-emacs-con-macros.html</guid>
  <pubDate>Sat, 09 Sep 2023 18:39:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Publicación de un paquete en MELPA]]></title>
  <description><![CDATA[
<p>
El otro día estaba mirando la lista de paquetes de MELPA, y vi que
había  varios paquetes que añadían al calendario de Emacs los días
festivos de varios países. Sin embargo no encontré por ningún lado
los festivos de España, y pensé en hacer yo mismo el paquete.
</p>
<div id="outline-container-org782b57c" class="outline-2">
<h2 id="org782b57c">Primer paso: creación del paquete</h2>
<div class="outline-text-2" id="text-org782b57c">
<p>
Como es un paquete muy simple, no me llevó mucho tiempo. Me basé en el
paquete de mexican-holidays y copié su estructura. Luego fui a la
página del gobierno donde están publicados los festivos de 2023.
</p>
</div>
</div>
<div id="outline-container-org3ba5d98" class="outline-2">
<h2 id="org3ba5d98">Segundo paso: formato del paquete</h2>
<div class="outline-text-2" id="text-org3ba5d98">
<p>
Una vez creado, le di al paquete el formato requerido por
MELPA. Siguiendo las instrucciones de
<code>https://github.com/melpa/melpa/blob/master/README.md#contributing</code> y
<code>https://github.com/melpa/melpa/blob/master/CONTRIBUTING.org</code>.
</p>

<p>
Al ser un paquete de un sólo archivo, sin dependencias, lo único que
hice fue pasarle el package-lint y checkdoc para comprobar que todo
estaba correcto y con buena documentación y estructura.
</p>
</div>
</div>
<div id="outline-container-org220b410" class="outline-2">
<h2 id="org220b410">Tercer paso: creación del recipe y pull request</h2>
<div class="outline-text-2" id="text-org220b410">
<p>
Para integrar el paquete en MELPA, hay que hacer un <code>git clone</code> del
repositorio de MELPA, añadir un archivo llamado recipe donde se
incluye el nombre del paquete así como el repositorio fuente, y por
último solicitar un pull request en Github.
</p>
</div>
</div>
<div id="outline-container-orgb990825" class="outline-2">
<h2 id="orgb990825">Cuarto paso: comprobación del merge</h2>
<div class="outline-text-2" id="text-orgb990825">
<p>
Antes de hacer un merge en MELPA, un revisor comprobará que el paquete
cumple todos los requerimientos, hará algún comentario por si falta
algo y luego finalmente se hará el merge. En mi caso me faltaba añadir
el archivo de licencia, tras añadirlo el paquete fue incluido en
MELPA.
</p>
</div>
</div>
<div id="outline-container-org621b970" class="outline-2">
<h2 id="org621b970">Conclusión</h2>
<div class="outline-text-2" id="text-org621b970">
<p>
Todo el proceso se realizó en menos de 24 horas. Todas las
instrucciones fueron muy claras, y el revisor muy amable. Incluso sin
saber mucho de elisp, he podido crear y contribuir con un paquete al
entorno de GNU Emacs.
</p>
</div>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-elisp,.html">elisp,</a> <a href="https://www.finaprosadigital.com/tag-melpa.html">melpa</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[elisp,]]></category>
  <category><![CDATA[melpa]]></category>
  <link>https://www.finaprosadigital.com/2023-06-27-publicaci%C3%B3n-de-un-paquete-en-melpa.html</link>
  <guid>https://www.finaprosadigital.com/2023-06-27-publicaci%C3%B3n-de-un-paquete-en-melpa.html</guid>
  <pubDate>Tue, 27 Jun 2023 16:25:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Subiendo el volumen]]></title>
  <description><![CDATA[
<p>
Por alguna razón, en mi Thinkpad X230 a veces el volumen al 100% sigue siendo demasiado bajo. Pero como es posible subir el volumen bastante por encima del 100%, he implementado un atajo de teclado en el archivo de configuración de i3wm que me permita subir el volumen todo lo que quiera.
</p>

<p>
Simplemente hay que añadir las siguientes líneas al config de i3:
</p>

<p>
<code>bindsym Shift+XF86AudioRaiseVolume exec pactl -- set-sink-volume 0 +10% &amp;&amp; pkill -RTMIN+10 i3blocks</code>
<code>bindsym Shift+XF86AudioLowerVolume exec pactl -- set-sink-volume 0 -10% &amp;&amp; pkill -RTMIN+10 i3blocks</code>
</p>

<p>
Y así, al pulsar shift y el botón de subir o bajar el volumen, se subirá por encima del 100% o se bajará en incrementos del 10%.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-alsa,audio,i3wm.html">alsa,audio,i3wm</a> </div>]]></description>
  <category><![CDATA[alsa,audio,i3wm]]></category>
  <link>https://www.finaprosadigital.com/2023-05-28-subiendo-el-volumen.html</link>
  <guid>https://www.finaprosadigital.com/2023-05-28-subiendo-el-volumen.html</guid>
  <pubDate>Sun, 28 May 2023 12:45:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Guía para leer a Gene Wolfe]]></title>
  <description><![CDATA[
<p>
Gracias a la tecnología RSS descubrí hace un par de meses el mundo de Gene Wolfe a través del blog "Take on Rules"
(<a href="https://takeonrules.com/2022/05/30/on-gathering-an-online-group-for-gaming/">https://takeonrules.com/2022/05/30/on-gathering-an-online-group-for-gaming/</a>), en el que se cita un fragmento del libro
"La Ciudadela del Autarca" (aunque el resto del post no tiene nada que ver con el libro). Me pareció curioso el título
del libro y tenía un presentimiento de que me iba a gustar. 
</p>

<p>
Tanto ha sido así que estoy ya me lo he leído cuatro veces, y desde que descubrí las infinitas capas de profundidad que da
Gene Wolfe a sus relatos se ha convertido probablemente en el libro que más he disfrutado de todos los que he leído. 
</p>

<p>
Es un escritor que ya en el mundo anglosajón es poco conocido (es conocido entre escritores, pero no gusta tanto a los
lectores), cuanto más en España, por lo que he decidido dejar aquí adaptada en español la guía sobre cómo leer a Gene
Wolfe que hizo en su día Neil Gaiman, con el objetivo de facilitar su lectura. Son libros densos, cuya lectura requiere
poner atención, estar concentrado y atento a los detalles, pero es altamente gratificante ir descifrando los misterios y
el universo que propone Wolfe. 
</p>

<p>
Según Gaiman, para disfrutar la lectura de Gene Wolfe hay que: 
</p>

<ol class="org-ol">
<li>Confiar en el texto implícitamente. Las respuestas están ahí.</li>
<li>No te fíes del texto a ciegas. Está lleno de trucos y engaños, el narrador no es una persona en la que se pueda
confiar.</li>
<li>Vuelve a leer. Es mejor la segunda vez. Será aún mejor la tercera vez. Y de todos modos, los libros se transformarán
sutilmente mientras estés lejos de ellos. El libro "Paz" realmente era una memoria agradable del Medio Oeste la primera
vez que lo leí. Solo se convirtió en una novela de terror en la segunda o tercera lectura.</li>
<li>Hay lobos ahí dentro, acechando detrás de las palabras. A veces salen en las páginas. A veces esperan hasta que cierres
el libro. El almizcleño olor a lobo a veces puede ser enmascarado por el perfume aromático del romero. Ten en cuenta
que estos no son lobos de hoy, que se arrastran grises en manadas por lugares desiertos. Estos son lobos excepcionales,
enormes y solitarios que podrían mantenerse en pie frente a los osos pardos.</li>
<li>Leer a Gene Wolfe es un trabajo peligroso. Es un acto de lanzar cuchillos, y como todos los buenos actos de lanzar
cuchillos, puedes perder dedos, dedos de los pies, lóbulos de las orejas o ojos en el proceso. A Gene se la
refanfinfla, él es el que está lanzando los cuchillos.</li>
<li>Ponte cómodo. Sirve una tetera de té. Cuelga una señal de NO MOLESTAR. Comienza en la página uno.</li>
<li>Hay dos tipos de escritores astutos. Los que señalan cuán astutos son, y los que no ven la necesidad de señalar cuán
astutos son. Gene Wolfe es del segundo tipo, y la inteligencia es menos importante que la historia. No es inteligente
para hacerte sentir estúpido. Es inteligente para hacerte inteligente también.</li>
<li>Él estaba allí. Lo vio suceder. Sabe cuál fue la reflexión que vieron en el espejo esa noche.</li>
<li>Estar dispuesto a aprender.</li>
</ol>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-literatura,.html">literatura,</a> <a href="https://www.finaprosadigital.com/tag-gene,.html">Gene,</a> <a href="https://www.finaprosadigital.com/tag-wolfe.html">Wolfe</a> </div>]]></description>
  <category><![CDATA[literatura,]]></category>
  <category><![CDATA[Gene,]]></category>
  <category><![CDATA[Wolfe]]></category>
  <link>https://www.finaprosadigital.com/2023-04-01-gu%C3%ADa-para-leer-a-gene-wolfe.html</link>
  <guid>https://www.finaprosadigital.com/2023-04-01-gu%C3%ADa-para-leer-a-gene-wolfe.html</guid>
  <pubDate>Sat, 01 Apr 2023 11:05:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Creando un modo menor en Emacs]]></title>
  <description><![CDATA[
<p>
Aprovechando la versatilidad de Emacs he decidido crear un "modo menor" para poder jugar de forma más cómoda al tetris dentro del propio Emacs. Seguramente haya formas menos complicadas de hacer lo mismo, pero haciendo esto se aprende un poco mejor cómo funcionan los modos menores.
</p>

<p>
He adaptado el código de System Crafters  (<a href="https://systemcrafters.cc/learning-emacs-lisp/creating-minor-modes">https://systemcrafters.cc/learning-emacs-lisp/creating-minor-modes</a>), y he creado sendas funciones para asignar el movimiento de las piezas del tetris a las teclas "j" y "k".  El modo se llama "tetritecla-basic-mode" y básicamente sólo sirve para añadir esos atajos de teclas, junto a "k" para rotar piezas y "h" para bajarlas.
</p>

<p>
Si ahora activo el modo "tetritecla-basic-mode" con un hook al iniciar el programa "tetris", ya obtengo las nuevas teclas de forma automática cada vez que quiera jugar. ¡Fácil y cómodo!
</p>

<p>
A continuación dejo el código:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp">(make-variable-buffer-local
  (<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetritecla-basic-mode</span> nil
    <span style="color: #9ac8e0;">"Alterna tetritecla-basic-mode."</span>))

(<span style="color: #b6a0ff;">defvar</span> <span style="color: #00d3d0;">tetritecla-basic-mode-map</span> (make-sparse-keymap)
  <span style="color: #9ac8e0;">"El keymap para tetritecla-basic-mode"</span>)

<span style="color: #989898;">;; </span><span style="color: #989898;">Definici&#243;n de las teclas para jugar.</span>
(define-key tetritecla-basic-mode-map (kbd <span style="color: #79a8ff;">"j"</span>)
  (<span style="color: #b6a0ff;">lambda</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    (tetris-move-left)))

(define-key tetritecla-basic-mode-map (kbd <span style="color: #79a8ff;">"k"</span>)
  (<span style="color: #b6a0ff;">lambda</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    (tetris-rotate-prev)))     

(define-key tetritecla-basic-mode-map (kbd <span style="color: #79a8ff;">"h"</span>)
  (<span style="color: #b6a0ff;">lambda</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    (tetris-move-down)))

(define-key tetritecla-basic-mode-map (kbd <span style="color: #79a8ff;">"l"</span>)
  (<span style="color: #b6a0ff;">lambda</span> ()
    (<span style="color: #b6a0ff;">interactive</span>)
    (tetris-move-right)))

(add-to-list 'minor-mode-alist '(tetritecla-basic-mode <span style="color: #79a8ff;">" tetritecla"</span>))
(add-to-list 'minor-mode-map-alist (cons 'tetritecla-basic-mode tetritecla-basic-mode-map))

(<span style="color: #b6a0ff;">defun</span> <span style="color: #feacd0;">tetritecla-basic-mode</span> (<span style="color: #6ae4b9;">&amp;optional</span> ARG)
  (<span style="color: #b6a0ff;">interactive</span> (list 'toggle))
  (<span style="color: #b6a0ff;">setq</span> tetritecla-basic-mode
        (<span style="color: #b6a0ff;">if</span> (eq ARG 'toggle)
            (not tetritecla-basic-mode)
          (&gt; ARG 0)))

  <span style="color: #989898;">;; </span><span style="color: #989898;">Aviso de activaci&#243;n de modo</span>
  (<span style="color: #b6a0ff;">if</span> tetritecla-basic-mode
      (message <span style="color: #79a8ff;">"tetritecla-basic-mode activado"</span>)
    (message <span style="color: #79a8ff;">"tetritecla-basic-mode desactivado"</span>)))
</pre>
</div>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-elisp.html">elisp</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[elisp]]></category>
  <link>https://www.finaprosadigital.com/2023-01-12-creando-un-modo-menor-en-emacs.html</link>
  <guid>https://www.finaprosadigital.com/2023-01-12-creando-un-modo-menor-en-emacs.html</guid>
  <pubDate>Thu, 12 Jan 2023 22:21:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Notmuch-indicator]]></title>
  <description><![CDATA[
<p>
Protesilaos ha sacado un nuevo paquete para GNU/Emacs, <a href="eww:https://protesilaos.com/codelog/2022-09-21-notmuch-indicator-0-1-0/">notmuch-indicator</a>. Es el primer paquete que he visto que permite tener notificaciones sobre el correo en la modeline de Emacs sin tener que pelearse con código. Este paquete te permite tener un icono personalizable con el número de correos sin leer, o cualquier otro criterio que se le ocurra al usuario.
</p>

<p>
Su uso básico es tan simple como activar <code>notmuch-indicator-mode</code> y listo. Por supuesto, como cualquier paquete de Protesilaos, viene con una documentación excelente que explica todos los detalles y las posibilidades del paquete.
</p>

<p>
Con esto podemos tener fácilmente una integración perfecta del correo electrónico dentro de Emacs, y así maximizar el tiempo que pasamos dentro del mejor editor del mundo.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-protesilaos,.html">protesilaos,</a> <a href="https://www.finaprosadigital.com/tag-notmuch,.html">notmuch,</a> <a href="https://www.finaprosadigital.com/tag-email.html">email</a> </div>]]></description>
  <category><![CDATA[protesilaos,]]></category>
  <category><![CDATA[notmuch,]]></category>
  <category><![CDATA[email]]></category>
  <link>https://www.finaprosadigital.com/2022-09-22-notmuch-indicator.html</link>
  <guid>https://www.finaprosadigital.com/2022-09-22-notmuch-indicator.html</guid>
  <pubDate>Thu, 22 Sep 2022 20:11:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Publicación de una entrada con scp II]]></title>
  <description><![CDATA[
<p>
Para automatizar el despliegue del blog después de publicar una entrada con org-static-blog, se puede combinar la función <code>async-shell-command</code> con el hook que tiene org blog.
</p>

<p>
Antes que nada, para que funcione es necesario configurar la conexión de ssh para poder acceder a través de una clave al servidor. Por ejemplo, si ya tenemos la clave generada podemos usar:
</p>

<p>
<code>ssh-copy-id -i ~/.ssh/id_ed25519.pub pi@192.168.1.125</code>
</p>

<p>
Ahora, configuramos el hook:
</p>

<p>
<code>(add-hook 'org-publish-after-publishing-hook '(lambda () ((async-shell-command "scp -r ~/blog pi@192.168.1.125:/var/www/html/publish" "publicando"))))</code>
</p>

<p>
Y listo, cada vez que se publique una entrada con <code>org-static-blog-publish</code> se subirá el contenido al servidor automáticamente.
</p>

<p>
Edit: Me he confundido con el hook, el <code>org-publish-after-publishing-hook</code> es un hook de <code>org-publish</code> no de <code>org-static-publish</code>, por lo tanto su configuración es un poco más complicada y el hook que he puesto arriba no funciona. La función lambda sin embargo sí que es válida, la usaré en una futura entrada en la que configuré el hook correctamente.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-scp,.html">scp,</a> <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-blog,.html">blog,</a> <a href="https://www.finaprosadigital.com/tag-publicar.html">publicar</a> </div>]]></description>
  <category><![CDATA[scp,]]></category>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[blog,]]></category>
  <category><![CDATA[publicar]]></category>
  <link>https://www.finaprosadigital.com/2022-04-03-publicaci%C3%B3n-de-una-entrada-con-scp-ii.html</link>
  <guid>https://www.finaprosadigital.com/2022-04-03-publicaci%C3%B3n-de-una-entrada-con-scp-ii.html</guid>
  <pubDate>Sun, 03 Apr 2022 15:45:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Company ya tiene manual]]></title>
  <description><![CDATA[
<p>
Una de las mejores cosas que tiene el proyecto GNU, y por extensión GNU/Emacs, es la documentación. Con el paso de los años cada vez valoro más la importancia de una buena documentación, ya que leerla es la mejor forma de aprender a usar un determinado software.
</p>

<p>
En el caso de company-mode, tuve problemas cuando estaba configurándolo porque busqué por todos lados la documentación oficial pero solo encontraba posts en diversos blogs, que aunque pudieran ser muy útiles, no contenían el material de referencia que estaba buscando.
</p>

<p>
Quizás debido a que estoy ya acostumbrado a la extensa documentación de gran calidad de GNU, ni siquiera consideré que no existiera un manual como tal, y simplemente dejé de buscar porque pensé que no era capaz de encontrarlo. Pero hace poco descubrí que efectivamente el manual de company-mode se publicó en enero de 2022 si no me equivoco.
</p>

<p>
Está disponible online en <a href="https://company-mode.github.io/manual/Getting-Started.html">https://company-mode.github.io/manual/Getting-Started.html</a>, o, dependiendo de la versión de Emacs instalada se puede acceder al manual desde el propio Emacs con <code>C-h R company RET</code>.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-company-mode,.html">company-mode,</a> <a href="https://www.finaprosadigital.com/tag-emacs.html">emacs</a> </div>]]></description>
  <category><![CDATA[company-mode,]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://www.finaprosadigital.com/2022-04-02-company-ya-tiene-manual.html</link>
  <guid>https://www.finaprosadigital.com/2022-04-02-company-ya-tiene-manual.html</guid>
  <pubDate>Sat, 02 Apr 2022 19:06:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Octave en Emacs]]></title>
  <description><![CDATA[
<p>
Octave es la alternativa libre a Matlab®, que te permite hacer todo lo que hace Matlab pero sin tener que pagar miles de euros y descargar decenas de gigas.
</p>

<p>
Para integrarlo en mi flujo de trabajo en Emacs, decidí usar popper.el <code>https://github.com/karthink/popper</code>. Esto me permite tener a mano la consola de Octave con solo pulsar un botón.
</p>

<p>
Primero lo activo con <code>popper-mode</code>, después elijo el búfer que contiene la consola de Octave (por ejemplo el búfer que se crea al usar <code>run-octave</code>) y una vez en ese búfer con <code>popper-toggle-type</code> se convierte en un búfer fijado.
</p>

<p>
Luego se puede asignar <code>popper-toggle-latest</code> a cualquier tecla (por ejemplo f9), y al pulsar esa tecla la consola de Octave aparece y desaparece.
</p>

<p>
Es una buena forma de tener una consola de lo que sea siempre a mano.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-emacs,.html">emacs,</a> <a href="https://www.finaprosadigital.com/tag-octave.html">octave</a> </div>]]></description>
  <category><![CDATA[emacs,]]></category>
  <category><![CDATA[octave]]></category>
  <link>https://www.finaprosadigital.com/2022-03-17-octave-en-emacs.html</link>
  <guid>https://www.finaprosadigital.com/2022-03-17-octave-en-emacs.html</guid>
  <pubDate>Thu, 17 Mar 2022 19:48:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Publicación de una entrada con scp]]></title>
  <description><![CDATA[
<p>
En mi primer post indiqué el uso que hacía de sshfs para publicar el contenido del blog en mi Raspberry Pi. Sin embargo ahora mismo no me funciona ese método (no sé por qué), la carpeta sobre la que monto la Raspi con sshfs sigue vacía tras ejecutarse la orden, y no me da ningún error.
</p>

<p>
Así que he encontrado otra forma de copiar los arcihvos a través de scp. Sigue siendo un proceso muy simple, quizás incluso más con scp que con sshfs. La única orden que uso es:
</p>
<div class="org-src-container">
<pre class="src src-shell">scp -r ~/blog pi@192.168.1.125:/var/www/html/publish
</pre>
</div>

<p>
Con esto vuelvo a poder publicar entradas de forma cómoda en un momento.
</p>

<p>
Fuente: <a href="https://ugeek.github.io/blog/post/2021-04-01-scp-copias-por-ssh.html">https://ugeek.github.io/blog/post/2021-04-01-scp-copias-por-ssh.html</a>
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-blog,.html">blog,</a> <a href="https://www.finaprosadigital.com/tag-publicar,.html">publicar,</a> <a href="https://www.finaprosadigital.com/tag-scp.html">scp</a> </div>]]></description>
  <category><![CDATA[blog,]]></category>
  <category><![CDATA[publicar,]]></category>
  <category><![CDATA[scp]]></category>
  <link>https://www.finaprosadigital.com/2021-12-04-publicaci%C3%B3n-de-una-entrada.html</link>
  <guid>https://www.finaprosadigital.com/2021-12-04-publicaci%C3%B3n-de-una-entrada.html</guid>
  <pubDate>Sat, 04 Dec 2021 17:07:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Eshell para administración de sistemas]]></title>
  <description><![CDATA[
<p>
Llevo un tiempo intentando sustituir mi uso de Bash por Eshell. No es que tenga nada en contra de Bash, simplemente eshell es parte de Emacs y está escrita en Lisp, por lo que la puedo adaptar como quiera y se integra mejor en mi flujo de trabajo.
</p>

<p>
Sin embargo seguí usando Bash para conectarme por ssh a mi servidor en la Raspberry Pi. Hace poco descubrí que no es necesario hacer ésto si uso la Eshell. Simplemente puedo abrir una conexión con Tramp desde Emacs, y una vez que esté por ejemplo en un directorio remoto con dired, abrir la Eshell. Mágicamente estaré ya dentro del servidor como si de una conexión por ssh se tratase.
</p>

<p>
Lo único que me queda por resolver es la configuración de Tramp, ya que ahora mismo se me queda pillado a veces y no consigo conectarme al servidor a través de él, aunque pueda hacerlo por ssh normalmente.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-eshell,.html">eshell,</a> <a href="https://www.finaprosadigital.com/tag-emacs.html">emacs</a> </div>]]></description>
  <category><![CDATA[eshell,]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://www.finaprosadigital.com/2021-10-21-eshell-para-administraci%C3%B3n-de-sistemas.html</link>
  <guid>https://www.finaprosadigital.com/2021-10-21-eshell-para-administraci%C3%B3n-de-sistemas.html</guid>
  <pubDate>Thu, 21 Oct 2021 09:33:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Registro del dominio]]></title>
  <description><![CDATA[
<p>
Finalmente, para asociar un dominio al blog y así no tener que acordarme de la ip para entrar, he registrado <code>unavidalibre.xyz</code> en <code>epik.com</code>.
</p>

<p>
Una vez registrado, en el apartado de DNS RECORDS he asociado el nombre del dominio a mi ip, y así finalmente puedo entrar a mi blog con una dirección web normal.
</p>

<p>
He seguido las instrucciones de la página web de Luke Smith (<a href="https://landchad.net/dns">https://landchad.net/dns</a>)
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-epik,.html">epik,</a> <a href="https://www.finaprosadigital.com/tag-dominio,.html">dominio,</a> <a href="https://www.finaprosadigital.com/tag-registro.html">registro</a> </div>]]></description>
  <category><![CDATA[epik,]]></category>
  <category><![CDATA[dominio,]]></category>
  <category><![CDATA[registro]]></category>
  <link>https://www.finaprosadigital.com/2021-09-16-registro-del-dominio.html</link>
  <guid>https://www.finaprosadigital.com/2021-09-16-registro-del-dominio.html</guid>
  <pubDate>Thu, 16 Sep 2021 00:06:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Configuración del blog]]></title>
  <description><![CDATA[
<p>
La intención de esta entrada es describir el proceso que he seguido para crear el blog. La herramienta que he usado ha sido org-static-blog (<a href="https://github.com/bastibe/org-static-blog">https://github.com/bastibe/org-static-blog</a>). Como no conseguía darle estilo con CSS, cloné el repositorio del blog del creador de org-static-blog (<a href="https://github.com/bastibe/bastibe.github.com">https://github.com/bastibe/bastibe.github.com</a>) y luego lo modifiqué (eliminando todo salvo lo básico) para poder usarlo en mi servidor en la Raspi.
</p>

<p>
La configuración resultante la tengo en Gitlab (<a href="https://gitlab.com/gnuhack/dotfiles/-/blob/master/.emacs.d/emacs-literario.org">https://gitlab.com/gnuhack/dotfiles/-/blob/master/.emacs.d/emacs-literario.org</a>). El repositorio del blog modificado lo tengo en <code>~/blog</code>.
</p>

<p>
Finalmente, cuando quiera publicar una entrada no tengo más que usar <code>M-x org-static-blog-create-new-post</code>, escribir el post, y luego ejecutar <code>M-x org-static-blog-publish</code>.
</p>

<p>
Para terminar, monto la Raspi en una carpeta de mi sistema <code>sshfs pi@192.168.1.130:/var/www/html  ~/Public</code> y luego paso el contenido de mi ordenador a la Raspi <code>cp -r blog/ Public/</code>.
</p>
<div class="taglist"><a href="https://www.finaprosadigital.com/tags.html">Tags</a>: <a href="https://www.finaprosadigital.com/tag-config,.html">config,</a> <a href="https://www.finaprosadigital.com/tag-org-static-blog.html">org-static-blog</a> </div>]]></description>
  <category><![CDATA[config,]]></category>
  <category><![CDATA[org-static-blog]]></category>
  <link>https://www.finaprosadigital.com/2021-09-15-configuraci%C3%B3n-del-blog.html</link>
  <guid>https://www.finaprosadigital.com/2021-09-15-configuraci%C3%B3n-del-blog.html</guid>
  <pubDate>Wed, 15 Sep 2021 17:16:00 +0200</pubDate>
</item>
</channel>
</rss>
