Lume Nueglow Plugin Demo

Demo GitHub jsDelivr

This is a Lume plugin to add support for Nueglow.

For example, here’s a quickstart script, highlighted with this plugin.

// _config.ts
import lume from "https://cdn.jsdelivr.net/gh/lumeland/lume/mod.ts";
import nueglow from "https://cdn.jsdelivr.net/gh/ethmarks/lume_nueglow@v1.1.1/mod.ts";

const site = lume();

site.use(nueglow());

export default site;

Themes

The biggest advantage of Nueglow is that it’s very easy to create custom themes. Rather than massive JSON files, Nueglow themes consist of only a handful of CSS custom properties:

[glow] {
  --glow-bg-color: #111729;
  --glow-font-color: #f0fbf9;
  --glow-primary-color: #8fdfd4;
  --glow-secondary-color: #aae7de;
  --glow-accent-color: #69cebf;
  --glow-special-color: #c5f0e9;
  --glow-base-color: #52b8a9;
  --glow-char-color: #3ca294;
  --glow-comment-color: #4a6360;
  --glow-counter-color: #2b7a6f;
  --glow-selected-color: #8fdfd426;
}

The example above is a Catppuccin-inspired theme, which you can see below:

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

It’s also easy to create themes that complement a brand color. For example, if your brand color is #8FDFD4, then you can create a monochromatic theme that uses different shades of your brand color.

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

Here’s a theme that I created by lazily combining random pastel colors:

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

A complete list of included themes is available at the Themes page.

Special Syntax

Nueglow has some special syntax for drawing attention to specific selections and lines.

If you wrap a selection in single bullet markers (e.g. •text•), Nueglow will surround it in <mark> tags. For example, look how fibonacci(num - 1) is highlighted in the example below.

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

If you wrap a selection in double bullet markers (e.g. ••text••), Nueglow will wrap it in <u> tags. This is typically used for drawing attention to errors. For example, look how num = 1 is underlined in the example below.

