Resaltado de sintaxis de código minimalista

Resaltado de sintaxis de código minimalista

En un artículo anterior [este: Cmder: La consola para Windows] te contábamos que nosotros estamos utilizamos el CMS Publii para generar el sitio en donde estas parado.

Publii es excelente. Punto. Tenemos pensando sacar una serie de artículos dedicados exclusivamente a Publii, cubriendo desde su funcionamiento básico hasta las creación de templates para el CMS.

Tabla de contenidos

Buscando la mejor manera de incluir código en nuestros artículos para que se vea "bonito", estuvimos evaluando varias alternativas, dado que Publii no integra (al menos a mayo de 2021) un syntax highlighter que permita, desde el editor, resaltar código fuente de diferentes lenguajes de programación.

Hay un issue en el repo del proyecto dedicado específicamente a este tema: Syntax highlighter?

Dentro de todas las alternativas que los usuarios ofrecen en el issue, encontramos una que se adapta a nuestro estilo pragmático y funcional (un eufemismo para perezoso), y es la solución propuesta por el usuario tcamde.

Básicamente tcamde propone lo siguiente:

"No quería añadir ese JS y CSS extra en cada página sólo para resaltar ocasionalmente el código. Así que uso esta solución:

  1. Copiar el código
  2. Pegar en alguna herramienta de resaltado de código en línea, por ejemplo, Syntax highlighter
  3. Obtenga el HTML de salida con estilos en línea
  4. Copie esto en su contenido como fragmento de HTML

Me funciona muy bien y es mucho más pequeño"

Lo que llamamos una solución minimalista. En vez de tener que lidiar con inclusiones de librerías JS, que se pueden romper cuando se cambia de versión de Publii y que genera más carga al sitio, simplemente generamos un HTML con estilo embebido a partir de la entrada, que puede ser un trozo de código de [casi] cualquiera de los lenguajes de programación más populares, que son, entre otros, los siguientes:

  • arduino
  • armasm (arm)
  • xml (html, xhtml, rss, atom, xjb, xsd, xsl, plist)
  • asciidoc (adoc)
  • aspectj
  • autohotkey
  • autoit
  • cmake (cmake.in)
  • csp
  • css
  • d
  • markdown (md, mkdown, mkd)
  • dart
  • ruby (rb, gemspec, podspec, thor, irb)
  • erb
  • erlang-repl
  • erlang (erl)
  • fix
  • go (golang)
  • golo
  • gradle
  • groovy
  • haml
  • handlebars (hbs, html.hbs, html.handlebars)
  • haskell (hs)
  • haxe (hx)
  • hsp
  • htmlbars
    http (https)
  • inform7 (i7)
  • ini (toml)
  • irpf90
  • java (jsp)
  • javascript (js, jsx)
  • json
  • julia
  • kotlin
  • lasso (ls, lassoscript)
  • mipsasm (mips)
  • mizar
  • perl (pl, pm)
  • mojolicious
  • monkey
  • moonscript (moon)
  • nginx (nginxconf)
  • nimrod (nim)
  • nix (nixos)
  • nsis
  • objectivec (mm, objc, obj-c)
  • ocaml (ml)
  • openscad (scad)
  • oxygene
  • parser3
  • pf (pf.conf)
  • php (php3, php4, php5, php6)
  • powershell (ps)
  • processing
  • profile
  • prolog
  • protobuf
  • puppet (pp)
  • purebasic (pb, pbi)
  • python (py, gyp)
  • q (k, kdb)
  • qml (qt)
  • r
  • rib
  • roboconf (graph, instances)
  • rsl
  • ruleslanguage
  • rust (rs)
  • scala
  • scheme
  • scilab (sci)
  • scss
  • smali (smali)
  • smalltalk (st)
  • sml (ml)
  • sqf (sqf)

¿Cómo se usa Online Syntax Higlighter?

El uso de Online Syntax Higlighter es muy sencillo. Para mostrar su funcionamiento vamos a utilizar código de la página Rosetta Code; seleccionar algunos de los lenguajes soportados y copiar y pegar en este artículo el resultado en HTML con los diferentes temas (estilos visuales) disponibles en la herramienta. Empecemos.

Primero mostraremos el procedimiento. Queremos convertir esta función JS en algo con más estilo, con colores y todo eso:

function factorial(n) {
//check our edge case
if (n < 0) { throw "Number must be non-negative"; }

var result = 1;
//we skip zero and one since both are 1 and are identity
while (n > 1) {
result *= n;
n--;
}
return result;
}
  1. Copiamos y pegamos el código en el textarea Unhighlighted Code.
  2. Seleccionamos el lenguaje.
  3. Seleccionamos el estilo.
  4. Presionamos el botón HIGHLIGHT!
  5. Copiamos el código HTML retornado.

El resultado es el siguiente:

Código: Javascript

Tema: Default

function factorial(n) {
//check our edge case
if (n < 0) { throw "Number must be non-negative"; }
 
var result = 1;
//we skip zero and one since both are 1 and are identity
while (n > 1) {
result *= n;
n--;
}
return result;
}

Tema: Androidstudio

function factorial(n) {
//check our edge case
if (n < 0) { throw "Number must be non-negative"; }
 
var result = 1;
//we skip zero and one since both are 1 and are identity
while (n > 1) {
result *= n;
n--;
}
return result;
}

Código: Groovy

Tema: Atelier Cave Dark

