forked from sejo/compudanzas
374 lines
9.0 KiB
Awk
374 lines
9.0 KiB
Awk
# gemtext2html
|
|
# convierte un archivo en gemtext a html de acuerdo a la spec
|
|
# excepción: enlaces a imagen (jpg, png, gif) se vuelven <img>
|
|
# TODO actualizar descripción
|
|
# TODO h2 en nav?
|
|
#
|
|
# importante: solo un {wikilink} (con o sin espacios) por línea
|
|
#
|
|
# modo de uso:
|
|
# awk -f gemtext2html.awk archivo.gmo > archivo.html
|
|
#
|
|
|
|
BEGIN{
|
|
sitio = "compudanzas"
|
|
descripcion = "explorations of computing at a human scale"
|
|
# para poder abrir y cerrar <ul>, <pre>, <p>:
|
|
modo_lista = 0
|
|
modo_pre = 0
|
|
modo_parrafo = 0
|
|
modo_galeria = 0
|
|
|
|
en_section = 1 #empezamos abriendo una <section> sin h1
|
|
|
|
navcount = 0
|
|
|
|
bloque = 0 # para no agregar <br/> después de headers y blockquotes
|
|
|
|
print "<!DOCTYPE html>"
|
|
print "<html xmlns='http://www.w3.org/1999/xhtml' lang='es-MX,en'>"
|
|
print "<head>"
|
|
print "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />"
|
|
print "<meta content='initial-scale=1.0' name='viewport'/>"
|
|
#
|
|
print "<link rel='me' href='https://sunbeam.city/@compudanzas'>"
|
|
print "<link rel='me' href='https://post.lurk.org/@compudanzas'>"
|
|
print "<link rel='me' href='https://merveilles.town/@sejo'>"
|
|
print "<link rel='stylesheet' href='./static/estilo.css'>"
|
|
print " <link rel='icon' href='./img/iconocompudanzas_16.png' type='image/png' sizes='16x16'> "
|
|
print " <link rel='icon' href='./img/iconocompudanzas_32.png' type='image/png' sizes='32x32'> "
|
|
print " <link rel='icon' href='./img/iconocompudanzas_64.png' type='image/png' sizes='64x64'> "
|
|
|
|
print "<meta property='og:type' content='website' />"
|
|
print "<meta property='og:image' content='https://compudanzas.net/img/iconocompudanzas_128_w.png'>"
|
|
|
|
contenido = "<main><section>"
|
|
nav = "<nav><ul>"
|
|
}
|
|
|
|
function appendContenido( t ){
|
|
contenido = contenido t "\n"
|
|
}
|
|
function appendNav( t ){
|
|
nav = nav t "\n"
|
|
navcount++
|
|
}
|
|
|
|
function wikiLink( t ){
|
|
i = match( t, /{.+}/)
|
|
if ( i ){
|
|
ifinal = index(t, "}") # índice del } final
|
|
|
|
prev = substr(t, 1, i-1) # string previa al link
|
|
# link = substr(t, i, ifinal-i+1) # {link}
|
|
nombre = substr(t, i+1, ifinal-i-1) # link
|
|
link = nombre
|
|
nombre = nombre2Link( nombre, "_" )
|
|
|
|
post = substr(t, ifinal+1) # string posterior
|
|
|
|
return prev "<a href='./" nombre ".html'>" link "</a>" post
|
|
}
|
|
else{
|
|
return t
|
|
}
|
|
}
|
|
|
|
function nombre2Link( t, r ){ # convierte un nombre con espacios, a uno con r (e.g. "_"
|
|
gsub(" ",r,t);
|
|
return t
|
|
}
|
|
|
|
|
|
NR == 1{
|
|
titulo = $0
|
|
sub("#[[:blank:]]+","",titulo) #prefijo
|
|
|
|
archivo = FILENAME
|
|
sub(/^.+\//,"",archivo) # remove path from filename
|
|
sub(/.gmo$/,".html",archivo) #change extension
|
|
|
|
print "<meta property='og:title' content='" sitio " — " titulo "'>"
|
|
print "<meta property='og:description' content='" descripcion "'>"
|
|
print "<meta name='description' content='" descripcion "'>"
|
|
print "<meta property='og:url' content='https://compudanzas.net/" archivo "'>"
|
|
|
|
|
|
print "<title>" sitio " — " titulo "</title>"
|
|
print "</head>"
|
|
print "<body>"
|
|
print "<header>"
|
|
print "<p><a class='icon' href='./home.html' title='" sitio "'><img src='./img/iconocompudanzas_32.png' style='margin:0' alt='icono de compudanzas'/></a></p>"
|
|
print "<h1>"titulo"</h1>"
|
|
print "</header>"
|
|
|
|
bloque = 1
|
|
|
|
next # lee la siguiente línea
|
|
}
|
|
|
|
|
|
|
|
/^\+ /{ # include literal
|
|
sub(/^+ /,"",$0) # elimina el +
|
|
appendContenido( $0 )
|
|
next
|
|
}
|
|
|
|
/^&/{ # include literal gemtext
|
|
next
|
|
}
|
|
|
|
/^[[:blank:]]*$/ { # línea vacía
|
|
if( !modo_pre ) {
|
|
if( modo_lista ){ # cierra la lista
|
|
modo_lista = 0
|
|
appendContenido( "</ul>" )
|
|
}
|
|
else if( modo_parrafo ){ # cierra el párrafo
|
|
modo_parrafo = 0
|
|
appendContenido( "</p>" )
|
|
}
|
|
else if( modo_galeria ){
|
|
modo_galeria = 0
|
|
appendContenido( "</gallery>" )
|
|
}
|
|
# else
|
|
# appendContenido( "<br/>" )
|
|
if( bloque ) # si lo previo fue header o blockquote
|
|
bloque = 0;
|
|
|
|
}
|
|
else
|
|
appendContenido( $0 )
|
|
next
|
|
}
|
|
|
|
/^=>/{ # link
|
|
if(!modo_pre){
|
|
if( modo_lista ){ # cierra la lista
|
|
modo_lista = 0
|
|
appendContenido( "</ul>" )
|
|
}
|
|
else if( modo_parrafo ){ # cierra el párrafo
|
|
modo_parrafo = 0
|
|
appendContenido( "</p>" )
|
|
}
|
|
|
|
bloque = 1 #empieza bloque porque es <p>
|
|
|
|
# borra flecha del inicio
|
|
sub("^=>","",$0)
|
|
# ahora $1 es el path, $2 a $NF el texto
|
|
|
|
# concatena todo el texto
|
|
texto = $2
|
|
for(i=3; i<=NF; i++){
|
|
texto = texto" "$i
|
|
}
|
|
|
|
if( match($1, /^\.\//)) { # si es link local
|
|
# si el path es imagen
|
|
if( match($1, /(png|jpg|gif)$/) ){
|
|
# crea imagen <img>
|
|
if( !modo_galeria ){
|
|
appendContenido("<gallery>")
|
|
modo_galeria = 1
|
|
}
|
|
appendContenido("<img src='"$1"' alt=\""texto"\" loading='lazy'/>")
|
|
}
|
|
# si el path no es imagen y es .gmi
|
|
else if( match($1, /gmi$/) ){
|
|
# convierte enlace de .gmi a .html !
|
|
sub(".gmi$",".html",$1)
|
|
|
|
# quita { }
|
|
sub("{","",texto)
|
|
sub("}","",texto)
|
|
|
|
# crea link <a>
|
|
appendContenido("<p><a href='"$1"' class=arrow>"texto"</a></p>")
|
|
}
|
|
else{
|
|
appendContenido("<p><a href='"$1"' class=arrow>"texto"</a></p>")
|
|
}
|
|
}
|
|
else{ # link externo
|
|
appendContenido("<p><a href='"$1"' rel='external noreferrer noopener' target=_blank class=arrow>"texto"</a></p>")
|
|
}
|
|
}
|
|
else{
|
|
appendContenido( $0 )
|
|
}
|
|
next
|
|
}
|
|
|
|
/^* /{ # lista
|
|
if(!modo_pre){
|
|
if(!modo_lista){ # inicia la lista
|
|
if(modo_parrafo){
|
|
modo_parrafo = 0
|
|
appendContenido( "</p>" )
|
|
}
|
|
modo_lista = 1
|
|
appendContenido( "<ul>" )
|
|
}
|
|
sub("*[[:blank:]]+","<li>",$0)
|
|
sub("$","</li>",$0)
|
|
appendContenido( wikiLink($0) )
|
|
}
|
|
else
|
|
appendContenido( $0 )
|
|
next
|
|
}
|
|
|
|
/^```/{ # preformatted
|
|
if(modo_pre){
|
|
# cierra preformatted
|
|
modo_pre = 0
|
|
appendContenido( "</pre>" )
|
|
}
|
|
else{
|
|
if( modo_lista ){ # cierra la lista
|
|
modo_lista = 0
|
|
appendContenido( "</ul>" )
|
|
}
|
|
else if( modo_parrafo ){ # cierra el párrafo
|
|
modo_parrafo = 0
|
|
appendContenido( "</p>" )
|
|
}
|
|
|
|
# abre preformatted
|
|
modo_pre = 1
|
|
appendContenido( "<pre>" )
|
|
}
|
|
next
|
|
}
|
|
|
|
/^> /{ # blockquote
|
|
if(!modo_pre){
|
|
sub(">[[:blank:]]+","<blockquote>",$0)
|
|
sub("$","</blockquote>",$0)
|
|
bloque = 1
|
|
}
|
|
appendContenido( $0 )
|
|
next
|
|
}
|
|
|
|
/^# /{ # h1
|
|
if(!modo_pre){
|
|
sub("#[[:blank:]]+","",$0) #prefijo
|
|
sub("$","",$0) #sufijo
|
|
bloque = 1
|
|
|
|
if( !en_section ){ # si no se ha iniciado una sección antes
|
|
appendContenido( "<section>" )
|
|
en_section = 1
|
|
}
|
|
else{
|
|
appendContenido( "</section><section>" )
|
|
}
|
|
|
|
# crea header con id
|
|
appendContenido( "<h1 id='"$0"'>"$0"</h1>" )
|
|
|
|
# agrega header a navegación
|
|
appendNav( "<li><a href='#"$0"'>"$0"</a></li>" )
|
|
}
|
|
else{
|
|
appendContenido( $0 )
|
|
}
|
|
next
|
|
|
|
}
|
|
|
|
/^## /{ # h2
|
|
if(!modo_pre){
|
|
sub("##[[:blank:]]+","",$0)
|
|
sub("$","",$0)
|
|
# crea header con id
|
|
appendContenido( "<h2 id='"$0"'>"$0"</h2>" )
|
|
bloque = 1
|
|
}
|
|
else{
|
|
appendContenido( $0 )
|
|
}
|
|
next
|
|
}
|
|
|
|
/^### /{ # h3
|
|
if(!modo_pre){
|
|
sub("###[[:blank:]]+","",$0)
|
|
sub("$","",$0)
|
|
appendContenido( "<h3 id='"$0"'>"$0"</h3>" )
|
|
bloque = 1
|
|
}
|
|
else{
|
|
appendContenido( $0 )
|
|
}
|
|
next
|
|
}
|
|
|
|
#$0 !~ /^(=>|```|#{1,3} |* |\+|>|[[:blank:]]*$)/{ # líneas de texto (no "especiales")
|
|
{ # cualquier otra línea de texto
|
|
if(!modo_pre){
|
|
if(!modo_parrafo){
|
|
modo_parrafo = 1
|
|
appendContenido( "<p>" )
|
|
}
|
|
else # nueva línea en el mismo párrafo
|
|
appendContenido( "<br/>" )
|
|
|
|
# busca y convierte wikiLink (máx uno por línea)
|
|
appendContenido( wikiLink($0) )
|
|
}
|
|
else{
|
|
gsub("<","\\<",$0)
|
|
gsub(">","\\>",$0)
|
|
appendContenido( $0 )
|
|
}
|
|
}
|
|
|
|
END{
|
|
# imprime y cierra nav
|
|
if(navcount){
|
|
print nav
|
|
print "</ul></nav>"
|
|
}
|
|
|
|
# imprime contenido
|
|
print contenido
|
|
# cierra tags que pudieron haber quedado abiertas
|
|
if(modo_pre)
|
|
print "</pre>"
|
|
else if(modo_parrafo)
|
|
print "</p>"
|
|
else if(modo_lista)
|
|
print "</ul>"
|
|
|
|
# finaliza...
|
|
print "</section>"
|
|
print "</main>"
|
|
print "<footer>"
|
|
# footer with filename:
|
|
sub("tmp/","",FILENAME)
|
|
print "<p>"
|
|
print "<a href='https://tildegit.org/sejo/compudanzas/src/branch/main/src/" FILENAME "' rel='external noreferrer noopener' target=_blank>source file</a> —"
|
|
print "most recent update: "
|
|
print "<time datetime='"fecha"'>1" fecha"</time> — "
|
|
sub(".gmo",".gmi",FILENAME)
|
|
print "<a href='gemini://compudanzas.net/" FILENAME "' rel='external noreferrer noopener' target=_blank>view in gemini://</a>"
|
|
print "</p><hr/>"
|
|
# links:
|
|
print "<p><a href='./about.html'>about</a> <a href='./contact.html'>contact</a> <a href='./support.html'>support</a></p>"
|
|
# print "<p><a href='https://webring.xxiivv.com/#random' target='_blank' title='webring' rel='external noreferrer noopener'>webring</a>"
|
|
print "<p><a class='icon' href='./home.html' title='" sitio "'><img src='./img/iconocompudanzas_32.png' width=32 height=32 alt='icono de compudanzas'/></a>"
|
|
print "<a href='https://webring.xxiivv.com/#random' target='_blank' title='webring'><img src='./img/icon.black.svg' width='32' height='32' alt='xxiivv webring'/></a></p>"
|
|
|
|
print "<p><a href='https://post.lurk.org/@compudanzas' target='_blank' title='mastodon' rel='external me noreferrer noopener'>@compudanzas</a></p>"
|
|
print "<p>texts, images, and code are shared with the <a href='https://wiki.p2pfoundation.net/Peer_Production_License' target=_blank rel='external noreferrer noopener' title='Peer Production License'>peer production license</a></p>"
|
|
print "</footer>"
|
|
print "</body>"
|
|
print "</html>"
|
|
}
|