function fibonacci(num: number): number {
  if (num = 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

If you prefix a line with a greater than sign (>), Nueglow will wrap the whole line in <dfn> tags. For example, look how the return line is highlighted in the example below.

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

If you prefix a line with a minus sign (-) or plus sign (+), Nueglow will wrap the whole line in <del> or <ins> tags, respectively. For example, look at the diff below.

function fibonacci(num: number): number {
  if (num == 1) return 0;
  if (num == 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
  const minusOneFib = fibonacci(num - 1);
  const minusTwoFib = fibonacci(num - 2);
  return minusOneFib + minusTwoFib;
}

Languages

Nueglow supports every programming language because it uses heuristics rather than grammars. If it looks like code and uses code-y words like if and return, Nueglow can highlight it.

Here are a bunch of example snippetsSourced from https://github.com/nuejs/nue/blob/master/packages/nueglow/test/generate.js. for many different programming languages.

Astro
---
import MyComponent from "./MyComponent.astro";
const items = ["Dog", "Cat", "Platypus"];
---

<ul>
  {items.map((item) => (
    <li>{item}</li>
  ))}
</ul>

<!-- renders as <div>Hello!</div> -->
<Element>
  <p>Hello</p>
  <p>Hello!</p>
</Element>
C#
public void MyTaskAsync(string[] files) {

  MyTaskWorker worker = new MyTaskWorker(MyTaskWorker);
  AsyncCallback fooback = new AsyncCallback(MyTask);

  lock (_sync) {
    if (_myTaskIsRunning)
      throw new OperationException(
        "The control is busy."
      );

    // one-line comment here
    AsyncOperation async = Async.CreateOperation(null);
    bool cancelled;

    worker.BeginInvoke(files, context, out cancelled);

    _myTaskIsRunning = true;
    _myTaskContext = context;
  }
}
C++
#include <iostream>
using namespace std;

int main() {

  int first_number, second_number, sum;

  cout << "Enter two integers: ";
  cin >> first_number >> second_number;

  // sum of two numbers in stored
  sum = first_number + second_number;

  // prints sum
  cout << first_number << " + "
    <<  second_number << " = " << sum;

  return 0;
}
Clojure Script
(ns clojure.examples.hello
   (:genclass))

;; This program displays Hello World
(defn Example []
  (println [+ 1 2 3]))
(Example)

:dev-http {8080 "public"}
  :builds
  {:app
    {:target :browser
      :output-dir "public/app/js"
Crystal
# A very basic HTTP server
require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world, got #{context}"
end

puts "Listening http://127.0.0.1:8080"
server.listen(8080)
CSS
 "../css/dark.css";

/* Let's check out CSS code */
.syntax {
  border: 1px solid #fff1 !important;
  background-color: var(--base-600);
  border-radius: var(--radius);
  margin-bottom: 3em;

  (width < 900) {
    transform: scale(1.1);
    filter: blur(4px);
  }

   {
    transition: transform 4s;
  }
}
GO
package main

import "fmt"

// fibonacci is a function that returns a function
func fibonacci() func() int {
  f2, f1 := 0, 1
  return func() int {
    f := f2
    f2, f1 = f1, f+f1
    return f
  }
}

func main() {
  f := fibonacci()
  for i := 0; i < 10; i++ {
    fmt.Println(f())
  }
}
Handlebars
{#
  Mixed Django style comment
#}

<h1>
  {{#if quotaFull}}
    Please come back tomorrow.
  {{/if}}
</h1>

<!-- handlebars example -->
<ul>
  {{#each serialList}}
    <li>{{this}}</li>
  {{/each}}
</ul>
Haskell
putTodo :: (Int, String) -> IO ()
putTodo (n, todo) = putStrLn (show n ++ ": " ++ todo)

prompt :: [String] -> IO ()
prompt todos = do
  putStrLn ""
  putStrLn "Current TODO list:"
  mapM_ putTodo (zip [0..] todos)

delete :: Int -> [a] -> Maybe [a]
HTML
<figure ="img" class="baz { foo } ${ bar }">
  <img loading="lazy" :alt="alt" :src="_ || src">

  <!-- HTML comment here -->
  <p>I finally made it to the public</p>

  <figcaption :if="caption">{{ caption }}</figcaption>

  <script>
    constructor(data) {
      this.caption = data.caption || ''
    }
  </script>
</figure>
Java
// Importing generic Classes/Files
import java.io.*;

class GFG {

  // Function to find the biggest of three numbers
  static int biggestOfThree(int x, int y, int z) {
    return z > (x > y ? x : y) ? z : ((x > y) ? x : y);
  }

  // Main driver function
  public static void main(String[] args) {
    int a, b, c;
    a = 5; b = 10; c = 3;

    // Calling the above function in main
    largest = biggestOfThree(a, b, c);
  }
}
JavaScript
"use strict"

// import some UI stuff
import { layout } from 'components/layout'

// environment
const ENV = {
  scripts: ['lol.js'],
  styles: ['lma\no.css'],
  desc: undefined
}

export default function({ val }) {
  const fooo = val.split('\n') // 30px
  return `<div class='node'></div>`
}
JSON
{
  "author": "John Doe <john.doe@gmail.com>",
  "keywords": ["json", "es5"],
  "version": 1.5,
  "keywords": ["json", "json5"],
  "version": 1.7,

  "scripts": {
    "test": "mocha --ui exports --reporter spec",
    "build": "./lib/cli.js -c package.json5",
  }
}
JSON5
{
  // this is a JSON5 snippet
  author: 'John Doe <john.doe@gmail.com>',
  keywords: ['json', 'es5'],
  version: 1.5,
  keywords: ['json', 'json5'],
  version: 1.7,

  scripts: {
    test: 'mocha --ui exports --reporter spec',
    build: './lib/cli.js -c package.json5',
  }
}
JSX
import { FormEvent } from 'react';

/*
  Multi-line comment goes here
*/
export default function Page() {
  async function onSubmit(event: FormEvent<Element>) {
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    });
  }

  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}
Julia
function finalize_ref(r::AbstractRemoteRef)
  # Check if the finalizer is already run

  if islocked(client_refs) || 100
      # delay finalizer for later
      finalizer(finalize_ref, r)
      return nothing # really nothing
  end

  t =  begin; sleep(5); println('done'); end

  # lock should always be followed by try
  Threads. for i = 1:10
    a[i] = Threads.threadid()
  end
end
Kotlin
(DelicateCoroutinesApi::class)

fun main() = runBlocking {
  val job = GlobalScope.launch {
    // root coroutine with launch
    println("Throwing exception from launch")
    throw IndexOutOfBoundsException()
  }
  try {
    deferred.await()
    println("Unreached")
  } catch (e: ArithmeticException) {
    println("Caught ArithmeticException")
  }
}
Lua
-- This here is a comment
function perm (a)
  local n = table.getn(a)
  return coroutine.wrap(function () permgen(a, n) end)
end


-- Another function
function printResult (a)
  for i,v in ipairs(a) do
    io.write(v, " ")
  end
  io.write("hello")
end
Markdown
---
title: Lightning CSS might yield our thinking
tags: [ css, design systems ]
pubDate: 2024-02-12
---

# This is something about Lightning CSS
I'm baby else umami wolf yield batch iceland
adaptogen. Iceland **chambray** raclette stumptown

![Hey](/world.png)

> Air plant adaptogen artisan gastropub deep v dreamcatcher
> Pinterest intelligentsia gluten-free truffaut.

* first
* second

[grid]
  nollie: "Something"
  list: [ foo, bar ]
  foo: 10
  bar: 30
MDX
import {Chart} from './snowfall.js'
export const year = 2023

# Last year’s snowfall

In {year}, the snowfall was above average.
It was followed by a warm spring which caused
flood conditions in many of the nearby rivers.

![Hey](/world.png)

> Air plant adaptogen artisan gastropub deep v dreamcatcher
> Pinterest intelligentsia gluten-free truffaut.

<Chart year={year} color="#fcb32c" />

<Elemment { ...attr }>
  <p class="epic">Yo</p>
</Element>
Nim
import std/strformat

type
  Person = object
    name: string
    age: Natural # Ensures the age is positive

let people = [
  Person(name: "John", age: 45),
  Person(name: "Kate", age: 30)
]

for person in people:
  # Type-safe string interpolation,
  # evaluated at compile time.
  echo(fmt"{person.name} is {person.age} years old")
Nuemark
---
title: Noel's cringe content
|description: Not much to say
unlisted: true
---

# Lets get magical
I'm baby truffaut umami wolf small batch iceland
adaptogen. Iceland **chambray** raclette stumptown

// line comment here
[table head="Foo | Bar | Baz"]
  - Content first               | + | + | +
  - Content collections         | + | + | +
  - Hot-reloading               | + | + | +
  - AI content generation       | + | + | +

 > This is my blockquote right here

[.listbox]
  * Nothing here to see
  * This one is a banger

  ![Hello](/banger.png)

[image loading="eager"]
| small: "/img/explainer-tall.png"
  src: "/img/explainer.png"
  hidden: true
  width: 800
Perl
#!/usr/bin/perl
use warnings;
use Path::Tiny;

# foo/bar
my $dir = path('foo','bar');

# Iterate over the content of foo/bar
my $iter = $dir->iterator;

while (my $file = $iter->()) {

  # Print out the file name and path
  print "$file";
}
PHP
<!DOCTYPE html>

<!-- HTML comment -->
<form method="get" action="target_proccessor.php">
  <input type="search" name="search">
  <input type="submit" name="submit" value="Search">

  <?php
    // inline PHP comment
    $camp = array("zero" => "free", "one" => "code" );
    print_r($camp);
  ?>
</form>
Python
# Function definition
def find_square(num):
    result = num * num
    return result

'''
This is a multiline comment
'''
square = find_square(3) // 2

# Weirdoes
if (False) continue
elif (True) nonlocal + zoo
else None

print('Square:', square)
Ruby
# line comment here
def get_numbers_stack(list)
  stack  = [[0, []]]
  output = []

  =begin
    Ruby multiline comments are pretty weirdoes
    Or maybe not??
  =end
  until stack.empty?
    index, taken = stack.pop
    next output << taken if index == list.size
    stack.unshift [index + 1, taken]
    stack.unshift [index + 1, taken + [list[index]]]
  end
  output
end
Rust
use std::fmt::{ Debug, Display };

// all drinks are emptied
fn compare_prints<T: Debug + Display>(t: &T) {
  println!("Debug: `{:?}`", t);
}

fn compare_types<T: Debug, U: Debug>(t: &T, u: &U) {
  println!("t: `{:?}`", t);
}
Shell
#!/bin/bash

myfile = 'cars.txt'

touch $myfile
if [ -f $myfile ]; then
   rm cars.txt
   echo "$myfile deleted"
fi

# open demo on the browser
open "http://localhost:8080"
SQL
SELECT
  date_trunc('week', orderdate),
  count(1)

FROM orders

WHERE orderdate between '2024-01-01' AND '2024-02-01'

RANK() OVER (ORDER BY __ order_amount DESC)

INNER JOIN payment_status p ON o.status_id = p.id;
Styled component
import styled from 'styled-components';

const Wrapper = styled.section`
  background: papayawhip;
  color: ${aquasky},
  padding: 4em;
`;

// Wrapper becomes a React component
render(
  <Wrapper defaultOpened="yes">
    <Title>
      Hello World!
    </Title>
  </Wrapper>
);
Svelte
<script>
  // line comment
  import Info from './Info.svelte';

  const pkg = {
    name: 'svelte',
    version: 3,
    speed: 'blazing',
    website: 'https://svelte.dev'
  };
</script>

<!-- layout goes here -->
<p>These styles...</p>
<Nested />
<Info {...pkg} />

<style>
  /* CSS comment */
  p {
    color: purple;
    font-family: 'Comic Sans MS', cursive;
    font-size: 2em;
  }
</style>
TOML
# This is a TOML document

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
TypeScript
// user interface
interface User { name: string;  id: number; }

// account interface
class UserAccount {
  name: string;
  id: number;

  constructor(name: string, id: number) {
    this.name = name;
    this.id = id;
  }
}

const user: User = new UserAccount("Murphy", 1);
ZIG
const std = ("std");
const parseInt = std.fmt.parseInt;

test "parse integers" {
    const input = "123 67 89,99";
    const ally = std.testing.allocator;

    // Ensure the list is freed at scope exit
    defer list.deinit();

    var it = std.mem.tokenizeAny(u8, input, " ,");
    while (it.next()) |num| {
        const n = try parseInt(u32, num, 10);
        try list.append(n); // EOL comment
    }
}
YAML
title: Do this or else that yield happens
tags: [ function, default, const ]
date: 2024-02-12
more: "strings"
count: 10
xmas: true

# Comment here
Documentation:
  Hello World: /syntax-test
  Nothing goes: /morphine/boss "hello"
list:
  - Michelangelo "boost"