From 08439ee27125539e66cac4a6f2ddf6488878a601 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 16 May 2024 20:27:10 -0700 Subject: docs: update highlighting --- docs/SYNTAX.md | 16 +- docs/TYPES.md | 6 +- docs/book/SYNTAX.html | 16 +- docs/book/TYPES.html | 6 +- docs/book/highlight.js | 3180 +++++++++++++++++++++++++----------------- docs/book/tomorrow-night.css | 15 +- 6 files changed, 1911 insertions(+), 1328 deletions(-) diff --git a/docs/SYNTAX.md b/docs/SYNTAX.md index c6e96f6..249d6e3 100644 --- a/docs/SYNTAX.md +++ b/docs/SYNTAX.md @@ -4,7 +4,7 @@ There is little difference between a function, macro, and operator call. There are only a few forms such calls can take, too, though notably more than most other languages (due to, among other things, uniform function call syntax): hence this section. -``` +```puck # The standard, unambiguous call. routine(1, 2, 3, 4) # The method call syntax equivalent. @@ -22,7 +22,7 @@ routine 1, 2, 3, 4 Binary operators have some special rules. -``` +```puck # Valid call syntaxes for binary operators. What can constitute a binary # operator is constrained for parsing's sake. Whitespace is optional. 1 + 2 @@ -33,7 +33,7 @@ Binary operators have some special rules. As do unary operators. -``` +```puck # The standard call for unary operators. Postfix. 1? ?(1) @@ -41,7 +41,7 @@ As do unary operators. Method call syntax has a number of advantages: notably that it can be *chained*: acting as a natural pipe operator. Redundant parenthesis can also be omitted. -``` +```puck # The following statements are equivalent: foo.bar.baz foo().bar().baz() @@ -110,7 +110,7 @@ of that then ... A line beginning with a scope token is treated as attached to the previous expression. -``` +```puck # Technically allowed. Please don't do this. let foo = ... @@ -132,7 +132,7 @@ of that then ... This *can* lead to some ugly possibilities for formatting that are best avoided. -``` +```puck # Much preferred. let foo = @@ -166,7 +166,7 @@ There are some syntactic constructs unambiguously recognizable as statements: al Expressions can go almost anywhere. Our indentation rules above allow for it. -``` +```puck # Some different formulations of valid expressions. if cond then @@ -190,7 +190,7 @@ let foo = that ``` -``` +```puck # Some different formulations of *invalid* expressions. # These primarily break the rule that everything following a scope token # (ex. `=`, `do`, `then`) not at the end of the line must be self-contained. diff --git a/docs/TYPES.md b/docs/TYPES.md index 5ea320a..5d97db5 100644 --- a/docs/TYPES.md +++ b/docs/TYPES.md @@ -259,15 +259,15 @@ func eval(context: mut HashTable[Ident, Value], expr: Expr): Result[Value] of Variable(ident) then context.get(ident).err("Variable not in context") of Application(body, arg) then - if body of Abstraction(param, body as inner_body): + if body of Abstraction(param, body as inner_body) then context.set(param, context.eval(arg)?) # from std.tables context.eval(inner_body) else Error("Expected Abstraction, found {}".fmt(body)) - of Conditional(condition, then_case, else_case): + of Conditional(condition, then_case, else_case) then if context.eval(condition)? == "true" then context.eval(then_case) - else: + else context.eval(else_case) of expr then Error("Invalid expression {}".fmt(expr)) diff --git a/docs/book/SYNTAX.html b/docs/book/SYNTAX.html index 4860718..6783b5e 100644 --- a/docs/book/SYNTAX.html +++ b/docs/book/SYNTAX.html @@ -176,7 +176,7 @@

Syntax: A Casual and Formal Look

Call Syntax

There is little difference between a function, macro, and operator call. There are only a few forms such calls can take, too, though notably more than most other languages (due to, among other things, uniform function call syntax): hence this section.

-
# The standard, unambiguous call.
+
# The standard, unambiguous call.
 routine(1, 2, 3, 4)
 # The method call syntax equivalent.
 1.routine(2, 3, 4)
@@ -191,7 +191,7 @@ routine
 routine 1, 2, 3, 4
 

Binary operators have some special rules.

-
# Valid call syntaxes for binary operators. What can constitute a binary
+
# Valid call syntaxes for binary operators. What can constitute a binary
 # operator is constrained for parsing's sake. Whitespace is optional.
 1 + 2
 1+2
@@ -199,12 +199,12 @@ routine 1, 2, 3, 4
 +(1, 2)
 

As do unary operators.

-
# The standard call for unary operators. Postfix.
+
# The standard call for unary operators. Postfix.
 1?
 ?(1)
 

Method call syntax has a number of advantages: notably that it can be chained: acting as a natural pipe operator. Redundant parenthesis can also be omitted.

-
# The following statements are equivalent:
+
# The following statements are equivalent:
 foo.bar.baz
 foo().bar().baz()
 baz(bar(foo))
@@ -252,7 +252,7 @@ of this then ...
 of that then ...
 

A line beginning with a scope token is treated as attached to the previous expression.

-
# Technically allowed. Please don't do this.
+
# Technically allowed. Please don't do this.
 let foo
 = ...
 
@@ -271,7 +271,7 @@ then ...
 of that then ...
 

This can lead to some ugly possibilities for formatting that are best avoided.

-
# Much preferred.
+
# Much preferred.
 
 let foo =
   ...
@@ -298,7 +298,7 @@ of that then ...
 

First, a word on the distinction between expressions and statements. Expressions return a value. Statements do not. That is all.

There are some syntactic constructs unambiguously recognizable as statements: all declarations, modules, and use statements. There are no syntactic constructs unambiguously recognizable as expressions. As calls returning void are treated as statements, and expressions that return a type could possibly return void, there is no explicit distinction between expressions and statements made in the parser: or anywhere before type-checking.

Expressions can go almost anywhere. Our indentation rules above allow for it.

-
# Some different formulations of valid expressions.
+
# Some different formulations of valid expressions.
 
 if cond then
   this
@@ -320,7 +320,7 @@ let foo =
   else
     that
 
-
# Some different formulations of *invalid* expressions.
+
# Some different formulations of *invalid* expressions.
 # These primarily break the rule that everything following a scope token
 # (ex. `=`, `do`, `then`) not at the end of the line must be self-contained.
 
diff --git a/docs/book/TYPES.html b/docs/book/TYPES.html
index 5abe998..1054e03 100644
--- a/docs/book/TYPES.html
+++ b/docs/book/TYPES.html
@@ -395,15 +395,15 @@ func eval(context: mut HashTable[Ident, Value], expr: Expr): Result[Value]
   of Variable(ident) then
     context.get(ident).err("Variable not in context")
   of Application(body, arg) then
-    if body of Abstraction(param, body as inner_body):
+    if body of Abstraction(param, body as inner_body) then
       context.set(param, context.eval(arg)?) # from std.tables
       context.eval(inner_body)
     else
       Error("Expected Abstraction, found {}".fmt(body))
-  of Conditional(condition, then_case, else_case):
+  of Conditional(condition, then_case, else_case) then
     if context.eval(condition)? == "true" then
       context.eval(then_case)
-    else:
+    else
       context.eval(else_case)
   of expr then
     Error("Invalid expression {}".fmt(expr))
