Publicar con org-mode II
Este es un artículo de esos incoherentes en los que me dedico a
contestar preguntas y peticiones de aclaración. Ya en este blog
hablé de cómo publicar en html
con org-mode
, fue un artículo casi
a vuela pluma y rápido sin detenerme en detalles y eso ha propiciado
varias dudas. Además, algunos me habéis preguntado por más detalles
sobre la publicación y los distintos formatos en los que podemos
publicar. Además de detalles que hay que tener en cuenta. El
principal foco de atención han sido las plantillas, y particularmente
qué opciones de exportación son más aconsejables. También cómo
montar un servidor local para visualizar los cambios y hacer pruebas,
en el caso de que sea un proyecto para html
: bien sea un blog o
simplemente documentación. Y también cómo gestionar si se desea que la
salida se produzca en varios formatos, por ejemplo, html
y pdf
. Y
también si es mejor utilizar etiquetas include
o enlazar los
archivos. Algunas de estas preguntas tienen respuestas sencillas de
procedimiento, pero a otras sólo puedo contestar: depende. Ahora
bien, ese depende es lo que explico en adelante.
El depende principal es el de la salida que queremos obtener y en
función de esa salida debemos trabajar. Cuando el proyecto sólo se
publicará en un formato, no hay ningún problema: configuramos ese
formato y no hará falta más. Cuando hacemos cambios generamos la
salida y todo funcionará perfectamente. El problema viene cuando
queremos generar documentos de diverso tipo con sus diferentes
idiosincrasias. No hace falta rebuscar mucho, por ejemplo, si nos
fijamos en la manera en que html
y TeX
numeran sus cabeceras,
veremos que son significativamente distintas y que, por tanto,
necesito tener configuradas opciones distintas según el formato de
salida. ¿Eso complica las cosas? Pues un poco: necesitamos cabeceras
de exportación con opciones distintas, e incluso quizá diferentes
opciones de publicación. Ten en cuenta que exportación y
publicación, aunque lo pueda parecer de primeras, no son sinónimos
para mí.
Efectivamente, podemos separar lo que significa convertir nuestro
documento org
en otro formato, ─eso es exportación─, de lo que
significa facilitar el acceso al contenido, ─que es la publicación─.
Si te has perdido un poco, espero que lo entiendas con el ejemplo.
Vamos a imaginar que queremos generar una documentación de algún
proyecto es una especie de wiki donde las distintas páginas
estarán enlazadas mediante enlaces, valga la rebuznancia, entre
ficheros org
. Exportar esta wiki a formato html
es sencillo:
sólo hay que seguir los pasos del artículo donde explicaba como
publicar html
desde org-mode
. Como todo ya está explicado en ese
artículo no voy a dar muchos detalles: se ponen enlaces entre los
archivos org
y recordamos activar :recursive t
en las opciones de
publicación del proyecto, ya está todo listo... Pero, opciones de
publicación... opciones de exportación... ¡uff! ¿de qué va todo
esto?
Opciones de exportación
Algunos me dicen que copian las cabeceras de sus documentos org
1 y no
entienden por qué unas veces les muestra bien los subíndices, como en
H2O ─por poner un ejemplo─, y otras veces muestra algo como H_2O o
incluso H2O, sin ninguna explicación aparente. La respuesta a ese
gran enigma es que estás copiando las opciones sin saber qué
significan y qué comportamientos controlan. Revisa la documentación
de org-mode
, ahí está todo explicado. Pero si te da pereza sigue
leyendo un poco.
La manera más rápida de generar una plantilla de exportación es copiar una ya hecha. Sin embargo, algunas veces nos encontramos con líneas como la siguiente:
#+options: H:3 num:nil toc:nil \n:nil ::nil |:t ^:{} -:nil f:t *:t <:t
Nos puede parecer algo esotérico y casi mágico, que casi da miedo
tocar para no cagarla, pero tenemos que ser conscientes que cada
elemento de esa lista tiene efectos sobre el documento
generado. Además esos elementos se circunscriben al fichero en
cuestión y sólo afectan a la exportación del mismo. Utilizar otras
opciones, para otros contenidos es lo que hace que la utilidad de las
plantillas sea increíble. Por ejemplo, en la exportación a html
podemos no necesitar tener el índice de los apartados, ─especialmente
si lo vamos a tratar como páginas web enlazadas─, pero al generar la
salida para pdf
con los mismos archivos, nos puede parecer
imprescindible. Lo más rápido será tener plantillas para generar
html
y para generar pdf
... además, al generar así los html
querremos que se creen un montón de ficheros con una determinada
estructura, mientras que para el pdf
lo querremos todo en un archivo
monolítico. Bien, vale, pero me estoy enrollando. Vamos con las
opciones, no voy a ser exhaustivo, porque están bien explicadas en la
documentación de org-mode
. Voy a explicar, brevemente las que he
puesto en el ejemplo anterior y alguna más porque la considero
importante conocer.
H
- Establece el número de niveles de cabecera que se exportarán
como tal. A partir del número expresado, el resto de cabeceras
org
se exportarán como elementos de una lista. num
- Establece si queremos que las cabeceras se numeren al
exportar. Un valor de
nil
hará que se omita el número. También podemos tenerlo activado mediantet
y si, en el documento, queremos que algún apartado no sea numerado se le puede añadir una propiedad (C-c C-x p
)UNNUMBERED
puesta at
. Si ponemos esa propiedad anotoc
, el apartado y todos sus subapartados no aparecerán tampoco en el índice de contenido. toc
- Establece si al exportar se generará un índice de contenido
para el fichero. Si en lugar de
nil
ot
aparece un número, lo que hace es limitar el nivel de encabezado que aparecerá en el índice de contenido. \n
- Establece si debe preservar los saltos de línea cuando realiza la exportación.
:
- Establece si las regiones de ancho fijo (que comienzan cada
línea con un carácter
:
y un espacio o retorno de carro) se exportan al fichero generado o se ocultan. Si establecemos el valor anil
, podemos utilizar estas secciones como si fueran comentarios dentro de nuestro ficheroorg
que luego no aparecerán en la salida. Podemos hacer algo similar con los drawers y la opciónd
. |
- Establece si exportará las tablas.
^
- Establece cómo se tratarán los subíndices y superíndices.
Los valores pueden ser
nil
,t
ó{}
. Los dos primeros desactivan y activan, respectivamente, la notación que emplea los caracteres_
para subíndices y^
para superíndices. La opción marcada con las llaves indica que sólo tendrá efecto, convertir a subíndice o superíndice, en aquellas cadenas que se encuentren entre llaves a continuación de uno de esos caracteres. -
- Activar o desactivar la conversión de cadenas especiales. Es
decir, si activamos esta opción la salida interpretará las cadenas
especiales
\-
,--
y---
. f
- Activa o desactiva la exportación de las notas a pie de página.
*
- Activa o desactiva la exportación de texto enfatizado, negrita, cursiva, etc.
<
- Activa o desactiva la inclusión de marcas de tiempo y fecha en la exportación.
Hay más y todas interesantes y están muy bien explicadas en la
documentación de org-mode
. Además, otra opción que me parece muy
importante es poder exportar el contenido con otro nombre. Como es
normal, por defecto, el contenido se exportará a un fichero con nombre
idéntico al fichero org
pero con la extensión adecuada: html
,
pdf
, etc.
Si como hemos visto antes, tenemos un fichero que realizará la
exportación a html
y otro a pdf
, no podemos llamar a los dos con
el mismo nombre, porque ya hemos visto que podemos necesitar
diferentes opciones de exportación. Por ejemplo, si tenemos un fichero
exportar-html.org
y otro exportar-pdf.org
, por defecto se
generarán los archivos de salida exportar-html.html
y
exportar-pdf.pdf
... feo ¿no? Nos gustaría obtener como resultado
exportar.html
y exportar.pdf
. ¿Cómo lo podemos hacer? Añadiendo en
cada fichero el nombre del fichero donde queremos exportar, por
ejemplo, en nuestro fichero exportar-html.org
:
#+setupfile: mi-plantilla-html.org #+export_file_name: exportar.html
Opciones de publicación
Mucho de lo que voy a hablar ahora, ya lo conté en el artículo sobre
publicar html
que dije antes. Voy a repetir algunas cosas, pero
añadiendo la opción de que queremos exportar tanto a html
en
ficheros distintos, como en pdf
en un fichero monolítico.
Mi costumbre, como ya conté, es tener en el proyecto un fichero
elisp
para configurar los proyectos de exportación y cargarlo según
lo necesite. Pongo aquí uno que podría servirnos de ejemplo, o
plantilla para nuestro proyecto de doble exportación:
(require 'ox-publish) (setq org-publish-project-alist '( ("org-to-html" :base-directory "~/proyectos/programa/documentacion/" :base-extension "org" :publishing-directory "~/proyectos/programa/docs/" :language es :publishing-function org-html-publish-to-html :exclude "documentacion-pdf.org" :recursive t :section-numbers nil :headline-levels 6 :html-preamble t) ("org-to-pdf" :base-directory "~/proyectos/programa/documentacion" :base-extension "org" :language es :publishing-directory "~/proyectos/programas/docs" :exclude "documentacion-html.org" :recursive nil :section-numbers t :publishing-function org-latex-publish-to-pdf :headline-levels 5) ("org-auxiliares" :base-directory "~/proyectos/programa/documentacion/" :base-extension "css\\|js\\|png\\|ttf\\|pdf" :publishing-directory "~/proyectos/programa/docs/" :recursive t :publishing-function org-publish-attachment) ("documentacion" :components ("org-to-html" "org-to-pdf" "org-auxiliares"))))
Ese código está planteado para una estructura tal que:
. ├── docs │ └── ... (directorio donde se publicará) ├── documentacion │ ├── documentacion-html.org │ └── documentacion-pdf.org ├── publicacion-docs.el ├── org │ ├── css │ │ └── ... (hojas de estilo) │ ├── img │ │ └── ... (ficheros de imagen) │ ├── js │ │ └── ... (ficheros javascript) │ └── ... (ficheros org) ├── plantillas │ ├── plantilla-html.org │ └── plantilla-pdf.org └── README.org
Como se puede ver, tenemos dos tipos de plantillas: para html
y para
pdf
. Dos tipos de ficheros fuente: para html
y para pdf
. ¿Cómo
evitamos que al exportar el sistema nos cree más salida de la que
necesitamos. Es decir, sólo necesitamos que se genere html
desde el
fichero documentación-html.org
y sólo necesitamos que se genere
pdf
desde el fichero documentación-pdf.org
. Para esto tenemos dos
proyectos de exportación: org-to-html
y org-to-pdf
. Pero vemos
que, aunque los contenidos al final serán los mismos las opciones
cambian. Especialmente hay que señalar que el otro generador es
excluido del proyecto. Cuando generamos html
queremos que utilice el
org
correspondiente e ignore el otro.
Montar un servidor local
Cuando trabajamos en un proyecto que se visualizará como una página
web es útil, muchas veces, contar con una manera de montar un
servidor local que actúe como si fuera un sitio de Internet general,
pero sólo accesible desde localhost (127.0.0.1)
. No tienes por qué
hacerlo desde Emacs si no quieres, pero ya que estás editando con
él, para qué lo vas a hacer desde fuera. Desde fuera hay muchas
maneras: hay lenguajes que proporcionan sus propios servidores
locales y que podemos utilizar.
Por ejemplo, en Python 3.x
:
python -m http.server 8080
En PHP
:
php -S localhost:8080
En Ruby
:
ruby -run -e httpd . -p 8080
El listado puede ser muy largo, porque parece que cada lenguaje que se
utiliza de uno u otro modo para programar para la web tiene un
sistema de hacerlo. En todos los casos anteriores se cuenta que el
lanzamiento se hace situándose en el directorio donde se encuentran
los ficheros de salida y utilizan, algunos sin mencionarlo, el
directorio actual (.
) para levantar un demonio httpd
. Además, en
todos los ejemplos anteriores se ha utilizado el puerto 8080
, pero
se podría utilizar cualquier otro al uso, recordando que los puertos
recomendados para los servicios, ─por ejemplo, 80
es el puerto
http
por defecto─, necesitan permisos de root para habilitarlos.
Es bastante cómodo tener el servidor levantado, al hacer cambios y generar la salida en su correspondiente directorio, podemos ir viendo el efecto de esos cambios con cualquier navegador.
En los ejemplos anteriores hemos podido ve que las herramientas para
montar servidores locales, necesitan todas un par de datos: el
directorio donde está la página y el puerto por el que servir el
contenido. Normalmente, en los ejemplos anteriores el directorio se
omite, porque se entiende que el comando se lanza desde una consola
estando situados en él. De la misma manera, en Emacs, necesitamos
especificar qué directorio y qué puerto queremos utilizar. Esto lo
hacemos con un poco de código elisp
. Por ejemplo, una de las
estrategias para configurar nuestro servidor local puede ser ajustar
los valores necesarios en el mismo fichero que cargábamos antes con
los proyectos de publicación, añadiendo las siguientes líneas:
(setq httpd-port 8080) (setq httpd-root "~/mi-directorio") (httpd-start)
Si sólo tienes un proyecto de publicación html
, lo puedes establecer
mediante M-x customize-group <RET> simple-httpd
. En todo caso, esas
tres líneas de código bastan para lanzar nuestro servidor. Las podemos
evaluar con el código del proyecto de publicación o tenerlas a mano en
algún buffer donde las podamos evaluar... o establecerlas una a una
con M-x
.
Flujo de trabajo
Más que por simple-httpd.es
, que es el fuente donde descansa nuestro
servidor, las preguntas estaban enfocadas al flujo de trabajo con
html
. Bien, hasta aquí hemos hablado de los primeros pasos:
- Crear el contenido con
org-mode
. - Publicar el contenido con las herramientas de Emacs.
- Servir los
html
desde un servidor local para visualizarlos.
¿Cómo seguimos? Cuando tenemos alguna modificación que comprobar la
publicamos y para eso, sólo hay que ir repitiendo los pasos del 1
al
3
y viéndolos en el navegador que más nos guste. Por otro lado, a
algunos no os gusta partir de un css
ya hecho, para ir modificando
los distintos aspectos del mismo. La justificación que me habéis dado
es válida: terminas con un css
con un montón de elementos que tiene
que cargar el navegador, pero que no son útiles. Por otro lado, además
de la declaración del css
que se incluye en la cabecera en la misma
aparece un apartado de style
, no sólo es que queda feo, es que ocupa
también. Se puede aligerar la cabecera desactivando la exportación de
esos valores mediante:
#+options: html-style: nil
Si queremos crear nuestro css
desde lo más básico a lo más general,
podemos observar dicha inclusión y tomarla como código básico para
exportación. Al menos, la exportación desde org-mode
establece las
siguientes clases específicas:
p.author
- Información del autor incluyendo el email.
p.date
- Fecha de publicación
p.creator
- Información sobre la versión de
org-mode
y Emacs. .title
- Título del documento.
.subtitle
- Subtítulo del documento.
.todo
- palabras clave
TODO
. .done
- palabras clave
DONE
. .WAITING
- clase para encabezados a la espera.
.timestamp
- etiqueta de tiempo.
.timestamp-kwd
- palabra clave asociada a una etiqueta de tiempo,
como
scheduled
. .timestamp-wrapper
- espacio alrededor de la etiqueta de tiempo y su palabra clave.
.tag
- Etiqueta en una cabecera. Típicamente las que aparecen a la derecha de la cabecera.
._HOME
- Cada etiqueta utilizándose como una clase, reemplazando
@
por_
.target
- objetivo para links.
.linenr
- número de línea en bloques de código
.code-highlighted
- líneas de código destacadas
div.outline-N
- Nivel de cabecera, donde
N
es un número (1
,2
, ...6
) div.outline-text-N
div
extra para el texto de la cabecera..section-number-N
- Número de sección de la cabecera.
.figure-number
- Etiqueta para las figuras tal que «Figure 1:»
.table-number
- Etiqueta para las tablas, tal que «Table 1:»
.listing-number
- Etiqueta para bloques de código «Listing 1:»
div.figure
- Clase para imágenes en líneas de texto.
pre.src
- Código fuente formateado.
pre.example
- bloques
example
p.verse
- Párrafos verse
div.footnotes
- Cabecera para la sección de notas al pie.
p.footnote
- Párrafo que contiene una nota al pie.
.footref
- Número de referencia de una nota al pie (siempre como
<sup>
). .footnum
- Número de una nota al pie (siempre como
<sup>
). .org-svg
- Clase por defecto para una imagen
.svg
enlazada.
¿Qué ocurre si quiero definir mis propias clases? Pues es algo
sencillo. Vamos a imaginar que quiero crear una clase para el css
que me formatee con un determinado estilo, por ejemplo, un aviso,
que haga que el texto se escriba en rojo para destacarlo. El código
css
es muy sencillo:
.aviso { color: #FF0000; }
Hacer que un párrafo de nuestro documento se muestre con el formato
para la clase aviso
es tan sencillo como escribir en nuestro fichero
org
:
...
#+attr_html: :class aviso
Este es un párrafo de aviso que mostrará el texto en rojo.
...
Si no quiero definir una clase y utilizar directamente las propiedades
de html
podría haber escrito el código así:
...
#+attr_html: :class aviso :style color:red;
Este es un párrafo de aviso que mostrará el texto en rojo.
...
Además de las clases mencionadas arriba, un css
básico debe contar
con definiciones para las etiquetas de texto habituales en un fichero
html
: <html>
, <body>
, <h1>
... <h6>
, <p>
, <em>
, <i>
,
<b>
, <table>
, <dt>
, <dh>
, <dd>
, <li>
, <ol>
, <ul>
,
<img>
... y también puede definir estilos especiales para dos tipos
de elementos marcados con id=
: #preamble
, #content
y
#postamble
.
De estos tres últimos elementos, nuestro fichero org
genera sólo,
por decirlo así, el content
. El pie y la cabecera están controladas
por variables:
org-html-preamble
- si no es
nil
genera un preámbulo con el contenido de la variableorg-html-preamble-format
. org-html-preamble-format
- cadena
html
que se mostrará en la exportación. Por defecto está vacía. org-html-postamble
- si no es
nil
genera un pie de página con el contenido de la variableorg-html-postamble-format
. org-html-postamble-format
cadena
html
que se mostrará. Por defecto, su valor se establece:(setq org-html-postamble-format '(("en" "<p class=\"author\">Author: %a (%e)</p> <p class=\"date\">Date: %d</p> <p class=\"creator\">%c</p> <p class=\"validation\">%v page</p>")))
Algunos sistemas de publicación, se basan en todas estas estructuras,
variables y métodos para generar sitios web estáticos. Por ejemplo,
org-static-blog
, con el que está hecho este blog, se basa en estos
procedimientos añadiéndoles un poco de funcionalidad mediante código
elisp
.
Conclusiones
Este no es un artículo muy coherente. He escrito sobre distintos
aspectos de lo mismo y hecho muchas referencias a un artículo anterior
que no tienes por qué haber leído. Sin embargo, espero que hayas
podido ver, o al menos intuir, toda la flexibilidad que tiene
org-mode
a la hora de exportar y publicar contenido.
Todo lo que he escrito lo he sacado de la documentación, por lo que la contestación rápida a las preguntas hubiera sido: lee el puto manual. Pero no me sale ser tan borde y prefiero contestar, porque muchas veces me obliga a buscar el porqué de las cosas y entender mejor lo que creía que ya sabía.
A veces, la necesidad de concisión hace que dé por sabido algo que parece no serlo. Eso es fuente de muchas de las preguntas que me hacéis y para las que, de vez en cuando, tampoco tengo una respuesta clara, porque yo también las puedo estar haciendo por inercia y sin leer el puto manual... así que: ¡gracias por las preguntas! Porque me obligan a buscar las respuestas.
Footnotes:
Hay quien me ha dicho: de sitios solventes como tu blog... ¿solvente mi blog? Revisa el concepto, por favor.
Comentarios