diff pygments_lexer_pseudocode2/algpseudocode.py @ 53:39151225fb84

Rename the new pseudocode implementation to AlgPseudocode. Because it is modelled after CTAN's algpseudocode(x).
author Franz Glasner <fzglas.hg@dom66.de>
date Sun, 26 Apr 2026 19:16:23 +0200
parents pygments_lexer_pseudocode2/pseudocode.py@5bfa9113d3c4
children e8f4af9e20a8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pygments_lexer_pseudocode2/algpseudocode.py	Sun Apr 26 19:16:23 2026 +0200
@@ -0,0 +1,163 @@
+
+# -*- coding: utf-8 -*-
+# :-
+# SPDX-FileCopyrightText: © 2026 Franz Glasner
+# SPDX-License-Identifier: MIT
+# :-
+r"""A pseudocode lexer along the lines of CTAN's algpseudocode or
+algpseudocodex.
+
+"""
+
+__all__ = ["AlgPseudocodeLexer",
+           "AlgPseudocodeLexer_DE", "AlgPseudocodeLexer_FR"]
+
+
+import re
+
+from pygments.lexer import include, bygroups
+from pygments.token import (Comment, Keyword, Name, Text, Whitespace)
+
+#
+# Relative imports do not work with pygments.lexers.load_lexer_from_file()
+# in all of our supported Python releases.
+#
+from pygments_lexer_pseudocode2.bases import LexBase
+
+
+class AlgPseudocodeLexer(LexBase):
+
+    """A pseudocode lexer along the lines of CTAN's algpseudocode or
+    algpseudocodex.
+
+    Some ideas (e.g. strings) are borrowed from Pygment's Python lexer.
+
+    """
+
+    name = "AlgPseudocode"
+    aliases = ["algpseudocode", "algpseudo"]
+    filenames = ["*.algpseudo", "*.algpseudocode"]
+    mimetypes = []
+    flags = re.MULTILINE
+
+    LANG = "en"
+    TRANSLATIONS = {
+        "PROG": "PROGRAM",
+        "PROGRAM": "PROGRAM",
+        "ALGO": "ALGORITHM",
+        "ALGORITHM": "ALGORITHM",
+        "PROC": "PROCEDURE",
+        "PROCEDURE": "PROCEDURE",
+        "FUNC": "FUNCTION",
+        "FUNCTION": "FUNCTION",
+        "FN": "FUNCTION",
+        "CLASS": "CLASS",
+    }
+    SYMBOLS = {
+        "REMARK": "▷",  # U+25B7: Unicode 1.0 (Arrows)
+        "Remark": "▷",
+        "remark": "▷",
+        "REM": "▷",
+        "Rem": "▷",
+        "rem": "▷",
+        "R": "▷",
+        "r": "▷",
+        "BLOCK": "┃",   # U+2503: Unicode 1.0 (Bow Drawing)
+        "Block": "┃",
+        "block": "┃",
+    }
+
+    def op_translate(toktype):
+
+        def _op_translate(lexer, match, ctx=None):
+            kw = match.group().upper()
+            yield match.start(), toktype, lexer.TRANSLATIONS.get(kw, kw)
+
+        return _op_translate
+
+    def op_symbol(toktype):
+
+        def _op_symbol(lexer, match, ctx=None):
+            kw = match.group()
+            yield match.start(), toktype, lexer.SYMBOLS.get(kw, kw)
+
+        return _op_symbol
+
+    tokens = {
+        "root": [
+            (r"\n", Whitespace),
+            (r"/\*", Comment.Multiline, "multiline-nested-comment"),
+            (r"//.*$", Comment.Single),
+            (r"(?:\\)(REMARK|Remark|remark|REM|Rem|rem|R|r)\b(.*)$",
+             bygroups(op_symbol(Comment.Single), Comment.Single)),
+            (r"(?:\\)(BLOCK|Block|block)\b(.*)$",
+             bygroups(op_symbol(Text), Text)),
+            (r"\\\n", Text),
+            (r"(?i)\\("
+             r"(?:prog(?:ram)?)"
+             r"|(?:algo(?:rithm)?)"
+             r"|(?:proc(?:edure)?)"
+             r"|(?:func(?:tion)?|(?:fn))"
+             r"|(?:class)"
+             r")(\s*)(\{)",
+             bygroups(op_translate(Keyword), Whitespace, Name.Entity),
+             "entity-name"),
+            include("expr"),
+            (r"\s+", Text),
+        ],
+        "entity-name": [       # may be multiline
+            (r"[^\\}]+", Name.Entity),
+            (r"\\\}", Name.Entity),
+            (r"\\", Name.Entity),
+            (r"\}", Name.Entity, "#pop"),
+        ],
+        "expr": [
+            include("py-strings"),
+            include("py-numbers"),
+            include("py-name"),
+        ]
+    }
+
+
+class AlgPseudocodeLexer_DE(AlgPseudocodeLexer):
+
+    name = "AlgPseudocodeDE"
+    aliases = ["algpseudocode-de", "algpseudo-de"]
+    filenames = ["*.algpseudo-de", "*.algpseudocode-de"]
+
+    LANG = "de"
+    TRANSLATIONS = AlgPseudocodeLexer.TRANSLATIONS.copy()
+    TRANSLATIONS.update({
+        "PROG": "PROGRAMM",
+        "PROGRAM": "PROGRAMM",
+        "ALGO": "ALGORITHMUS",
+        "ALGORITHM": "ALGORITHMUS",
+        "PROC": "PROZEDUR",
+        "PROCEDURE": "PROZEDUR",
+        "FUNC": "FUNKTION",
+        "FUNCTION": "FUNKTION",
+        "FN": "FUNKTION",
+        "CLASS": "KLASSE",
+    })
+
+
+class AlgPseudocodeLexer_FR(AlgPseudocodeLexer):
+
+    name = "AlgPseudocodeFR"
+    aliases = ["algpseudocode-fr", "algpseudo-fr"]
+    filenames = ["*.algpseudo-fr", "*.algpseudocode-fr"]
+
+    LANG = "de"
+    TRANSLATIONS = AlgPseudocodeLexer.TRANSLATIONS.copy()
+    TRANSLATIONS.update({
+        "PROG": "PROGRAMME",
+        "PROGRAM": "PROGRAMME",
+        "ALGO": "ALGORITHME",
+        "ALGORITHM": "ALGORITHME",
+        "PROC": "PROCÉDURE",
+        "PROCEDURE": "PROCÉDURE",
+        "FUNC": "FONCTION",
+        "FUNCTION": "FOUNCTION",
+        "FN": "FONCTION",
+        "CLASS": "CLASSE",
+    })