def rFact
rFact = { (it > 1) ? it * rFact(it - 1) : 1 as BigInteger }

Tema: Atelier Forest Light

def rFact
rFact = { (it > 1) ? it * rFact(it - 1) : 1 as BigInteger }

Código: Haskell

Tema: Codepen Embed

fac n
    | n >= 0    = go 1 n
    | otherwise = error "Negative factorial!"
        where go acc 0 = acc
              go acc n = go (acc * n) (n - 1)

Tema: Codepen Embed

fac n
    | n >= 0    = go 1 n
    | otherwise = error "Negative factorial!"
        where go acc 0 = acc
              go acc n = go (acc * n) (n - 1)

Código: Julia

Tema: Dark

function fact(n::Integer)
    n < 0 && return zero(n)
    f = one(n)
    for i in 2:n
        f *= i
    end
    return f
end
 
for i in 10:20
	println("$i -> ", fact(i))
end

Tema: Dracula

function fact(n::Integer)
    n < 0 && return zero(n)
    f = one(n)
    for i in 2:n
        f *= i
    end
    return f
end
 
for i in 10:20
	println("$i -> ", fact(i))
end

Código: Julia

Tema: Github

fun facti(n: Int) = when {
    n < 0 -> throw IllegalArgumentException("negative numbers not allowed")
    else  -> {
        var ans = 1L
        for (i in 2..n) ans *= i
        ans
    }
}
 
fun factr(n: Int): Long = when {
    n < 0 -> throw IllegalArgumentException("negative numbers not allowed")
    n < 2 -> 1L
    else  -> n * factr(n - 1)
}
 
fun main(args: Array<String>) {
    val n = 20
    println("$n! = " + facti(n))
    println("$n! = " + factr(n))
}

Tema: Gruvbox Dark

fun facti(n: Int) = when {
    n < 0 -> throw IllegalArgumentException("negative numbers not allowed")
    else  -> {
        var ans = 1L
        for (i in 2..n) ans *= i
        ans
    }
}
 
fun factr(n: Int): Long = when {
    n < 0 -> throw IllegalArgumentException("negative numbers not allowed")
    n < 2 -> 1L
    else  -> n * factr(n - 1)
}
 
fun main(args: Array<String>) {
    val n = 20
    println("$n! = " + facti(n))
    println("$n! = " + factr(n))
}

Código: Java

Tema: Gruvbox Light

import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.Scanner;
 
public class LargeFactorial {
    public static long userInput;
    public static void main(String[]args){
        Scanner input = new Scanner(System.in);
        System.out.println("Input factorial integer base: ");
        try {
            userInput = input.nextLong();
            System.out.println(userInput + "! is\n" + factorial(userInput) + " using standard factorial method.");
            System.out.println(userInput + "! is\n" + factorialRec(userInput) + " using recursion method.");
        }catch(InputMismatchException x){
            System.out.println("Please give integral numbers.");
        }catch(StackOverflowError ex){
            if(userInput > 0) {
                System.out.println("Number too big.");
            }else{
                System.out.println("Please give non-negative(positive) numbers.");
            }
        }finally {
            System.exit(0);
        }
    }
    public static BigInteger factorialRec(long n){
        BigInteger result = BigInteger.ONE;
        return n == 0 ? result : result.multiply(BigInteger.valueOf(n)).multiply(factorial(n-1));
    }
    public static BigInteger factorial(long n){
        BigInteger result = BigInteger.ONE;
        for(int i = 1; i <= n; i++){
            result = result.multiply(BigInteger.valueOf(i));
        }
        return result;
    }
}

Tema: Monokai Sublime

import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.Scanner;
 
public class LargeFactorial {
    public static long userInput;
    public static void main(String[]args){
        Scanner input = new Scanner(System.in);
        System.out.println("Input factorial integer base: ");
        try {
            userInput = input.nextLong();
            System.out.println(userInput + "! is\n" + factorial(userInput) + " using standard factorial method.");
            System.out.println(userInput + "! is\n" + factorialRec(userInput) + " using recursion method.");
        }catch(InputMismatchException x){
            System.out.println("Please give integral numbers.");
        }catch(StackOverflowError ex){
            if(userInput > 0) {
                System.out.println("Number too big.");
            }else{
                System.out.println("Please give non-negative(positive) numbers.");
            }
        }finally {
            System.exit(0);
        }
    }
    public static BigInteger factorialRec(long n){
        BigInteger result = BigInteger.ONE;
        return n == 0 ? result : result.multiply(BigInteger.valueOf(n)).multiply(factorial(n-1));
    }
    public static BigInteger factorial(long n){
        BigInteger result = BigInteger.ONE;
        for(int i = 1; i <= n; i++){
            result = result.multiply(BigInteger.valueOf(i));
        }
        return result;
    }
}

A modo resumen sobre resaltado de sintaxis de código minimalista

Las cosas solían ser tan sencillas. Con HTML y un poco de AJAX tenías suficiente para armarte un buen front end, pero parece que algunas cosas tienen que complicarse, y cada tanto un grupo de iluminados crea el nuevo super framework para hacer más complicado lo que se puede resolver con las herramientas que ya tenemos, pero bueno, esta discusión la dejamos para otro momento...


[La foto de portada es de Florian Olivo]

 


/ Súmate al boletín. No es gran cosa, pero es gratis 👇 /


— Ojo, son avisos 👇—
— Fin de los avisos —