Publicar html con org-mode
En el artículo de hoy hablo de cómo exportar de org-mode
a html
para utilizarlo en un proyecto con varios ficheros org
interconectados entre sí. Al exportar, las referencias org
se
convierten en sus correspondientes enlaces html
guardando la misma
estructura de directorios que tengan los ficheros org
. Es la forma
en la que org-mode
publica. Si quieres ahorrarte el suplicio de
leer el artículo y como lo cuento, busca el apartado publishing en
la documentación de org-mode
... pero si prefieres leer un resumen en
español y saber cómo lo hago yo: sigue leyendo.
¿De qué va todo esto de publicar html
desde org-mode
? ¿Para qué
lo puedo utilizar? Pues pondré un ejemplo, con un proyecto que estoy
empezando. Hace un tiempo puse por aquí una prueba para crear un
librojuego con org-mode
. Era una prueba pequeña y apenas se
utilizaban cuatro ficheros. Como eran tan pocos ficheros, las
cabeceras y la exportación se podía hacer a mano. Sin embargo, en un
proyecto largo, tener que hacerlo así puede ser un poco complicado,
tedioso y sujeto a errores y olvidos.
El caso de uso propuesto es parte de un proyecto más amplio. El
problema es que estoy haciendo una especie de MUD para aplicarlo en un
proyecto de prevención del acoso escolar para la Asociación PICA1
con la que, los que leéis el blog habitualmente, sabéis que
colaboro. El caso es que la parte servidor del mismo está
prácticamente finalizada, a la espera de que se llene de contenido y
de corregir los fallos y completar las carencias que se encuentren
durante el proceso. Para dotar de contenido algo tan interactivo como
un MUD, no sirve un guión lineal. Por ello, pensé en escribir
guiones más interactivos, en formato librojuego. He probado varios
sistemas que automatizan la creación de ese tipo de juegos: he
probado Undum, he probado Twine, he probado Squiffy... y ninguno de
los tres ha funcionado como esperaba. El primero, que había que
escribir el código en puro html
y javascript
, sin embargo, por
alguna razón que no llegué a averiguar algunos enlaces no
funcionaban. De los otros dos, además de tener que instalar node
y
un montón de paquetes, no terminaron de funcionar correctamente. La
otra idea que se me ocurrió era montar un wiki
enlazando páginas
directamente. Sin embargo, para que funcione tienes que tener un
servidor y para trabajar en modo monousuario es muy lioso.
Cuando le comenté los problemas que tenía para encontrar una
herramienta adecuada a un amigo del CAAD2, me dijo: pensaba
que lo harías con algún pichorro de Emacs. Y tenía razón, al final no
me tendré que pegar con cosas como electron y node o desperdiciar
espacio en disco y en memoria con esas cosas, teniendo suficiente con
el texto gestionado por los chismáticos de Emacs y org-mode
.
Estructura de ficheros
Para iniciar el proyecto es recomendable tener clara la estructura que le daremos a nuestro contenido. El proyecto lo he llamado, de forma provisional, Kvintero3 y tiene la siguiente estructura de ficheros:
. ├── html │ └── ... (directorio donde se publicará) ├── kvintero.el ├── org │ ├── css │ │ └── ... (hojas de estilo) │ ├── img │ │ └── ... (ficheros de imagen) │ ├── js │ │ └── ... (ficheros javascript) │ └── ... (ficheros org) ├── plantillas │ └── plantilla-base.org └── README.org
se pueden apreciar algunas cosas así a bote pronto: los directorios
org
y html
serán idénticos, pero mientras el primero está
compuesto de los fuentes de org-mode
el segundo es el resultado de
convertir los fuentes en html
. En esos directorios hay otros
subdirectorios para la(s) hoja(s) de estilos, las imágenes y los
archivos javascript
. También hay un directorio que se llama
plantillas
, donde hay sólo un fichero de momento y más adelante
analizaremos su contenido. Además de todo ésto también hay un fichero
de código que se llama kvintero.el
que contiene un par de formas que
definen algunas variables del proyecto para poder exportar cómodamente
en tres teclazos.
Es una estructura muy simple, aunque su visualización en árbol, pueda
dar una primera impresión de complejidad. En realidad, sólo necesitas
crear el directorio org
y dentro de él: el css
, el img
y el
js
, cada uno con sus cosas, para que no se mezclen.
Para que dicha estructura sea efectiva es recomendable que luego, en
los enlaces se utilicen siempre paths relativos. Para que el sitio
desplegado o publicado, ─como prefieras llamarlo─, funcione
incluso sin un servidor, es siempre recomendable el uso de dichos
paths relativos. Además, se pueden utilizar anclas a etiquetas
concretas dentro de otros ficheros org
4, como veremos después.
El código
Como he dicho antes, el código es muy sencillo, lo pongo aquí y luego lo comentaré un poco:
(require 'ox-publish) (setq org-publish-project-alist '( ("fuentes-org" :base-directory "~/proyectos/kvintero/org/" :base-extension "org" :publishing-directory "~/proyectos/kvintero/html/" :recursive t :publishing-function org-html-publish-to-html :headline-levels 4 :html-preamble t) ("org-auxiliares" :base-directory "~/proyectos/kvintero/org/" :base-extension "css\\|js\\|png\\|ttf" :publishing-directory "~/proyectos/kvintero/html/" :recursive t :publishing-function org-publish-attachment) ("kvintero" :components ("fuentes-org" "org-auxiliares"))))
La primera línea no necesita mucho que explicar: nos aseguramos que
está en el sistema el paquete que proporciona ox-publish
. Después de
esa primera forma, nos encontramos con otra que establece la lista de
proyectos para publicar. Cada elemento de la lista tiene una forma
general tal que:
("nombre-proyecto" ...)
Vamos a analizarlo un poco más despacio.
Proyectos de publicación
El primer elemento de la lista trata con los fuentes. Establece cuál
es su directorio base en :base-directory
. Vemos que coincide también
con el segundo elemento. En él buscará los ficheros con los que debe
trabajar. Como se puede observar el valor se establede al lugar donde
se encuentran los ficheros que fuentes-org
debe tratar o trabajar.
En :base-extension
se especifica de qué tipo son los ficheros tiene
que procesar. Si nos fijamos en la primera forma la extensión es
única: org
, pero en la segunda se establece una lista de extensiones
separadas por \\|
. Lo siguiente que se necesita es el lugar donde se
depositará el resultado del proceso y se pone en
:publishing-directory
. En este caso es un directorio local, pero
también se puede configurar un path
con el formato que entienda
tramp
, por ejemplo: /ssh:usuario@host:path/al/sitio
. También se
pueden especificar ficheros que se ignorarán durante el proceso con
otras variables, si necesitas esta información: mira en la
documentación de org-mode
.
Está previsto que se puedan meter otros directorios dentro del
directorio base para gestionar diferentes subproyectos y queremos
que se procesen todos, guardando la estructura. Para permitir que se
publiquen todos esos subproyectos hay que establecer :recursive
a
t
y el sistema analizará también todos los subdirectorios que se
encuentren dentro del base.
Por último, en :publish-function
se establece qué función procesará
los ficheros. En el primer caso se quiere que se convierta el fichero
procesado a html
y para ello que se utilice la función
org-html-publish-to-html
. En el segundo caso queremos que copie los
ficheros nada más y por eso se establece a org-publish-attachment
.
Hay más opciones que configurar si se necesitan: funciones que se
ejecuten antes o después de la publicación, por ejemplo, y muchas
otras opciones. Vuelvo a recomendar que le echéis un vistazo a la
documentación de org-mode
.
La tercera de las formas, que antes no la he mencionado, es un conjunto de ambas, especificado por una lista de componentes. Llamando a ésta, se llama a las dos anteriores.
Luego en el texto del proyecto hay que recordar enlazar de forma relativa a la estructura de directorios. Además también se pueden enlazar lugares concretos de un fichero. Ya sé que lo sabéis pero está bien recordarlo. Para hacerlo suelo utilizar las formas:
[[file:cualquier.org::*Título de apartado][Texto mostrado]] [[file:cualquier.org::#id-definido][Texto mostrado]] [[file:cualquier.org::mi objetivo][Texto mostrado]]
El formato con *Título de apartado
busca entre los títulos de
sección que contenga el fichero el que coincida con Título de
apartado. Con #id-definido
se busca un elemento que en sus
propiedades contenga #+name: id-definido
. Y por último, si quieres
saltar a algún sitio situado en medio de un documento, que no tiene
lista de propiedades donde ponerle nombre, se puede utilizar la forma
<<mi objetivo>>
, en el texto y se enlaza de la tercera forma.
Como digo, supongo que todos esos detalles ya los conocéis, al menos
quienes utilizáis habitualmente org-mode
, pero, ─como digo─, no está
de más repasarlo.
Plantillas y documentos
Una forma de estandarizar y ahorrar tiempo en la publicación de los
ficheros org
, tanto en html
como en pdf
es proporcionar al
sistema una plantilla que haga las veces de configuración de la
página, estableciendo los valores oportunos. En esas plantillas lo que
se hace, normalmente, es situar todas las opciones que pondríamos en
la cabecera que sean comunes a todas las páginas. Para este proyecto
he preparado la siguiente cabecera:
#+author: Notxor #+email: notxor@nueva-actitud.org #+options: ':t *:t -:t ::t <:t H:3 \n:nil ^:t arch:headline author:t c:nil #+options: creator:comment d:(not LOGBOOK) date:t e:t email:nil f:t inline:t #+options: num:t p:nil pri:nil stat:t tags:t tasks:t tex:t timestamp:t toc:t #+language: es #+exclude_tags: noexport #+select_tags: export #+options: html-postamble:auto html-postamble:nil tex:t #+html_container: div #+html_doctype: xhtml-strict #+html_head: <link rel="stylesheet" type="text/css" href="css/tus-estilos-favoritos.css" />
Todos esos valores comunes pueden cambiar en un momento dado, porque
se quiera mostrar una determinada página con otra hoja de estilos o
porque varíen los paths, o por cualquier otro motivo. Estas cosas
harán que necesitemos más tipos de cabecera. Por ejemplo, si creamos
un subdirectorio dentro de nuestro sitio base y utilizamos la misma
cabecera para publicar el sitio, no encontrará el fichero .css
,
necesitamos cambiar la última línea a:
#+html_head: <link rel="stylesheet" type="text/css" href="../css/style.css" />
Modificando el path en el que debe buscar la hoja de estilos.
Si ya tenemos una plantilla en la que basarnos, generar las demás que nos hagan falta es tan sencillo como copiar la plantilla-base y modificar los valores que queramos cambiar... y llamaremos a dicha plantilla desde el fichero que queramos con el formato:
#+setupfile: ../plantilla/plantilla-base.org #+title: Este es el Título #+subtitle: y este el Subtítulo
Como se puede apreciar, la cabecera queda resumida a dos o tres
líneas, muchas veces será suficiente establecer el #+setupfile:
, o
como mucho añadirle un título.
Otro factor a destacar es que establecemos que utilizando la etiqueta
noexport
se puede eliminar todo un árbol interno del documento
cuando lo exportamos.
* Notas :noexport: Esta información no se exportará al fichero ~html~
Hoja de estilos
Antes de meternos en un pequeño tutorial, que consistirá en que iré
haciendo algunos pasos para la creación de un sitio y, si quieres,
puedas irlos siguiendo para comprobar que todo funciona. También
necesitas una hoja de estilos que nos sirva de punto de partida. Por
Internet ha muchos ficheros css
para la exportación de org-mode
publicados, puedes utilizar el que más te guste... si eres vago como
yo, puedes descargarte el que voy a utilizar en el proyecto de:
http://thomasf.github.io/solarized-css
es el mismo que utilicé en aquella prueba sin hacerle ninguna
modificación. Sin embargo, esta vez sí le haré cambios. En la web, el
autor, recomienda el uso de un enlace directo al sitio de Internet.
Pero, es una hoja destinada a mostrar sólo una estructura org
, más
como agenda, y no para publicar documentos. Además quiero ajustar las
fuentes y otros parámetros. Por eso descargo el fichero y luego iré
contando las modificaciones que le haré, según avance el tutorial.
Puedes elegir entre dos temas de color:
solarized-dark

solarized-light

Particularmente me gusta más el solarized-light
y será el que
utilice. No olvidéis modificar en la plantilla el nombre de la hoja de
estilo que más te guste. Prefiero siempre partir de una hoja de
estilos ya creada y modificarla que crear una desde cero.
Publicación
Yo comenzaré con un pequeño fichero de texto en formato org
para
empezar el proyecto, cualquier texto vale, yo he preparado estos
pequeños párrafos para comenzar:
#+setupfile: ../plantillas/plantilla-base.org #+title: Kvintero ─ Introducción Dos campanas tañieron al unísono cuando se abrió el arco iris. Los viajeros hubieran podido oír las dos, si hubieran prestado atención. Pero impactados por el viaje no las escucharon. La primera sonó escondida, como olvidada, oculta entre el ruido del tráfico y el ajetreo de la ciudad. La segunda sonó rotunda bajo las estrellas en una noche silenciosa, pero fue ignorada por aquellos que pudieron llegar a oírla. Su sonido rodó por los tejados de pizarra y paja, rebotó por las calles de piedra y acero, deshaciéndose en ecos hacia las montañas. Una tercera quiso sonar con ellas, pero rajada y rota apenas consiguió emitir un chirrido metálico. Sin embargo, ésta obtuvo más atención cuando lanzó su desafinado tañido. El /brujo/ abrió los ojos y sonrió con malicia. [[file:piedra.org][Continuar...]]
Comenzamos con los cambios:
El autor del css
utiliza la carga de fuentes desde la habitual URL
de gúguel, una política que no es de mi agrado. Yo, en cambio, he
bajado de Internet algunas fuentes de daFont, un sitio donde se
pueden encontrar fuentes de todo tipo y desde el que se pueden
descargar para uso personal. Cada uno se puede bajar las fuentes que
quiera, yo he bajado Feathergraphy, que es gratuita para uso
personal5, en los títulos y para el texto utilizaré la habitual
Linux Libertine que uso también como fuente principal en este
blog, y que tiene una licencia libre y se puede utilizar para
cualquier fin.
Los ficheros ttf
los he colocado en un directorio llamado fuentes
que no aparece en el árbol de directorios anterior, tenéis que
crearlo, copiar las fuente ahí e importarlas en el css
como sigue:
@font-face { font-family: "Libertine Regular"; src: url('../fuentes/LinLibertine_R.ttf') format('truetype'); font-weight: normal; font-style: normal; } @font-face { font-family: "Feathergraphy"; src: url('../fuentes/Feathergraphy2.ttf') format('truetype'); font-weight: normal; font-style: normal; }
El paso siguiente es modificar algunos estilos. En las cabeceras, se
añade una instrucción font-family: 'Feathergraphy'
y en el apartado
body
se añade font-family: 'Libertine Regular'
. Para ver el
resultado hay que publicarlo. Sigamos los siguientes pasos:
- Cargar el código que hicimos antes con el comando
M-x load-file
y seleccionado el ficherokvintero.el
que habíamos creado para tener la lista de proyectos para publicación. A partir de este momento, si estamos en un fichero
org
podemos emplear el comando de exportarC-c C-e
, ahora seleccionamos el apartado Publish (P
), ychoose project
(x
), elegimos el proyectokvintero
y se realiza la magia.Si no estamos en un fichero
org
, podemos utilizar el comandoM-x org-publish-project RET kvintero RET
.- Abrir el fichero en un navegador web. Obtendremos algo parecido a:

Vista la imagen, no me gusta cómo queda el título y voy a separarlo en
dos. La cabecera del fichero org
quedará así:
#+setupfile: ../plantillas/plantilla-base.org #+title: Kvintero * Introducción
Tras modificar el org
lo guardamos y volvemos a publicar el
proyecto, bien con C-c C-e
o con M-x org-publish-project
.
Volvemos a ver cómo ha reaccionado nuestro html
. El resultado
quedará como:

Bueno, parece que ha surtido efecto, pero me gusta menos aún: aparece un índice que no quiero y el título me lo numera... algo más hay que cambiar. Y lo que hay que cambiar está en la plantilla. En concreto en la línea:
#+options: num:t p:nil pri:nil stat:t tags:t tasks:t tex:t timestamp:t toc:t
Hay que cambiarla por:
#+options: num:nil p:nil pri:nil stat:t tags:t tasks:t tex:t timestamp:t toc:nil
Volvemos a publicar el proyecto por el método habitual. ¿Qué ha
ocurrido? ¿Nada? Pues sí, no ha ocurrido nada, porque hemos modificado
un fichero que no está dentro del proceso del proyecto. Para que tenga
efecto hay que rehacer todos los ficheros que enlacen la cabecera. Lo
que yo hago es entrar en el dired
, si tienes activado normalmente,
como yo el dired-sidebar
lo tienes a mano. Pasas a ese buffer,
seleccionas los ficheros, ─si son muchos, puedes seleccionar el
directorio entero─, pulsando m
para marcar y luego pulsas T
(obsérvese la mayúscula). Es lo mismo que hacer un touch
en una
consola, que es el otro método rápido. Si ahora repites el comando de
publicar el proyecto, el resultado será:

Poniendo una imagen
Voy a poner una imagen en el proyecto, más para ilustrar de otro modo cómo es el proceso de mantener un proyecto completo, el ir haciendo pequeñas modificaciones e ir viendo cómo se van produciendo los resultados.
Lo primero que necesito es encontrar una imagen. Yo me descargué una
fotografía de un menhir de Internet y le apliqué algunos filtros
con GIMP. Al final, el fichero .png
lo he copiado en el directorio
img
que cuelga del directorio base. Para cargar la imagen, se hace
como siempre en org-mode
.
#+setupfile: ../plantillas/plantilla-base.org #+title: Kvintero * Introducción [[file:img/menhir.png]]
Una vez introducido el enlace de la imagen, si queremos verla aparecer
en nuestro documento html
debemos publicar el proyecto. Como
seguramente estaremos aún en el fichero org
, la pulsación completa
será C-c C-e P x kvintero
y obtendremos algo así:

Está bien, pero es un poco soso. Vamos a darle un poco de vidilla
con la hoja de estilos, a ver si lo adornamos un poco. Primero, me
gustaría que la imagen se desplazara a la izquierda y el texto se
ajustara a ella mostrándose a la derecha, y no debajo. Eso es fácil de
hacer con css
.
.float-left { float: left; margin-right: 1em; } .float-right { float: right; margin-left: 1em; }
En principio me bastaba con float-left
, pero ya puestos, he creado
también float-right
para tenerlo disponible en el futuro. Así podré
manejar imágenes ajustándolas en uno de los laterales. Además añado un
margen en el lado donde irá el texto, para que no se junte en exceso a
la imagen.
Ya puestos a hacer cambios, ─y puesto que es un documento que hará las veces de /librojuego/─, me gustaría resaltar más algunos elementos, hacer que la primera letra del párrafo inicial se muestre más grande y remarcar la primera línea destacándola. Para esto he añadido un poco más de código a la hoja de estilos.
.p-inicio::first-line { font-weight: bold; color: rgba(0,0,0,0.85); } .p-inicio::first-letter { position: relative; padding-top: 0.1em; display: block; float: left; font-family: 'Feathergraphy'; font-weight: normal; font-size: 3.2em; line-height: 0.8em; color: #d33682; margin-right: 0.1em; }
La primera parte, .p-inicio::first-line
, establece que la primera
línea del párrafo se escriba en negrita y con un color negro con una
transparencia del 15%.
La segunda parte, .p-inicio::first-letter
, establece que la primera
letra del párrafo se muestre con un tamaña 3.2
veces el tamaño de
letra normal y que utilice el tipo de letra y el color del título.
Bueno, hechos los cambios necesitamos visualizarlos en nuestro
navegador favorito. Como seguramente seguiremos en el buffer donde
hemos hecho los cambios podemos publicar el proyecto utilizando la
combinación M-x org-publish-project RET kvintero RET
. El resultado
que debemos obtener sería algo así:

¿No? ¿No ha salido bien? Claro, hemos modificado la hoja de estilos, pero no le hemos dicho al documento qué estilos y dónde tiene que aplicarlos. Eso es fácil:
#+setupfile: ../plantillas/plantilla-base.org #+title: Kvintero * Introducción #+attr_html: :class float-left [[file:img/menhir.png]] #+attr_html: :class p-inicio Dos campanas tañieron al unísono cuando se abrió el arco iris. Los viajeros hubieran podido oír las dos, si hubieran prestado atención. Pero impactados por el viaje no las escucharon.
Delante del elemento del documento que queremos aplicar uno de los
estilos que acabamos de crear, utilizaremos el comentario especial
#+attr_html:
para establecer la :class
con el nombre que hayamos
puesto en la hoja de estilos. Si lo haces como está en el código
anterior y publicas el proyecto como venimos haciendo hasta ahora,
obtendrás los resultados como se mostraron arriba.
Por supuesto, ajustar todas estas cosas lleva su tiempo y es
recomendable utilizar las herramientas de desarrollador web que provea
el navegador que utilices. Yo normalmente estoy utilizando Falkon
:

Primero hago los ajustes ahí, probando colores, márgenes, fuentes, etc. y luego lo paso al código definitivo de la hoja de estilos.
Conclusiones
Publicar proyectos es una forma sencilla, pero potente de crear
contenido web que se puede emplear para muchas cosas desde
org-mode
. Una de los usos para desarrolladores es, generar la
documentación para colocarla en Internet o distribuirla con el
programa. Generar un epub
fácilmente. Tener un sitio de Internet
estático de una manera sencilla. También, en lugar de enfocar la
publicación a html
se puede enfocar a pdf
con LaTeX, o incluso
tener proyectos que generen la documentación en varios formatos:
info
, html
, pdf
, etc.
Hay un montón de aspectos que no he utilizado aquí, pero están
explicados en la documentación de org
.
Footnotes:
Protención a la Infancia Contra el Abuso https://asociacionpica.org
Club de Aventuras AD en http://www.caad.es/... sí, aún existe el foro.
Su significado sería Quinta Tierra: en Esperanto Kvin significa 5 y Tero, Tierra.
Hay una explicación completa de dichas anclas en el apartado
4.8 Search Options in File Links del manual de org-mode
.
Si la vas a emplear para algún proyecto profesional, que no se te olvide pagar los pocos euros que cuesta.
Comentarios