diff --git a/docs/book/highlight.js b/docs/book/highlight.js
index 2661c0e..2352580 100644
--- a/docs/book/highlight.js
+++ b/docs/book/highlight.js
@@ -1,6 +1,6 @@
 /*!
-  Highlight.js v11.9.0 (git: 215b7639e5)
-  (c) 2006-2023 undefined and other contributors
+  Highlight.js v11.9.0 (git: ea6ad285eb)
+  (c) 2006-2024 Josh Goebel  and other contributors
   License: BSD-3-Clause
  */
 var hljs = (function () {
@@ -2604,1031 +2604,1486 @@ var hljs = (function () {
   var HighlightJS = highlight;
 
   /*
-  Language: Puck
-  Description: Puck is a whitespace-sensitive, memory-safe, interface-oriented, imperative language with functional underpinnings.
-  Website: https://puck-lang.org
-  Category: system
+  Language: Bash
+  Author: vah 
+  Contributrors: Benjamin Pannell 
+  Website: https://www.gnu.org/software/bash/
+  Category: common, scripting
   */
 
-  function puck(hljs) {
-    const TYPES = [
-      "struct",
-      "tuple",
-      "union",
-      "enum",
-      "class",
-      "ref",
-      "refc",
-      "ptr",
-      "array",
-      "list",
-      "slice",
-      "int",
-      "uint",
-      "float",
-      "dec",
-      "i8",
-      "i16",
-      "i32",
-      "i64",
-      "i128",
-      "u8",
-      "u16",
-      "u32",
-      "u64",
-      "u128",
-      "f32",
-      "f64",
-      "f128",
-      "dec64",
-      "dec128",
-      "void",
-      "empty",
-      "never",
-      "bool",
-      "byte",
-      "chr",
-      "str"
+  /** @type LanguageFn */
+  function bash(hljs) {
+    const regex = hljs.regex;
+    const VAR = {};
+    const BRACED_VAR = {
+      begin: /\$\{/,
+      end: /\}/,
+      contains: [
+        "self",
+        {
+          begin: /:-/,
+          contains: [ VAR ]
+        } // default values
+      ]
+    };
+    Object.assign(VAR, {
+      className: 'variable',
+      variants: [
+        { begin: regex.concat(/\$[\w\d#@][\w\d_]*/,
+          // negative look-ahead tries to avoid matching patterns that are not
+          // Perl at all like $ident$, @ident@, etc.
+          `(?![\\w\\d])(?![$])`) },
+        BRACED_VAR
+      ]
+    });
+
+    const SUBST = {
+      className: 'subst',
+      begin: /\$\(/,
+      end: /\)/,
+      contains: [ hljs.BACKSLASH_ESCAPE ]
+    };
+    const COMMENT = hljs.inherit(
+      hljs.COMMENT(),
+      {
+        match: [
+          /(^|\s)/,
+          /#.*$/
+        ],
+        scope: {
+          2: 'comment'
+        }
+      }
+    );
+    const HERE_DOC = {
+      begin: /<<-?\s*(?=\w+)/,
+      starts: { contains: [
+        hljs.END_SAME_AS_BEGIN({
+          begin: /(\w+)/,
+          end: /(\w+)/,
+          className: 'string'
+        })
+      ] }
+    };
+    const QUOTE_STRING = {
+      className: 'string',
+      begin: /"/,
+      end: /"/,
+      contains: [
+        hljs.BACKSLASH_ESCAPE,
+        VAR,
+        SUBST
+      ]
+    };
+    SUBST.contains.push(QUOTE_STRING);
+    const ESCAPED_QUOTE = {
+      match: /\\"/
+    };
+    const APOS_STRING = {
+      className: 'string',
+      begin: /'/,
+      end: /'/
+    };
+    const ESCAPED_APOS = {
+      match: /\\'/
+    };
+    const ARITHMETIC = {
+      begin: /\$?\(\(/,
+      end: /\)\)/,
+      contains: [
+        {
+          begin: /\d+#[0-9a-f]+/,
+          className: "number"
+        },
+        hljs.NUMBER_MODE,
+        VAR
+      ]
+    };
+    const SH_LIKE_SHELLS = [
+      "fish",
+      "bash",
+      "zsh",
+      "sh",
+      "csh",
+      "ksh",
+      "tcsh",
+      "dash",
+      "scsh",
     ];
+    const KNOWN_SHEBANG = hljs.SHEBANG({
+      binary: `(${SH_LIKE_SHELLS.join("|")})`,
+      relevance: 10
+    });
+    const FUNCTION = {
+      className: 'function',
+      begin: /\w[\w\d_]*\s*\(\s*\)\s*\{/,
+      returnBegin: true,
+      contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /\w[\w\d_]*/ }) ],
+      relevance: 0
+    };
+
     const KEYWORDS = [
-      "pub",
-      "let",
-      "var",
-      "const",
-      "func",
-      "macro",
-      "type",
-      "mod",
-      "use",
-      "as",
-      "for",
-      "in",
-      "do",
-      "while",
-      "loop",
-      "block",
       "if",
       "then",
-      "elif",
       "else",
-      "when",
-      "match",
-      "of",
-      "where",
-      "try",
-      "catch",
-      "finally",
-      "lent",
-      "mut",
-      "break",
-      "continue",
-      "return",
-      "is"
-    ];
-    const BUILT_INS = [
-      "stdin",
-      "stdout",
-      "stderr",
-      "result"
+      "elif",
+      "fi",
+      "for",
+      "while",
+      "until",
+      "in",
+      "do",
+      "done",
+      "case",
+      "esac",
+      "function",
+      "select"
     ];
+
     const LITERALS = [
       "true",
-      "unit",
-      "false",
-      // "some",
-      // "none",
+      "false"
     ];
-    return {
-      name: 'Puck',
-      aliases: [ 'pk' ],
-      keywords: {
-        keyword: KEYWORDS,
-        literal: LITERALS,
-        type: TYPES,
-        built_in: BUILT_INS
-      },
-      contains: [
-        {
-          className: 'string',
-          begin: /[a-zA-Z]\w*"/,
-          end: /"/,
-          contains: [ { begin: /""/ } ]
-        },
-        {
-          className: 'string',
-          begin: /([a-zA-Z]\w*)?"""/,
-          end: /"""/
-        },
-        hljs.QUOTE_STRING_MODE,
-        {
-          className: 'type',
-          begin: /\b[A-Z]\w+\b/,
-          relevance: 0
-        },
-        {
-          className: 'number',
-          relevance: 0,
-          variants: [
-            { begin: /\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/ },
-            { begin: /\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/ },
-            { begin: /\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/ },
-            { begin: /\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/ }
-          ]
-        },
-        hljs.HASH_COMMENT_MODE
-      ]
-    };
-  }
 
-  /*
-  Language: Nim
-  Description: Nim is a statically typed compiled systems programming language.
-  Website: https://nim-lang.org
-  Category: system
-  */
+    // to consume paths to prevent keyword matches inside them
+    const PATH_MODE = { match: /(\/[a-z._-]+)+/ };
 
-  function nim(hljs) {
-    const TYPES = [
-      "int",
-      "int8",
-      "int16",
-      "int32",
-      "int64",
-      "uint",
-      "uint8",
-      "uint16",
-      "uint32",
-      "uint64",
-      "float",
-      "float32",
-      "float64",
-      "bool",
-      "char",
-      "string",
-      "cstring",
-      "pointer",
-      "expr",
-      "stmt",
-      "void",
-      "auto",
-      "any",
-      "range",
-      "array",
-      "openarray",
-      "varargs",
-      "seq",
-      "set",
-      "clong",
-      "culong",
-      "cchar",
-      "cschar",
-      "cshort",
-      "cint",
-      "csize",
-      "clonglong",
-      "cfloat",
-      "cdouble",
-      "clongdouble",
-      "cuchar",
-      "cushort",
-      "cuint",
-      "culonglong",
-      "cstringarray",
-      "semistatic"
-    ];
-    const KEYWORDS = [
-      "addr",
-      "and",
-      "as",
-      "asm",
-      "bind",
-      "block",
+    // http://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
+    const SHELL_BUILT_INS = [
       "break",
-      "case",
-      "cast",
-      "const",
+      "cd",
       "continue",
-      "converter",
-      "discard",
-      "distinct",
-      "div",
-      "do",
-      "elif",
-      "else",
-      "end",
-      "enum",
-      "except",
+      "eval",
+      "exec",
+      "exit",
       "export",
-      "finally",
-      "for",
-      "from",
-      "func",
-      "generic",
-      "guarded",
-      "if",
-      "import",
-      "in",
-      "include",
-      "interface",
-      "is",
-      "isnot",
-      "iterator",
-      "let",
-      "macro",
-      "method",
-      "mixin",
-      "mod",
-      "nil",
-      "not",
-      "notin",
-      "object",
-      "of",
-      "or",
-      "out",
-      "proc",
-      "ptr",
-      "raise",
-      "ref",
+      "getopts",
+      "hash",
+      "pwd",
+      "readonly",
       "return",
-      "shared",
-      "shl",
-      "shr",
-      "static",
-      "template",
-      "try",
-      "tuple",
-      "type",
-      "using",
-      "var",
-      "when",
-      "while",
-      "with",
-      "without",
-      "xor",
-      "yield"
-    ];
-    const BUILT_INS = [
-      "stdin",
-      "stdout",
-      "stderr",
-      "result"
-    ];
-    const LITERALS = [
-      "true",
-      "false"
+      "shift",
+      "test",
+      "times",
+      "trap",
+      "umask",
+      "unset"
     ];
-    return {
-      name: 'Nim',
-      keywords: {
-        keyword: KEYWORDS,
-        literal: LITERALS,
-        type: TYPES,
-        built_in: BUILT_INS
-      },
-      contains: [
-        {
-          className: 'meta', // Actually pragma
-          begin: /\{\./,
-          end: /\.\}/,
-          relevance: 10
-        },
-        {
-          className: 'string',
-          begin: /[a-zA-Z]\w*"/,
-          end: /"/,
-          contains: [ { begin: /""/ } ]
-        },
-        {
-          className: 'string',
-          begin: /([a-zA-Z]\w*)?"""/,
-          end: /"""/
-        },
-        hljs.QUOTE_STRING_MODE,
-        {
-          className: 'type',
-          begin: /\b[A-Z]\w+\b/,
-          relevance: 0
-        },
-        {
-          className: 'number',
-          relevance: 0,
-          variants: [
-            { begin: /\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/ },
-            { begin: /\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/ },
-            { begin: /\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/ },
-            { begin: /\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/ }
-          ]
-        },
-        hljs.HASH_COMMENT_MODE
-      ]
-    };
-  }
-
-  /*
-  Language: Rust
-  Author: Andrey Vlasovskikh 
-  Contributors: Roman Shmatov , Kasper Andersen 
-  Website: https://www.rust-lang.org
-  Category: common, system
-  */
 
-  /** @type LanguageFn */
-  function rust(hljs) {
-    const regex = hljs.regex;
-    const FUNCTION_INVOKE = {
-      className: "title.function.invoke",
-      relevance: 0,
-      begin: regex.concat(
-        /\b/,
-        /(?!let|for|while|if|else|match\b)/,
-        hljs.IDENT_RE,
-        regex.lookahead(/\s*\(/))
-    };
-    const NUMBER_SUFFIX = '([ui](8|16|32|64|128|size)|f(32|64))\?';
-    const KEYWORDS = [
-      "abstract",
-      "as",
-      "async",
-      "await",
-      "become",
-      "box",
-      "break",
-      "const",
-      "continue",
-      "crate",
-      "do",
-      "dyn",
-      "else",
-      "enum",
-      "extern",
-      "false",
-      "final",
-      "fn",
-      "for",
-      "if",
-      "impl",
-      "in",
+    const BASH_BUILT_INS = [
+      "alias",
+      "bind",
+      "builtin",
+      "caller",
+      "command",
+      "declare",
+      "echo",
+      "enable",
+      "help",
       "let",
-      "loop",
-      "macro",
-      "match",
-      "mod",
-      "move",
-      "mut",
-      "override",
-      "priv",
-      "pub",
-      "ref",
-      "return",
-      "self",
-      "Self",
-      "static",
-      "struct",
-      "super",
-      "trait",
-      "true",
-      "try",
+      "local",
+      "logout",
+      "mapfile",
+      "printf",
+      "read",
+      "readarray",
+      "source",
+      "sudo",
       "type",
-      "typeof",
-      "unsafe",
-      "unsized",
-      "use",
-      "virtual",
+      "typeset",
+      "ulimit",
+      "unalias"
+    ];
+
+    const ZSH_BUILT_INS = [
+      "autoload",
+      "bg",
+      "bindkey",
+      "bye",
+      "cap",
+      "chdir",
+      "clone",
+      "comparguments",
+      "compcall",
+      "compctl",
+      "compdescribe",
+      "compfiles",
+      "compgroups",
+      "compquote",
+      "comptags",
+      "comptry",
+      "compvalues",
+      "dirs",
+      "disable",
+      "disown",
+      "echotc",
+      "echoti",
+      "emulate",
+      "fc",
+      "fg",
+      "float",
+      "functions",
+      "getcap",
+      "getln",
+      "history",
+      "integer",
+      "jobs",
+      "kill",
+      "limit",
+      "log",
+      "noglob",
+      "popd",
+      "print",
+      "pushd",
+      "pushln",
+      "rehash",
+      "sched",
+      "setcap",
+      "setopt",
+      "stat",
+      "suspend",
+      "ttyctl",
+      "unfunction",
+      "unhash",
+      "unlimit",
+      "unsetopt",
+      "vared",
+      "wait",
+      "whence",
       "where",
-      "while",
-      "yield"
+      "which",
+      "zcompile",
+      "zformat",
+      "zftp",
+      "zle",
+      "zmodload",
+      "zparseopts",
+      "zprof",
+      "zpty",
+      "zregexparse",
+      "zsocket",
+      "zstyle",
+      "ztcp"
     ];
-    const LITERALS = [
-      "true",
-      "false",
-      "Some",
-      "None",
-      "Ok",
-      "Err"
+
+    const GNU_CORE_UTILS = [
+      "chcon",
+      "chgrp",
+      "chown",
+      "chmod",
+      "cp",
+      "dd",
+      "df",
+      "dir",
+      "dircolors",
+      "ln",
+      "ls",
+      "mkdir",
+      "mkfifo",
+      "mknod",
+      "mktemp",
+      "mv",
+      "realpath",
+      "rm",
+      "rmdir",
+      "shred",
+      "sync",
+      "touch",
+      "truncate",
+      "vdir",
+      "b2sum",
+      "base32",
+      "base64",
+      "cat",
+      "cksum",
+      "comm",
+      "csplit",
+      "cut",
+      "expand",
+      "fmt",
+      "fold",
+      "head",
+      "join",
+      "md5sum",
+      "nl",
+      "numfmt",
+      "od",
+      "paste",
+      "ptx",
+      "pr",
+      "sha1sum",
+      "sha224sum",
+      "sha256sum",
+      "sha384sum",
+      "sha512sum",
+      "shuf",
+      "sort",
+      "split",
+      "sum",
+      "tac",
+      "tail",
+      "tr",
+      "tsort",
+      "unexpand",
+      "uniq",
+      "wc",
+      "arch",
+      "basename",
+      "chroot",
+      "date",
+      "dirname",
+      "du",
+      "echo",
+      "env",
+      "expr",
+      "factor",
+      // "false", // keyword literal already
+      "groups",
+      "hostid",
+      "id",
+      "link",
+      "logname",
+      "nice",
+      "nohup",
+      "nproc",
+      "pathchk",
+      "pinky",
+      "printenv",
+      "printf",
+      "pwd",
+      "readlink",
+      "runcon",
+      "seq",
+      "sleep",
+      "stat",
+      "stdbuf",
+      "stty",
+      "tee",
+      "test",
+      "timeout",
+      // "true", // keyword literal already
+      "tty",
+      "uname",
+      "unlink",
+      "uptime",
+      "users",
+      "who",
+      "whoami",
+      "yes"
     ];
-    const BUILTINS = [
-      // functions
-      'drop ',
-      // traits
-      "Copy",
-      "Send",
-      "Sized",
-      "Sync",
-      "Drop",
-      "Fn",
-      "FnMut",
-      "FnOnce",
-      "ToOwned",
-      "Clone",
-      "Debug",
-      "PartialEq",
-      "PartialOrd",
-      "Eq",
-      "Ord",
-      "AsRef",
-      "AsMut",
-      "Into",
-      "From",
-      "Default",
-      "Iterator",
-      "Extend",
-      "IntoIterator",
-      "DoubleEndedIterator",
-      "ExactSizeIterator",
-      "SliceConcatExt",
-      "ToString",
-      // macros
-      "assert!",
-      "assert_eq!",
-      "bitflags!",
-      "bytes!",
-      "cfg!",
-      "col!",
-      "concat!",
-      "concat_idents!",
-      "debug_assert!",
-      "debug_assert_eq!",
-      "env!",
-      "eprintln!",
-      "panic!",
-      "file!",
-      "format!",
-      "format_args!",
-      "include_bytes!",
-      "include_str!",
-      "line!",
-      "local_data_key!",
-      "module_path!",
-      "option_env!",
-      "print!",
-      "println!",
-      "select!",
-      "stringify!",
-      "try!",
-      "unimplemented!",
-      "unreachable!",
-      "vec!",
-      "write!",
-      "writeln!",
-      "macro_rules!",
-      "assert_ne!",
-      "debug_assert_ne!"
+
+    return {
+      name: 'Bash',
+      aliases: [
+        'sh',
+        'zsh'
+      ],
+      keywords: {
+        $pattern: /\b[a-z][a-z0-9._-]+\b/,
+        keyword: KEYWORDS,
+        literal: LITERALS,
+        built_in: [
+          ...SHELL_BUILT_INS,
+          ...BASH_BUILT_INS,
+          // Shell modifiers
+          "set",
+          "shopt",
+          ...ZSH_BUILT_INS,
+          ...GNU_CORE_UTILS
+        ]
+      },
+      contains: [
+        KNOWN_SHEBANG, // to catch known shells and boost relevancy
+        hljs.SHEBANG(), // to catch unknown shells but still highlight the shebang
+        FUNCTION,
+        ARITHMETIC,
+        COMMENT,
+        HERE_DOC,
+        PATH_MODE,
+        QUOTE_STRING,
+        ESCAPED_QUOTE,
+        APOS_STRING,
+        ESCAPED_APOS,
+        VAR
+      ]
+    };
+  }
+
+  /*
+  Language: C
+  Category: common, system
+  Website: https://en.wikipedia.org/wiki/C_(programming_language)
+  */
+
+  /** @type LanguageFn */
+  function c(hljs) {
+    const regex = hljs.regex;
+    // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
+    // not include such support nor can we be sure all the grammars depending
+    // on it would desire this behavior
+    const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
+    const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
+    const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
+    const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
+    const FUNCTION_TYPE_RE = '('
+      + DECLTYPE_AUTO_RE + '|'
+      + regex.optional(NAMESPACE_RE)
+      + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
+    + ')';
+
+
+    const TYPES = {
+      className: 'type',
+      variants: [
+        { begin: '\\b[a-z\\d_]*_t\\b' },
+        { match: /\batomic_[a-z]{3,6}\b/ }
+      ]
+
+    };
+
+    // https://en.cppreference.com/w/cpp/language/escape
+    // \\ \x \xFF \u2837 \u00323747 \374
+    const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
+    const STRINGS = {
+      className: 'string',
+      variants: [
+        {
+          begin: '(u8?|U|L)?"',
+          end: '"',
+          illegal: '\\n',
+          contains: [ hljs.BACKSLASH_ESCAPE ]
+        },
+        {
+          begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)",
+          end: '\'',
+          illegal: '.'
+        },
+        hljs.END_SAME_AS_BEGIN({
+          begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
+          end: /\)([^()\\ ]{0,16})"/
+        })
+      ]
+    };
+
+    const NUMBERS = {
+      className: 'number',
+      variants: [
+        { begin: '\\b(0b[01\']+)' },
+        { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' },
+        { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' }
+      ],
+      relevance: 0
+    };
+
+    const PREPROCESSOR = {
+      className: 'meta',
+      begin: /#\s*[a-z]+\b/,
+      end: /$/,
+      keywords: { keyword:
+          'if else elif endif define undef warning error line '
+          + 'pragma _Pragma ifdef ifndef elifdef elifndef include' },
+      contains: [
+        {
+          begin: /\\\n/,
+          relevance: 0
+        },
+        hljs.inherit(STRINGS, { className: 'string' }),
+        {
+          className: 'string',
+          begin: /<.*?>/
+        },
+        C_LINE_COMMENT_MODE,
+        hljs.C_BLOCK_COMMENT_MODE
+      ]
+    };
+
+    const TITLE_MODE = {
+      className: 'title',
+      begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
+      relevance: 0
+    };
+
+    const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
+
+    const C_KEYWORDS = [
+      "asm",
+      "auto",
+      "break",
+      "case",
+      "continue",
+      "default",
+      "do",
+      "else",
+      "enum",
+      "extern",
+      "for",
+      "fortran",
+      "goto",
+      "if",
+      "inline",
+      "register",
+      "restrict",
+      "return",
+      "sizeof",
+      "struct",
+      "switch",
+      "typedef",
+      "union",
+      "volatile",
+      "while",
+      "_Alignas",
+      "_Alignof",
+      "_Atomic",
+      "_Generic",
+      "_Noreturn",
+      "_Static_assert",
+      "_Thread_local",
+      // aliases
+      "alignas",
+      "alignof",
+      "noreturn",
+      "static_assert",
+      "thread_local",
+      // not a C keyword but is, for all intents and purposes, treated exactly like one.
+      "_Pragma"
     ];
-    const TYPES = [
-      "i8",
-      "i16",
-      "i32",
-      "i64",
-      "i128",
-      "isize",
-      "u8",
-      "u16",
-      "u32",
-      "u64",
-      "u128",
-      "usize",
-      "f32",
-      "f64",
-      "str",
+
+    const C_TYPES = [
+      "float",
+      "double",
+      "signed",
+      "unsigned",
+      "int",
+      "short",
+      "long",
       "char",
+      "void",
+      "_Bool",
+      "_BitInt",
+      "_Complex",
+      "_Imaginary",
+      "_Decimal32",
+      "_Decimal64",
+      "_Decimal96",
+      "_Decimal128",
+      "_Decimal64x",
+      "_Decimal128x",
+      "_Float16",
+      "_Float32",
+      "_Float64",
+      "_Float128",
+      "_Float32x",
+      "_Float64x",
+      "_Float128x",
+      // modifiers
+      "const",
+      "static",
+      "constexpr",
+      // aliases
+      "complex",
       "bool",
-      "Box",
-      "Option",
-      "Result",
-      "String",
-      "Vec"
+      "imaginary"
+    ];
+
+    const KEYWORDS = {
+      keyword: C_KEYWORDS,
+      type: C_TYPES,
+      literal: 'true false NULL',
+      // TODO: apply hinting work similar to what was done in cpp.js
+      built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream '
+        + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set '
+        + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos '
+        + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp '
+        + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper '
+        + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow '
+        + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp '
+        + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan '
+        + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
+    };
+
+    const EXPRESSION_CONTAINS = [
+      PREPROCESSOR,
+      TYPES,
+      C_LINE_COMMENT_MODE,
+      hljs.C_BLOCK_COMMENT_MODE,
+      NUMBERS,
+      STRINGS
     ];
-    return {
-      name: 'Rust',
-      aliases: [ 'rs' ],
-      keywords: {
-        $pattern: hljs.IDENT_RE + '!?',
-        type: TYPES,
-        keyword: KEYWORDS,
-        literal: LITERALS,
-        built_in: BUILTINS
-      },
-      illegal: '.]/,
+      contains: [
+        { // to prevent it from being confused as the function title
+          begin: DECLTYPE_AUTO_RE,
+          keywords: KEYWORDS,
           relevance: 0
         },
         {
-          begin: [
-            /fn/,
-            /\s+/,
-            hljs.UNDERSCORE_IDENT_RE
-          ],
-          className: {
-            1: "keyword",
-            3: "title.function"
-          }
+          begin: FUNCTION_TITLE,
+          returnBegin: true,
+          contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ],
+          relevance: 0
         },
+        // allow for multiple declarations, e.g.:
+        // extern void f(int), g(char);
         {
-          className: 'meta',
-          begin: '#!?\\[',
-          end: '\\]',
+          relevance: 0,
+          match: /,/
+        },
+        {
+          className: 'params',
+          begin: /\(/,
+          end: /\)/,
+          keywords: KEYWORDS,
+          relevance: 0,
           contains: [
+            C_LINE_COMMENT_MODE,
+            hljs.C_BLOCK_COMMENT_MODE,
+            STRINGS,
+            NUMBERS,
+            TYPES,
+            // Count matching parentheses.
             {
-              className: 'string',
-              begin: /"/,
-              end: /"/,
+              begin: /\(/,
+              end: /\)/,
+              keywords: KEYWORDS,
+              relevance: 0,
               contains: [
-                hljs.BACKSLASH_ESCAPE
+                'self',
+                C_LINE_COMMENT_MODE,
+                hljs.C_BLOCK_COMMENT_MODE,
+                STRINGS,
+                NUMBERS,
+                TYPES
               ]
             }
           ]
         },
+        TYPES,
+        C_LINE_COMMENT_MODE,
+        hljs.C_BLOCK_COMMENT_MODE,
+        PREPROCESSOR
+      ]
+    };
+
+    return {
+      name: "C",
+      aliases: [ 'h' ],
+      keywords: KEYWORDS,
+      // Until differentiations are added between `c` and `cpp`, `c` will
+      // not be auto-detected to avoid auto-detect conflicts between C and C++
+      disableAutodetect: true,
+      illegal: '=]/,
+            contains: [
+              { beginKeywords: "final class struct" },
+              hljs.TITLE_MODE
+            ]
+          }
+        ]),
+      exports: {
+        preprocessor: PREPROCESSOR,
+        strings: STRINGS,
+        keywords: KEYWORDS
+      }
+    };
+  }
+
+  /*
+  Language: Python
+  Description: Python is an interpreted, object-oriented, high-level programming language with dynamic semantics.
+  Website: https://www.python.org
+  Category: common
+  */
+
+  function python(hljs) {
+    const regex = hljs.regex;
+    const IDENT_RE = /[\p{XID_Start}_]\p{XID_Continue}*/u;
+    const RESERVED_WORDS = [
+      'and',
+      'as',
+      'assert',
+      'async',
+      'await',
+      'break',
+      'case',
+      'class',
+      'continue',
+      'def',
+      'del',
+      'elif',
+      'else',
+      'except',
+      'finally',
+      'for',
+      'from',
+      'global',
+      'if',
+      'import',
+      'in',
+      'is',
+      'lambda',
+      'match',
+      'nonlocal|10',
+      'not',
+      'or',
+      'pass',
+      'raise',
+      'return',
+      'try',
+      'while',
+      'with',
+      'yield'
+    ];
+
+    const BUILT_INS = [
+      '__import__',
+      'abs',
+      'all',
+      'any',
+      'ascii',
+      'bin',
+      'bool',
+      'breakpoint',
+      'bytearray',
+      'bytes',
+      'callable',
+      'chr',
+      'classmethod',
+      'compile',
+      'complex',
+      'delattr',
+      'dict',
+      'dir',
+      'divmod',
+      'enumerate',
+      'eval',
+      'exec',
+      'filter',
+      'float',
+      'format',
+      'frozenset',
+      'getattr',
+      'globals',
+      'hasattr',
+      'hash',
+      'help',
+      'hex',
+      'id',
+      'input',
+      'int',
+      'isinstance',
+      'issubclass',
+      'iter',
+      'len',
+      'list',
+      'locals',
+      'map',
+      'max',
+      'memoryview',
+      'min',
+      'next',
+      'object',
+      'oct',
+      'open',
+      'ord',
+      'pow',
+      'print',
+      'property',
+      'range',
+      'repr',
+      'reversed',
+      'round',
+      'set',
+      'setattr',
+      'slice',
+      'sorted',
+      'staticmethod',
+      'str',
+      'sum',
+      'super',
+      'tuple',
+      'type',
+      'vars',
+      'zip'
+    ];
+
+    const LITERALS = [
+      '__debug__',
+      'Ellipsis',
+      'False',
+      'None',
+      'NotImplemented',
+      'True'
+    ];
+
+    // https://docs.python.org/3/library/typing.html
+    // TODO: Could these be supplemented by a CamelCase matcher in certain
+    // contexts, leaving these remaining only for relevance hinting?
+    const TYPES = [
+      "Any",
+      "Callable",
+      "Coroutine",
+      "Dict",
+      "List",
+      "Literal",
+      "Generic",
+      "Optional",
+      "Sequence",
+      "Set",
+      "Tuple",
+      "Type",
+      "Union"
+    ];
+
+    const KEYWORDS = {
+      $pattern: /[A-Za-z]\w+|__\w+__/,
+      keyword: RESERVED_WORDS,
+      built_in: BUILT_INS,
+      literal: LITERALS,
+      type: TYPES
+    };
+
+    const PROMPT = {
+      className: 'meta',
+      begin: /^(>>>|\.\.\.) /
+    };
+
+    const SUBST = {
+      className: 'subst',
+      begin: /\{/,
+      end: /\}/,
+      keywords: KEYWORDS,
+      illegal: /#/
+    };
+
+    const LITERAL_BRACKET = {
+      begin: /\{\{/,
+      relevance: 0
+    };
+
+    const STRING = {
+      className: 'string',
+      contains: [ hljs.BACKSLASH_ESCAPE ],
+      variants: [
+        {
+          begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,
+          end: /'''/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            PROMPT
+          ],
+          relevance: 10
+        },
+        {
+          begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,
+          end: /"""/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            PROMPT
+          ],
+          relevance: 10
+        },
+        {
+          begin: /([fF][rR]|[rR][fF]|[fF])'''/,
+          end: /'''/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            PROMPT,
+            LITERAL_BRACKET,
+            SUBST
+          ]
+        },
+        {
+          begin: /([fF][rR]|[rR][fF]|[fF])"""/,
+          end: /"""/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            PROMPT,
+            LITERAL_BRACKET,
+            SUBST
+          ]
+        },
+        {
+          begin: /([uU]|[rR])'/,
+          end: /'/,
+          relevance: 10
+        },
+        {
+          begin: /([uU]|[rR])"/,
+          end: /"/,
+          relevance: 10
+        },
+        {
+          begin: /([bB]|[bB][rR]|[rR][bB])'/,
+          end: /'/
+        },
+        {
+          begin: /([bB]|[bB][rR]|[rR][bB])"/,
+          end: /"/
+        },
+        {
+          begin: /([fF][rR]|[rR][fF]|[fF])'/,
+          end: /'/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            LITERAL_BRACKET,
+            SUBST
+          ]
+        },
+        {
+          begin: /([fF][rR]|[rR][fF]|[fF])"/,
+          end: /"/,
+          contains: [
+            hljs.BACKSLASH_ESCAPE,
+            LITERAL_BRACKET,
+            SUBST
+          ]
+        },
+        hljs.APOS_STRING_MODE,
+        hljs.QUOTE_STRING_MODE
+      ]
+    };
+
+    // https://docs.python.org/3.9/reference/lexical_analysis.html#numeric-literals
+    const digitpart = '[0-9](_?[0-9])*';
+    const pointfloat = `(\\b(${digitpart}))?\\.(${digitpart})|\\b(${digitpart})\\.`;
+    // Whitespace after a number (or any lexical token) is needed only if its absence
+    // would change the tokenization
+    // https://docs.python.org/3.9/reference/lexical_analysis.html#whitespace-between-tokens
+    // We deviate slightly, requiring a word boundary or a keyword
+    // to avoid accidentally recognizing *prefixes* (e.g., `0` in `0x41` or `08` or `0__1`)
+    const lookahead = `\\b|${RESERVED_WORDS.join('|')}`;
+    const NUMBER = {
+      className: 'number',
+      relevance: 0,
+      variants: [
+        // exponentfloat, pointfloat
+        // https://docs.python.org/3.9/reference/lexical_analysis.html#floating-point-literals
+        // optionally imaginary
+        // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
+        // Note: no leading \b because floats can start with a decimal point
+        // and we don't want to mishandle e.g. `fn(.5)`,
+        // no trailing \b for pointfloat because it can end with a decimal point
+        // and we don't want to mishandle e.g. `0..hex()`; this should be safe
+        // because both MUST contain a decimal point and so cannot be confused with
+        // the interior part of an identifier
         {
-          begin: [
-            /let/,
-            /\s+/,
-            /(?:mut\s+)?/,
-            hljs.UNDERSCORE_IDENT_RE
-          ],
-          className: {
-            1: "keyword",
-            3: "keyword",
-            4: "variable"
-          }
+          begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?(?=${lookahead})`
         },
-        // must come before impl/for rule later
         {
-          begin: [
-            /for/,
-            /\s+/,
-            hljs.UNDERSCORE_IDENT_RE,
-            /\s+/,
-            /in/
-          ],
-          className: {
-            1: "keyword",
-            3: "variable",
-            5: "keyword"
-          }
+          begin: `(${pointfloat})[jJ]?`
         },
+
+        // decinteger, bininteger, octinteger, hexinteger
+        // https://docs.python.org/3.9/reference/lexical_analysis.html#integer-literals
+        // optionally "long" in Python 2
+        // https://docs.python.org/2.7/reference/lexical_analysis.html#integer-and-long-integer-literals
+        // decinteger is optionally imaginary
+        // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
         {
-          begin: [
-            /type/,
-            /\s+/,
-            hljs.UNDERSCORE_IDENT_RE
-          ],
-          className: {
-            1: "keyword",
-            3: "title.class"
-          }
+          begin: `\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${lookahead})`
         },
         {
-          begin: [
-            /(?:trait|enum|struct|union|impl|for)/,
-            /\s+/,
-            hljs.UNDERSCORE_IDENT_RE
-          ],
-          className: {
-            1: "keyword",
-            3: "title.class"
-          }
+          begin: `\\b0[bB](_?[01])+[lL]?(?=${lookahead})`
         },
         {
-          begin: hljs.IDENT_RE + '::',
-          keywords: {
-            keyword: "Self",
-            built_in: BUILTINS,
-            type: TYPES
-          }
+          begin: `\\b0[oO](_?[0-7])+[lL]?(?=${lookahead})`
         },
         {
-          className: "punctuation",
-          begin: '->'
+          begin: `\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${lookahead})`
         },
-        FUNCTION_INVOKE
+
+        // imagnumber (digitpart-based)
+        // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
+        {
+          begin: `\\b(${digitpart})[jJ](?=${lookahead})`
+        }
       ]
     };
-  }
-
-  /*
-  Language: Bash
-  Author: vah 
-  Contributrors: Benjamin Pannell 
-  Website: https://www.gnu.org/software/bash/
-  Category: common, scripting
-  */
-
-  /** @type LanguageFn */
-  function bash(hljs) {
-    const regex = hljs.regex;
-    const VAR = {};
-    const BRACED_VAR = {
-      begin: /\$\{/,
-      end: /\}/,
+    const COMMENT_TYPE = {
+      className: "comment",
+      begin: regex.lookahead(/# type:/),
+      end: /$/,
+      keywords: KEYWORDS,
       contains: [
-        "self",
+        { // prevent keywords from coloring `type`
+          begin: /# type:/
+        },
+        // comment within a datatype comment includes no keywords
         {
-          begin: /:-/,
-          contains: [ VAR ]
-        } // default values
+          begin: /#/,
+          end: /\b\B/,
+          endsWithParent: true
+        }
       ]
     };
-    Object.assign(VAR, {
-      className: 'variable',
+    const PARAMS = {
+      className: 'params',
       variants: [
-        { begin: regex.concat(/\$[\w\d#@][\w\d_]*/,
-          // negative look-ahead tries to avoid matching patterns that are not
-          // Perl at all like $ident$, @ident@, etc.
-          `(?![\\w\\d])(?![$])`) },
-        BRACED_VAR
-      ]
-    });
-
-    const SUBST = {
-      className: 'subst',
-      begin: /\$\(/,
-      end: /\)/,
-      contains: [ hljs.BACKSLASH_ESCAPE ]
-    };
-    const COMMENT = hljs.inherit(
-      hljs.COMMENT(),
-      {
-        match: [
-          /(^|\s)/,
-          /#.*$/
-        ],
-        scope: {
-          2: 'comment'
+        // Exclude params in functions without params
+        {
+          className: "",
+          begin: /\(\s*\)/,
+          skip: true
+        },
+        {
+          begin: /\(/,
+          end: /\)/,
+          excludeBegin: true,
+          excludeEnd: true,
+          keywords: KEYWORDS,
+          contains: [
+            'self',
+            PROMPT,
+            NUMBER,
+            STRING,
+            hljs.HASH_COMMENT_MODE
+          ]
         }
-      }
-    );
-    const HERE_DOC = {
-      begin: /<<-?\s*(?=\w+)/,
-      starts: { contains: [
-        hljs.END_SAME_AS_BEGIN({
-          begin: /(\w+)/,
-          end: /(\w+)/,
-          className: 'string'
-        })
-      ] }
-    };
-    const QUOTE_STRING = {
-      className: 'string',
-      begin: /"/,
-      end: /"/,
-      contains: [
-        hljs.BACKSLASH_ESCAPE,
-        VAR,
-        SUBST
       ]
     };
-    SUBST.contains.push(QUOTE_STRING);
-    const ESCAPED_QUOTE = {
-      match: /\\"/
-    };
-    const APOS_STRING = {
-      className: 'string',
-      begin: /'/,
-      end: /'/
-    };
-    const ESCAPED_APOS = {
-      match: /\\'/
-    };
-    const ARITHMETIC = {
-      begin: /\$?\(\(/,
-      end: /\)\)/,
+    SUBST.contains = [
+      STRING,
+      NUMBER,
+      PROMPT
+    ];
+
+    return {
+      name: 'Python',
+      aliases: [
+        'py',
+        'gyp',
+        'ipython'
+      ],
+      unicodeRegex: true,
+      keywords: KEYWORDS,
+      illegal: /(<\/|\?)|=>/,
       contains: [
+        PROMPT,
+        NUMBER,
         {
-          begin: /\d+#[0-9a-f]+/,
-          className: "number"
+          // very common convention
+          scope: 'variable.language',
+          match: /\bself\b/
         },
-        hljs.NUMBER_MODE,
-        VAR
+        {
+          // eat "if" prior to string so that it won't accidentally be
+          // labeled as an f-string
+          beginKeywords: "if",
+          relevance: 0
+        },
+        { match: /\bor\b/, scope: "keyword" },
+        STRING,
+        COMMENT_TYPE,
+        hljs.HASH_COMMENT_MODE,
+        {
+          match: [
+            /\bdef/, /\s+/,
+            IDENT_RE,
+          ],
+          scope: {
+            1: "keyword",
+            3: "title.function"
+          },
+          contains: [ PARAMS ]
+        },
+        {
+          variants: [
+            {
+              match: [
+                /\bclass/, /\s+/,
+                IDENT_RE, /\s*/,
+                /\(\s*/, IDENT_RE,/\s*\)/
+              ],
+            },
+            {
+              match: [
+                /\bclass/, /\s+/,
+                IDENT_RE
+              ],
+            }
+          ],
+          scope: {
+            1: "keyword",
+            3: "title.class",
+            6: "title.class.inherited",
+          }
+        },
+        {
+          className: 'meta',
+          begin: /^[\t ]*@/,
+          end: /(?=#)|$/,
+          contains: [
+            NUMBER,
+            PARAMS,
+            STRING
+          ]
+        }
       ]
     };
-    const SH_LIKE_SHELLS = [
-      "fish",
-      "bash",
-      "zsh",
-      "sh",
-      "csh",
-      "ksh",
-      "tcsh",
-      "dash",
-      "scsh",
-    ];
-    const KNOWN_SHEBANG = hljs.SHEBANG({
-      binary: `(${SH_LIKE_SHELLS.join("|")})`,
-      relevance: 10
-    });
-    const FUNCTION = {
-      className: 'function',
-      begin: /\w[\w\d_]*\s*\(\s*\)\s*\{/,
-      returnBegin: true,
-      contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /\w[\w\d_]*/ }) ],
-      relevance: 0
-    };
-
-    const KEYWORDS = [
-      "if",
-      "then",
-      "else",
-      "elif",
-      "fi",
-      "for",
-      "while",
-      "until",
-      "in",
-      "do",
-      "done",
-      "case",
-      "esac",
-      "function",
-      "select"
-    ];
+  }
 
-    const LITERALS = [
-      "true",
-      "false"
-    ];
+  /*
+  Language: Rust
+  Author: Andrey Vlasovskikh 
+  Contributors: Roman Shmatov , Kasper Andersen 
+  Website: https://www.rust-lang.org
+  Category: common, system
+  */
 
-    // to consume paths to prevent keyword matches inside them
-    const PATH_MODE = { match: /(\/[a-z._-]+)+/ };
+  /** @type LanguageFn */
 
-    // http://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html
-    const SHELL_BUILT_INS = [
+  function rust(hljs) {
+    const regex = hljs.regex;
+    // ============================================
+    // Added to support the r# keyword, which is a raw identifier in Rust.
+    const RAW_IDENTIFIER = /(r#)?/;
+    const UNDERSCORE_IDENT_RE = regex.concat(RAW_IDENTIFIER, hljs.UNDERSCORE_IDENT_RE);
+    const IDENT_RE = regex.concat(RAW_IDENTIFIER, hljs.IDENT_RE);
+    // ============================================
+    const FUNCTION_INVOKE = {
+      className: "title.function.invoke",
+      relevance: 0,
+      begin: regex.concat(
+        /\b/,
+        /(?!let|for|while|if|else|match\b)/,
+        IDENT_RE,
+        regex.lookahead(/\s*\(/))
+    };
+    const NUMBER_SUFFIX = '([ui](8|16|32|64|128|size)|f(32|64))\?';
+    const KEYWORDS = [
+      "abstract",
+      "as",
+      "async",
+      "await",
+      "become",
+      "box",
       "break",
-      "cd",
+      "const",
       "continue",
-      "eval",
-      "exec",
-      "exit",
-      "export",
-      "getopts",
-      "hash",
-      "pwd",
-      "readonly",
-      "return",
-      "shift",
-      "test",
-      "times",
-      "trap",
-      "umask",
-      "unset"
-    ];
-
-    const BASH_BUILT_INS = [
-      "alias",
-      "bind",
-      "builtin",
-      "caller",
-      "command",
-      "declare",
-      "echo",
-      "enable",
-      "help",
+      "crate",
+      "do",
+      "dyn",
+      "else",
+      "enum",
+      "extern",
+      "false",
+      "final",
+      "fn",
+      "for",
+      "if",
+      "impl",
+      "in",
       "let",
-      "local",
-      "logout",
-      "mapfile",
-      "printf",
-      "read",
-      "readarray",
-      "source",
+      "loop",
+      "macro",
+      "match",
+      "mod",
+      "move",
+      "mut",
+      "override",
+      "priv",
+      "pub",
+      "ref",
+      "return",
+      "self",
+      "Self",
+      "static",
+      "struct",
+      "super",
+      "trait",
+      "true",
+      "try",
       "type",
-      "typeset",
-      "ulimit",
-      "unalias"
-    ];
-
-    const ZSH_BUILT_INS = [
-      "autoload",
-      "bg",
-      "bindkey",
-      "bye",
-      "cap",
-      "chdir",
-      "clone",
-      "comparguments",
-      "compcall",
-      "compctl",
-      "compdescribe",
-      "compfiles",
-      "compgroups",
-      "compquote",
-      "comptags",
-      "comptry",
-      "compvalues",
-      "dirs",
-      "disable",
-      "disown",
-      "echotc",
-      "echoti",
-      "emulate",
-      "fc",
-      "fg",
-      "float",
-      "functions",
-      "getcap",
-      "getln",
-      "history",
-      "integer",
-      "jobs",
-      "kill",
-      "limit",
-      "log",
-      "noglob",
-      "popd",
-      "print",
-      "pushd",
-      "pushln",
-      "rehash",
-      "sched",
-      "setcap",
-      "setopt",
-      "stat",
-      "suspend",
-      "ttyctl",
-      "unfunction",
-      "unhash",
-      "unlimit",
-      "unsetopt",
-      "vared",
-      "wait",
-      "whence",
-      "where",
-      "which",
-      "zcompile",
-      "zformat",
-      "zftp",
-      "zle",
-      "zmodload",
-      "zparseopts",
-      "zprof",
-      "zpty",
-      "zregexparse",
-      "zsocket",
-      "zstyle",
-      "ztcp"
-    ];
-
-    const GNU_CORE_UTILS = [
-      "chcon",
-      "chgrp",
-      "chown",
-      "chmod",
-      "cp",
-      "dd",
-      "df",
-      "dir",
-      "dircolors",
-      "ln",
-      "ls",
-      "mkdir",
-      "mkfifo",
-      "mknod",
-      "mktemp",
-      "mv",
-      "realpath",
-      "rm",
-      "rmdir",
-      "shred",
-      "sync",
-      "touch",
-      "truncate",
-      "vdir",
-      "b2sum",
-      "base32",
-      "base64",
-      "cat",
-      "cksum",
-      "comm",
-      "csplit",
-      "cut",
-      "expand",
-      "fmt",
-      "fold",
-      "head",
-      "join",
-      "md5sum",
-      "nl",
-      "numfmt",
-      "od",
-      "paste",
-      "ptx",
-      "pr",
-      "sha1sum",
-      "sha224sum",
-      "sha256sum",
-      "sha384sum",
-      "sha512sum",
-      "shuf",
-      "sort",
-      "split",
-      "sum",
-      "tac",
-      "tail",
-      "tr",
-      "tsort",
-      "unexpand",
-      "uniq",
-      "wc",
-      "arch",
-      "basename",
-      "chroot",
-      "date",
-      "dirname",
-      "du",
-      "echo",
-      "env",
-      "expr",
-      "factor",
-      // "false", // keyword literal already
-      "groups",
-      "hostid",
-      "id",
-      "link",
-      "logname",
-      "nice",
-      "nohup",
-      "nproc",
-      "pathchk",
-      "pinky",
-      "printenv",
-      "printf",
-      "pwd",
-      "readlink",
-      "runcon",
-      "seq",
-      "sleep",
-      "stat",
-      "stdbuf",
-      "stty",
-      "tee",
-      "test",
-      "timeout",
-      // "true", // keyword literal already
-      "tty",
-      "uname",
-      "unlink",
-      "uptime",
-      "users",
-      "who",
-      "whoami",
-      "yes"
+      "typeof",
+      "union",
+      "unsafe",
+      "unsized",
+      "use",
+      "virtual",
+      "where",
+      "while",
+      "yield"
+    ];
+    const LITERALS = [
+      "true",
+      "false",
+      "Some",
+      "None",
+      "Ok",
+      "Err"
+    ];
+    const BUILTINS = [
+      // functions
+      'drop ',
+      // traits
+      "Copy",
+      "Send",
+      "Sized",
+      "Sync",
+      "Drop",
+      "Fn",
+      "FnMut",
+      "FnOnce",
+      "ToOwned",
+      "Clone",
+      "Debug",
+      "PartialEq",
+      "PartialOrd",
+      "Eq",
+      "Ord",
+      "AsRef",
+      "AsMut",
+      "Into",
+      "From",
+      "Default",
+      "Iterator",
+      "Extend",
+      "IntoIterator",
+      "DoubleEndedIterator",
+      "ExactSizeIterator",
+      "SliceConcatExt",
+      "ToString",
+      // macros
+      "assert!",
+      "assert_eq!",
+      "bitflags!",
+      "bytes!",
+      "cfg!",
+      "col!",
+      "concat!",
+      "concat_idents!",
+      "debug_assert!",
+      "debug_assert_eq!",
+      "env!",
+      "eprintln!",
+      "panic!",
+      "file!",
+      "format!",
+      "format_args!",
+      "include_bytes!",
+      "include_str!",
+      "line!",
+      "local_data_key!",
+      "module_path!",
+      "option_env!",
+      "print!",
+      "println!",
+      "select!",
+      "stringify!",
+      "try!",
+      "unimplemented!",
+      "unreachable!",
+      "vec!",
+      "write!",
+      "writeln!",
+      "macro_rules!",
+      "assert_ne!",
+      "debug_assert_ne!"
+    ];
+    const TYPES = [
+      "i8",
+      "i16",
+      "i32",
+      "i64",
+      "i128",
+      "isize",
+      "u8",
+      "u16",
+      "u32",
+      "u64",
+      "u128",
+      "usize",
+      "f32",
+      "f64",
+      "str",
+      "char",
+      "bool",
+      "Box",
+      "Option",
+      "Result",
+      "String",
+      "Vec"
     ];
-
     return {
-      name: 'Bash',
-      aliases: [ 'sh' ],
+      name: 'Rust',
+      aliases: [ 'rs' ],
       keywords: {
-        $pattern: /\b[a-z][a-z0-9._-]+\b/,
+        $pattern: hljs.IDENT_RE + '!?',
+        type: TYPES,
         keyword: KEYWORDS,
         literal: LITERALS,
-        built_in: [
-          ...SHELL_BUILT_INS,
-          ...BASH_BUILT_INS,
-          // Shell modifiers
-          "set",
-          "shopt",
-          ...ZSH_BUILT_INS,
-          ...GNU_CORE_UTILS
-        ]
+        built_in: BUILTINS
       },
+      illegal: ''
+        },
+        FUNCTION_INVOKE
       ]
     };
   }
@@ -3722,6 +4177,7 @@ var hljs = (function () {
     'operator',
     'optional', // contextual
     'override', // contextual
+    'package',
     'postfix', // contextual
     'precedencegroup',
     'prefix', // contextual
@@ -4218,14 +4674,17 @@ var hljs = (function () {
         }
       ] }
     };
+
     const KEYWORD_ATTRIBUTE = {
       scope: 'keyword',
-      match: concat(/@/, either(...keywordAttributes))
+      match: concat(/@/, either(...keywordAttributes), lookahead(either(/\(/, /\s+/))),
     };
+
     const USER_DEFINED_ATTRIBUTE = {
       scope: 'meta',
       match: concat(/@/, identifier)
     };
+
     const ATTRIBUTES = [
       AVAILABLE_ATTRIBUTE,
       KEYWORD_ATTRIBUTE,
@@ -4418,6 +4877,37 @@ var hljs = (function () {
       end: /}/
     };
 
+    const TYPE_DECLARATION = {
+      begin: [
+        /(struct|protocol|class|extension|enum|actor)/,
+        /\s+/,
+        identifier,
+        /\s*/,
+      ],
+      beginScope: {
+        1: "keyword",
+        3: "title.class"
+      },
+      keywords: KEYWORDS,
+      contains: [
+        GENERIC_PARAMETERS,
+        ...KEYWORD_MODES,
+        {
+          begin: /:/,
+          end: /\{/,
+          keywords: KEYWORDS,
+          contains: [
+            {
+              scope: "title.class.inherited",
+              match: typeIdentifier,
+            },
+            ...KEYWORD_MODES,
+          ],
+          relevance: 0,
+        },
+      ]
+    };
+
     // Add supported submodes to string interpolation.
     for (const variant of STRING.variants) {
       const interpolation = variant.contains.find(mode => mode.label === "interpol");
@@ -4451,19 +4941,7 @@ var hljs = (function () {
         ...COMMENTS,
         FUNCTION_OR_MACRO,
         INIT_SUBSCRIPT,
-        {
-          beginKeywords: 'struct protocol class extension enum actor',
-          end: '\\{',
-          excludeEnd: true,
-          keywords: KEYWORDS,
-          contains: [
-            hljs.inherit(hljs.TITLE_MODE, {
-              className: "title.class",
-              begin: /[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/
-            }),
-            ...KEYWORD_MODES
-          ]
-        },
+        TYPE_DECLARATION,
         OPERATOR_DECLARATION,
         PRECEDENCEGROUP,
         {
@@ -4487,401 +4965,504 @@ var hljs = (function () {
   }
 
   /*
-  Language: C
-  Category: common, system
-  Website: https://en.wikipedia.org/wiki/C_(programming_language)
+  Language: OCaml
+  Author: Mehdi Dogguy 
+  Contributors: Nicolas Braud-Santoni , Mickael Delahaye 
+  Description: OCaml language definition.
+  Website: https://ocaml.org
+  Category: functional
   */
 
-  /** @type LanguageFn */
-  function c(hljs) {
-    const regex = hljs.regex;
-    // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
-    // not include such support nor can we be sure all the grammars depending
-    // on it would desire this behavior
-    const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
-    const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
-    const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
-    const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
-    const FUNCTION_TYPE_RE = '('
-      + DECLTYPE_AUTO_RE + '|'
-      + regex.optional(NAMESPACE_RE)
-      + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
-    + ')';
-
-
-    const TYPES = {
-      className: 'type',
-      variants: [
-        { begin: '\\b[a-z\\d_]*_t\\b' },
-        { match: /\batomic_[a-z]{3,6}\b/ }
+  function ocaml(hljs) {
+    /* missing support for heredoc-like string (OCaml 4.0.2+) */
+    return {
+      name: 'OCaml',
+      aliases: [ 'ml' ],
+      keywords: {
+        $pattern: '[a-z_]\\w*!?',
+        keyword:
+          'and as assert asr begin class constraint do done downto else end '
+          + 'exception external for fun function functor if in include '
+          + 'inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method '
+          + 'mod module mutable new object of open! open or private rec sig struct '
+          + 'then to try type val! val virtual when while with '
+          /* camlp4 */
+          + 'parser value',
+        built_in:
+          /* built-in types */
+          'array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit '
+          /* (some) types in Pervasives */
+          + 'in_channel out_channel ref',
+        literal:
+          'true false'
+      },
+      illegal: /\/\/|>>/,
+      contains: [
+        {
+          className: 'literal',
+          begin: '\\[(\\|\\|)?\\]|\\(\\)',
+          relevance: 0
+        },
+        hljs.COMMENT(
+          '\\(\\*',
+          '\\*\\)',
+          { contains: [ 'self' ] }
+        ),
+        { /* type variable */
+          className: 'symbol',
+          begin: '\'[A-Za-z_](?!\')[\\w\']*'
+          /* the grammar is ambiguous on how 'a'b should be interpreted but not the compiler */
+        },
+        { /* polymorphic variant */
+          className: 'type',
+          begin: '`[A-Z][\\w\']*'
+        },
+        { /* module or constructor */
+          className: 'type',
+          begin: '\\b[A-Z][\\w\']*',
+          relevance: 0
+        },
+        { /* don't color identifiers, but safely catch all identifiers with ' */
+          begin: '[a-z_]\\w*\'[\\w\']*',
+          relevance: 0
+        },
+        hljs.inherit(hljs.APOS_STRING_MODE, {
+          className: 'string',
+          relevance: 0
+        }),
+        hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }),
+        {
+          className: 'number',
+          begin:
+            '\\b(0[xX][a-fA-F0-9_]+[Lln]?|'
+            + '0[oO][0-7_]+[Lln]?|'
+            + '0[bB][01_]+[Lln]?|'
+            + '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)',
+          relevance: 0
+        },
+        { begin: /->/ // relevance booster
+        }
       ]
-
     };
+  }
 
-    // https://en.cppreference.com/w/cpp/language/escape
-    // \\ \x \xFF \u2837 \u00323747 \374
-    const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
-    const STRINGS = {
-      className: 'string',
-      variants: [
+  /*
+  Language: Nim
+  Description: Nim is a statically typed compiled systems programming language.
+  Website: https://nim-lang.org
+  Category: system
+  */
+
+  function nim(hljs) {
+    const TYPES = [
+      "int",
+      "int8",
+      "int16",
+      "int32",
+      "int64",
+      "uint",
+      "uint8",
+      "uint16",
+      "uint32",
+      "uint64",
+      "float",
+      "float32",
+      "float64",
+      "bool",
+      "char",
+      "string",
+      "cstring",
+      "pointer",
+      "expr",
+      "stmt",
+      "void",
+      "auto",
+      "any",
+      "range",
+      "array",
+      "openarray",
+      "varargs",
+      "seq",
+      "set",
+      "clong",
+      "culong",
+      "cchar",
+      "cschar",
+      "cshort",
+      "cint",
+      "csize",
+      "clonglong",
+      "cfloat",
+      "cdouble",
+      "clongdouble",
+      "cuchar",
+      "cushort",
+      "cuint",
+      "culonglong",
+      "cstringarray",
+      "semistatic"
+    ];
+    const KEYWORDS = [
+      "addr",
+      "and",
+      "as",
+      "asm",
+      "bind",
+      "block",
+      "break",
+      "case",
+      "cast",
+      "const",
+      "continue",
+      "converter",
+      "discard",
+      "distinct",
+      "div",
+      "do",
+      "elif",
+      "else",
+      "end",
+      "enum",
+      "except",
+      "export",
+      "finally",
+      "for",
+      "from",
+      "func",
+      "generic",
+      "guarded",
+      "if",
+      "import",
+      "in",
+      "include",
+      "interface",
+      "is",
+      "isnot",
+      "iterator",
+      "let",
+      "macro",
+      "method",
+      "mixin",
+      "mod",
+      "nil",
+      "not",
+      "notin",
+      "object",
+      "of",
+      "or",
+      "out",
+      "proc",
+      "ptr",
+      "raise",
+      "ref",
+      "return",
+      "shared",
+      "shl",
+      "shr",
+      "static",
+      "template",
+      "try",
+      "tuple",
+      "type",
+      "using",
+      "var",
+      "when",
+      "while",
+      "with",
+      "without",
+      "xor",
+      "yield"
+    ];
+    const BUILT_INS = [
+      "stdin",
+      "stdout",
+      "stderr",
+      "result"
+    ];
+    const LITERALS = [
+      "true",
+      "false"
+    ];
+    return {
+      name: 'Nim',
+      keywords: {
+        keyword: KEYWORDS,
+        literal: LITERALS,
+        type: TYPES,
+        built_in: BUILT_INS
+      },
+      contains: [
         {
-          begin: '(u8?|U|L)?"',
-          end: '"',
-          illegal: '\\n',
-          contains: [ hljs.BACKSLASH_ESCAPE ]
+          className: 'meta', // Actually pragma
+          begin: /\{\./,
+          end: /\.\}/,
+          relevance: 10
         },
         {
-          begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)",
-          end: '\'',
-          illegal: '.'
+          className: 'string',
+          begin: /[a-zA-Z]\w*"/,
+          end: /"/,
+          contains: [ { begin: /""/ } ]
         },
-        hljs.END_SAME_AS_BEGIN({
-          begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
-          end: /\)([^()\\ ]{0,16})"/
-        })
-      ]
-    };
-
-    const NUMBERS = {
-      className: 'number',
-      variants: [
-        { begin: '\\b(0b[01\']+)' },
-        { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' },
-        { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' }
-      ],
-      relevance: 0
-    };
-
-    const PREPROCESSOR = {
-      className: 'meta',
-      begin: /#\s*[a-z]+\b/,
-      end: /$/,
-      keywords: { keyword:
-          'if else elif endif define undef warning error line '
-          + 'pragma _Pragma ifdef ifndef include' },
-      contains: [
         {
-          begin: /\\\n/,
+          className: 'string',
+          begin: /([a-zA-Z]\w*)?"""/,
+          end: /"""/
+        },
+        hljs.QUOTE_STRING_MODE,
+        {
+          className: 'type',
+          begin: /\b[A-Z]\w+\b/,
           relevance: 0
         },
-        hljs.inherit(STRINGS, { className: 'string' }),
         {
-          className: 'string',
-          begin: /<.*?>/
+          className: 'number',
+          relevance: 0,
+          variants: [
+            { begin: /\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/ },
+            { begin: /\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/ },
+            { begin: /\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/ },
+            { begin: /\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/ }
+          ]
         },
-        C_LINE_COMMENT_MODE,
-        hljs.C_BLOCK_COMMENT_MODE
+        hljs.HASH_COMMENT_MODE
       ]
     };
+  }
 
-    const TITLE_MODE = {
-      className: 'title',
-      begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
-      relevance: 0
-    };
-
-    const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
+  /*
+  Language: Puck
+  Description: Puck is a whitespace-sensitive, memory-safe, interface-oriented, imperative language with functional underpinnings.
+  Website: https://puck-lang.org
+  Category: system
+  */
 
-    const C_KEYWORDS = [
-      "asm",
-      "auto",
-      "break",
-      "case",
-      "continue",
-      "default",
-      "do",
-      "else",
-      "enum",
-      "extern",
-      "for",
-      "fortran",
-      "goto",
-      "if",
-      "inline",
-      "register",
-      "restrict",
-      "return",
-      "sizeof",
+  function puck(hljs) {
+    const KEYWORDS = [
       "struct",
-      "switch",
-      "typedef",
+      "tuple",
       "union",
-      "volatile",
-      "while",
-      "_Alignas",
-      "_Alignof",
-      "_Atomic",
-      "_Generic",
-      "_Noreturn",
-      "_Static_assert",
-      "_Thread_local",
-      // aliases
-      "alignas",
-      "alignof",
-      "noreturn",
-      "static_assert",
-      "thread_local",
-      // not a C keyword but is, for all intents and purposes, treated exactly like one.
-      "_Pragma"
-    ];
-
-    const C_TYPES = [
-      "float",
-      "double",
-      "signed",
-      "unsigned",
+      "enum",
+      "class",
+      "ref",
+      "refc",
+      "ptr",
+      "array",
+      "list",
+      "slice",
       "int",
-      "short",
-      "long",
-      "char",
+      "uint",
+      "float",
+      "f32",
+      "f64",
+      "f128",
+      "dec64",
+      "dec128",
       "void",
-      "_Bool",
-      "_Complex",
-      "_Imaginary",
-      "_Decimal32",
-      "_Decimal64",
-      "_Decimal128",
-      // modifiers
-      "const",
-      "static",
-      // aliases
-      "complex",
+      "never",
       "bool",
-      "imaginary"
+      "byte",
+      "char",
+      "str",
+      "pub",
+      "let",
+      "var",
+      "const",
+      "lent",
+      "mut",
+      "func",
+      "macro",
+      "type",
+      "mod",
+      "use",
+      "as",
+      "if",
+      "when",
+      "elif",
+      "else",
+      "then",
+      "match",
+      "of",
+      "where",
+      "try",
+      "with",
+      "finally",
+      "for",
+      "while",
+      "do",
+      "loop",
+      "block",
+      "quote",
+      "break",
+      "continue",
+      "return",
+      "raise",
+      "in",
+      "is",
+      "type"
     ];
-
-    const KEYWORDS = {
-      keyword: C_KEYWORDS,
-      type: C_TYPES,
-      literal: 'true false NULL',
-      // TODO: apply hinting work similar to what was done in cpp.js
-      built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream '
-        + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set '
-        + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos '
-        + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp '
-        + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper '
-        + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow '
-        + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp '
-        + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan '
-        + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
-    };
-
-    const EXPRESSION_CONTAINS = [
-      PREPROCESSOR,
-      TYPES,
-      C_LINE_COMMENT_MODE,
-      hljs.C_BLOCK_COMMENT_MODE,
-      NUMBERS,
-      STRINGS
+    const BUILT_INS = [
+      "stdin",
+      "stdout",
+      "stderr",
+      "std",
+      "lib"
     ];
-
-    const EXPRESSION_CONTEXT = {
-      // This mode covers expression context where we can't expect a function
-      // definition and shouldn't highlight anything that looks like one:
-      // `return some()`, `else if()`, `(x*sum(1, 2))`
-      variants: [
+    const LITERALS = [
+      "unit",
+      "true",
+      "false",
+      "Some",
+      "None"
+    ];
+    return {
+      name: 'Puck',
+      aliases: [ 'pk' ],
+      contains: [
         {
-          begin: /=/,
-          end: /;/
+          begin: [
+            /\n/,
+            /\s*/,
+            hljs.IDENT_RE,
+            /\s+/,
+          ],
+          className: {
+            1: "function"
+          }
         },
         {
-          begin: /\(/,
-          end: /\)/
+          className: 'string',
+          begin: /[a-zA-Z]\w*"/,
+          end: /"/,
+          contains: [ { begin: /""/ } ]
         },
         {
-          beginKeywords: 'new throw return else',
-          end: /;/
-        }
-      ],
-      keywords: KEYWORDS,
-      contains: EXPRESSION_CONTAINS.concat([
+          className: 'string',
+          begin: /([a-zA-Z]\w*)?"""/,
+          end: /"""/
+        },
+        hljs.QUOTE_STRING_MODE,
         {
-          begin: /\(/,
-          end: /\)/,
-          keywords: KEYWORDS,
-          contains: EXPRESSION_CONTAINS.concat([ 'self' ]),
-          relevance: 0
-        }
-      ]),
-      relevance: 0
-    };
-
-    const FUNCTION_DECLARATION = {
-      begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
-      returnBegin: true,
-      end: /[{;=]/,
-      excludeEnd: true,
-      keywords: KEYWORDS,
-      illegal: /[^\w\s\*&:<>.]/,
-      contains: [
-        { // to prevent it from being confused as the function title
-          begin: DECLTYPE_AUTO_RE,
-          keywords: KEYWORDS,
+          className: 'type',
+          begin: /\b[A-Z]\w*\b/,
           relevance: 0
         },
         {
-          begin: FUNCTION_TITLE,
-          returnBegin: true,
-          contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ],
+          className: 'keyword',
+          begin: /\bi\d+\b/,
           relevance: 0
         },
-        // allow for multiple declarations, e.g.:
-        // extern void f(int), g(char);
         {
-          relevance: 0,
-          match: /,/
+          className: 'keyword',
+          begin: /\bu\d+\b/,
+          relevance: 0
         },
         {
-          className: 'params',
-          begin: /\(/,
-          end: /\)/,
-          keywords: KEYWORDS,
+          className: 'number',
           relevance: 0,
-          contains: [
-            C_LINE_COMMENT_MODE,
-            hljs.C_BLOCK_COMMENT_MODE,
-            STRINGS,
-            NUMBERS,
-            TYPES,
-            // Count matching parentheses.
-            {
-              begin: /\(/,
-              end: /\)/,
-              keywords: KEYWORDS,
-              relevance: 0,
-              contains: [
-                'self',
-                C_LINE_COMMENT_MODE,
-                hljs.C_BLOCK_COMMENT_MODE,
-                STRINGS,
-                NUMBERS,
-                TYPES
-              ]
-            }
+          variants: [
+            { begin: /\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)/ },
+            { begin: /\b(0[oO][0-7][_0-7]*)/ },
+            { begin: /\b(0[bB][01][_01]*)/ },
+            { begin: /\b(\d[_\d]*)/ }
           ]
         },
-        TYPES,
-        C_LINE_COMMENT_MODE,
-        hljs.C_BLOCK_COMMENT_MODE,
-        PREPROCESSOR
-      ]
-    };
-
-    return {
-      name: "C",
-      aliases: [ 'h' ],
-      keywords: KEYWORDS,
-      // Until differentiations are added between `c` and `cpp`, `c` will
-      // not be auto-detected to avoid auto-detect conflicts between C and C++
-      disableAutodetect: true,
-      illegal: '=]/,
-            contains: [
-              { beginKeywords: "final class struct" },
-              hljs.TITLE_MODE
-            ]
+        {
+          begin: [
+            /let|var/,
+            /\s+/,
+            hljs.IDENT_RE
+          ],
+          className: {
+            1: "keyword",
+            3: "variable"
           }
-        ]),
-      exports: {
-        preprocessor: PREPROCESSOR,
-        strings: STRINGS,
-        keywords: KEYWORDS
-      }
-    };
-  }
-
-  /*
-  Language: OCaml
-  Author: Mehdi Dogguy 
-  Contributors: Nicolas Braud-Santoni , Mickael Delahaye 
-  Description: OCaml language definition.
-  Website: https://ocaml.org
-  Category: functional
-  */
-
-  function ocaml(hljs) {
-    /* missing support for heredoc-like string (OCaml 4.0.2+) */
-    return {
-      name: 'OCaml',
-      aliases: [ 'ml' ],
-      keywords: {
-        $pattern: '[a-z_]\\w*!?',
-        keyword:
-          'and as assert asr begin class constraint do done downto else end '
-          + 'exception external for fun function functor if in include '
-          + 'inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method '
-          + 'mod module mutable new object of open! open or private rec sig struct '
-          + 'then to try type val! val virtual when while with '
-          /* camlp4 */
-          + 'parser value',
-        built_in:
-          /* built-in types */
-          'array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit '
-          /* (some) types in Pervasives */
-          + 'in_channel out_channel ref',
-        literal:
-          'true false'
-      },
-      illegal: /\/\/|>>/,
-      contains: [
+        },
         {
-          className: 'literal',
-          begin: '\\[(\\|\\|)?\\]|\\(\\)',
-          relevance: 0
+          begin: [
+            /const/,
+            /\s+/,
+            hljs.IDENT_RE
+          ],
+          className: {
+            1: "keyword",
+            3: "constant"
+          }
         },
-        hljs.COMMENT(
-          '\\(\\*',
-          '\\*\\)',
-          { contains: [ 'self' ] }
-        ),
-        { /* type variable */
-          className: 'symbol',
-          begin: '\'[A-Za-z_](?!\')[\\w\']*'
-          /* the grammar is ambiguous on how 'a'b should be interpreted but not the compiler */
+        {
+          begin: [
+            /func|macro|mod/,
+            /\s+/,
+            hljs.IDENT_RE
+          ],
+          className: {
+            1: "keyword",
+            3: "function"
+          }
         },
-        { /* polymorphic variant */
-          className: 'type',
-          begin: '`[A-Z][\\w\']*'
+        {
+          begin: [
+            /type/,
+            /\s+/,
+            hljs.IDENT_RE
+          ],
+          className: {
+            1: "keyword",
+            3: "type"
+          }
         },
-        { /* module or constructor */
-          className: 'type',
-          begin: '\\b[A-Z][\\w\']*',
-          relevance: 0
+        {
+          begin: [
+            hljs.IDENT_RE,
+            /\(/
+          ],
+          className: {
+            1: "function"
+          }
         },
-        { /* don't color identifiers, but safely catch all identifiers with ' */
-          begin: '[a-z_]\\w*\'[\\w\']*',
-          relevance: 0
+        {
+          begin: [
+            hljs.IDENT_RE,
+            /\:/
+          ],
+          className: {
+            1: "params"
+          }
         },
-        hljs.inherit(hljs.APOS_STRING_MODE, {
-          className: 'string',
-          relevance: 0
-        }),
-        hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }),
         {
-          className: 'number',
-          begin:
-            '\\b(0[xX][a-fA-F0-9_]+[Lln]?|'
-            + '0[oO][0-7_]+[Lln]?|'
-            + '0[bB][01_]+[Lln]?|'
-            + '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)',
-          relevance: 0
+          begin: [
+            hljs.IDENT_RE,
+            /\./
+          ],
+          className: {
+            1: "variable"
+          }
         },
-        { begin: /->/ // relevance booster
-        }
-      ]
+        {
+          begin: [
+            /\./,
+            hljs.IDENT_RE,
+            /\b/
+          ],
+          className: {
+            2: "function"
+          }
+        },
+        {
+          className: "punctuation",
+          begin: '->'
+        },
+        {
+          className: "punctuation",
+          begin: '=>'
+        },
+        hljs.HASH_COMMENT_MODE
+      ],
+      keywords: {
+        keyword: KEYWORDS,
+        literal: LITERALS,
+        built_in: BUILT_INS
+      }
     };
   }
 
@@ -4892,6 +5473,7 @@ var hljs = (function () {
     grmr_nim: nim,
     grmr_ocaml: ocaml,
     grmr_puck: puck,
+    grmr_python: python,
     grmr_rust: rust,
     grmr_swift: swift
   });
diff --git a/docs/book/tomorrow-night.css b/docs/book/tomorrow-night.css
index 81fe276..a362570 100644
--- a/docs/book/tomorrow-night.css
+++ b/docs/book/tomorrow-night.css
@@ -21,7 +21,7 @@
 .css .hljs-id,
 .css .hljs-class,
 .css .hljs-pseudo {
-  color: #cc6666;
+  color: #E06C75;
 }
 
 /* Tomorrow Orange */
@@ -38,7 +38,7 @@
 /* Tomorrow Yellow */
 .ruby .hljs-class .hljs-title,
 .css .hljs-rule .hljs-attribute {
-  color: #f0c674;
+  color: #E5C07B;
 }
 
 /* Tomorrow Green */
@@ -49,13 +49,14 @@
 .hljs-name,
 .ruby .hljs-symbol,
 .xml .hljs-cdata {
-  color: #b5bd68;
+  color: #98C379;
 }
 
 /* Tomorrow Aqua */
 .hljs-title,
+.hljs-type,
 .css .hljs-hexcolor {
-  color: #8abeb7;
+  color: #56B6C2;
 }
 
 /* Tomorrow Blue */
@@ -67,13 +68,13 @@
 .perl .hljs-sub,
 .javascript .hljs-title,
 .coffeescript .hljs-title {
-  color: #81a2be;
+  color: #61AFEF;
 }
 
-/* Tomorrow Purple */
+/* One Dark Purple */
 .hljs-keyword,
 .javascript .hljs-function {
-  color: #b294bb;
+  color: #C678DD;
 }
 
 .hljs {
-- 
cgit v1.2.3-70-g09d2