# HG changeset patch # User Franz Glasner # Date 1778267994 -7200 # Node ID a4317957148b49dca02feea3669812adcbb0b74d # Parent 315cfe0a836fb42cda7fd86d50ac74db1a2741b0 Move all lexers into a subpackage pygments_lexer_pseudocode2.lexers. This is to prepare for a new subpackage with filters. diff -r 315cfe0a836f -r a4317957148b docs/conf.py --- a/docs/conf.py Fri May 08 19:49:08 2026 +0200 +++ b/docs/conf.py Fri May 08 21:19:54 2026 +0200 @@ -12,7 +12,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath('.'))) -from pygments_lexer_pseudocode2.algpseudocode import AlgPseudocodeLexer +from pygments_lexer_pseudocode2.lexers.algpseudocode import AlgPseudocodeLexer needs_sphinx = '2.1' diff -r 315cfe0a836f -r a4317957148b docs/details-algpseudocode.rst --- a/docs/details-algpseudocode.rst Fri May 08 19:49:08 2026 +0200 +++ b/docs/details-algpseudocode.rst Fri May 08 21:19:54 2026 +0200 @@ -421,7 +421,7 @@ .. code-block:: python from functools import partial - from pygments_lexer_pseudocode2.algpseudocode import AlgPseudocodeLexer + from pygments_lexer_pseudocode2.lexers.algpseudocode import AlgPseudocodeLexer def setup(app): diff -r 315cfe0a836f -r a4317957148b docs/intro.rst --- a/docs/intro.rst Fri May 08 19:49:08 2026 +0200 +++ b/docs/intro.rst Fri May 08 21:19:54 2026 +0200 @@ -125,4 +125,10 @@ :language: algpseudocode-fr :lines: 2- +And again the *Edmonds–Karp Algorithm* with german keywords: + +.. literalinclude:: examples/algorithm-edmonds-karp.pseudocode + :language: algpseudocode-de + :lines: 2- + More details you will find :ref:`here `. diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/algpseudocode.py --- a/pygments_lexer_pseudocode2/algpseudocode.py Fri May 08 19:49:08 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,691 +0,0 @@ -# -*- 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 logging -import re - -import pygments.util -from pygments.lexer import bygroups, include, words -from pygments.token import (Comment, Error, Generic, Keyword, Name, Operator, - Punctuation, 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 -from pygments_lexer_pseudocode2.utils import REVERSED_STANDARD_TYPES -from pygments_lexer_pseudocode2 import uniprops - -# -# As in the local imports: use an explicit name because __name__ is -# __builtins__ -# -_logger = logging.getLogger("pygments_lexer_pseudocode2.algpseudocode") - - -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", - "INPUT": "Input:", - "INPUTS": "Inputs:", - "OUTPUT": "Output:", - "OUTPUTS": "Outputs:", - "RETURNS": "Returns:", - "ENSURE": "Ensure:", - "REQUIRE": "Require:", - "IS": "IS", - "WITH": "WITH", - "IF": "IF", - "THEN": "THEN", - "ELSE": "ELSE", - "ELSEIF": "ELSE IF", - "ELSIF": "ELSE IF", - "ELIF": "ELSE IF", - "DO": "DO", # in WHILE ... DO - "WHILE": "WHILE", - "FOR": "FOR", - "FORALL": "FOR ALL", - "FROM": "FROM", - "TO": "TO", - "IN": "IN", # as in FOR ... IN - "STEP": "STEP", - "LOOP": "LOOP", - "REPEAT": "REPEAT", - "UNTIL": "UNTIL", - "RETURN": "RETURN", - "BEGIN": "BEGIN", - "END": "END", # not in END_TRANSLATIONS - } - END_TRANSLATIONS = { - "PROG": "END OF PROGRAM", - "PROGRAM": "END OF PROGRAM", - "ALGO": "END OF ALGORITHM", - "ALGORITHM": "END OF ALGORITHM", - "PROC": "END OF PROCEDURE", - "PROCEDURE": "END OF PROCEDURE", - "FUNC": "END OF FUNCTION", - "FUNCTION": "END OF FUNCTION", - "FN": "END OF FUNCTION", - "CLASS": "END OF CLASS", - "IF": "END IF", - "WHILE": "END WHILE", - "FOR": "END FOR", - "FORALL": "END FOR ALL", - "LOOP": "END LOOP", - } - DEFAULT_END_PREFIX = "END OF " - SYMBOL_REMARK = u"▷" # U+25B7: Unicode 1.0 (Geometric Shapes) - # SYMBOL_REMARK = u"▻" # U+25BB: Unicode 1.0 (Geometric Shapes) - # SYMBOL_REMARK = u"⍝" # U+235D: Unicode 1.1 (Misc. Technical, APL) - SYMBOL_BLOCK = u"◆" # U+25C6: Unicode 1.0 (Geometric Shapes) - # SYMBOL_BLOCK = u"┃" # U+2503: Unicode 1.0 (Bow Drawing) - # SYMBOL_BLOCK = u"●" # U+25CF: Unicode 1.0 (Geometric Shapes) - SYMBOL_TEXTSTATEMENT = u"▪" # U+25AA: Unicode 1.0 (Geometric Shapes) - # SYMBOL_TEXTSTATEMENT = u"■" # U+25A0: Unicode 1.0 (Geometric Shapes) - SYMBOLS = { - # Group REMARK - "REMARK": SYMBOL_REMARK, - "REM": SYMBOL_REMARK, - # Group STATEMENT - "STATEMENT": SYMBOL_BLOCK, - "STATE": SYMBOL_BLOCK, - "BLOCK": SYMBOL_BLOCK, - # Group TEXTSTATEMENT - "TEXTSTATEMENT": SYMBOL_TEXTSTATEMENT, - "TEXTSTATE": SYMBOL_TEXTSTATEMENT, - "TSTATEMENT": SYMBOL_TEXTSTATEMENT, - "TSTATE": SYMBOL_TEXTSTATEMENT, - "TEXTBLOCK": SYMBOL_TEXTSTATEMENT, - "TBLOCK": SYMBOL_TEXTSTATEMENT, - "<-": u"⟵", # U+27F5: Unicode 3.2 (Supplemental Arrows-A) - "->": u"⟶", # U+27F6: Unicode 3.2 (Supplemental Arrows-A) - "<->": u"⟷", # U+27F7: Unicode 3.2 (Supplemental Arrows-A) - # "=>": u"⟹", # U+27F9: Unicode 3.2 (Supplemental Arrows-A) - # "<=>": u"⟺", # U+27FA: Unicode 3.2 (Supplemental Arrows-A) - # "<-": u"←", # U+2190: Unicode 1.0 (Arrows) - # "->": u"→", # U+2192: Unicode 1.0 (Arrows) - # "<->": u"↔", # U+2194: Unicode 1.0 (Arrows) - "=>": u"⇒", # U+21D2: Unicode 1.0 (Arrows) - "<=>": u"⇔", # U+21D4: Unicode 1.0 (Arrows) - "<=": u"≤", # U+2264: Unicode 1.0 (Mathematical Operators) - ">=": u"≥", # U+2265: Unicode 1.0 (Mathematical Operators) - "<>": u"≠", # U+2260: Unicode 1.0 (Mathematical Operators) - "!=": u"≠", # U+2260: Unicode 1.0 (Mathematical Operators) - ":=": u"∶=", # "≔" U+2254 not recognizable in my (small) mono font - "=:": u"=∶", # "≕" U+2255 not recognizable in my (small) mono font - "?=": u"≟", # U+225F: Unicode 1.0 (Mathematical Operators) - } - - def op_translate(toktype): - - def _op_translate(lexer, match, ctx=None): - kw = match.group().upper() - yield match.start(), toktype, lexer.TRANSLATIONS.get(kw, kw) - if ctx: - ctx.pos = match.end() - - return _op_translate - - def op_opt_end_translate(toktype): - - def _op_end_translate(lexer, match, ctx=None): - if not lexer.no_end: - kw = match.group().upper() - yield (match.start(), - toktype, - lexer.END_TRANSLATIONS.get( - kw, - lexer.DEFAULT_END_PREFIX + kw)) - if ctx: - ctx.pos = match.end() - - return _op_end_translate - - def op_opt_ignore(toktype): - - def _op_opt_ignore(lexer, match, ctx=None): - if not lexer.no_end: - yield match.start(), toktype, match.group() - if ctx: - ctx.pos = match.end() - - return _op_opt_ignore - - def op_opt_ignore_or_fixed(toktype, value): - """Yield a fixed given token type and value or -- if the lexer's - `no_end` setting evals to ``True`` nothing. - - """ - - def _op_opt_ignore_or_fixed(lexer, match, ctx=None): - if not lexer.no_end: - yield match.start(), toktype, value - if ctx: - ctx.pos = match.end() - - return _op_opt_ignore_or_fixed - - def op_gets(lexer, match, ctx=None): - yield match.start(), Operator, lexer.symbol_gets - - def op_remark(lexer, match, ctx=None): - yield match.start(), Comment.Single, lexer.symbol_remark - - def op_symbol(toktype): - - def _op_symbol(lexer, match, ctx=None): - kw = match.group().upper() - yield match.start(), toktype, lexer.SYMBOLS.get(kw, kw) - if ctx: - ctx.pos = match.end() - - return _op_symbol - - def op_explicit_tokentype(lexer, match, ctx=None): - needed_css = match.group("type") - toktype = REVERSED_STANDARD_TYPES.get(needed_css, None) - if toktype is None: - # Be more error friendly - toktype = Generic.Error - val = match.group() - _logger.warning("Unhandled explicit token type: %s", val) - else: - val = match.group("character") - yield match.start(), toktype, val - if ctx: - ctx.pos = match.end() - - tokens = { - "root": [ - (r"\n", Whitespace), - (r"/\*", Comment.Multiline, "multiline-nested-comment"), - (r"\(\*", Comment.Multiline, "multiline-nested-comment-alt"), - (r"(//|#).*$", Comment.Single), - include("remark"), - (r"(?i)\\(block|state(?:ment)?)[ \t]*(\{)", - bygroups(op_symbol(Text), LexBase.op_fixed(Whitespace, " ")), - "block-expr"), - (r"(?i)\\(" - r"(?:textstate(?:ment)?)" - r"|(?:tstate(?:ment)?)" - r"|(?:textblock)" - r"|(?:tblock)" - r")[ \t]*(\{)", - bygroups(op_symbol(Text), LexBase.op_fixed(Whitespace, " ")), - "text-statement"), - (r"(?i)\\(" - r"(?:input(?:s)?)" - r"|(?:output(?:s)?)" - r"|(?:ensure)" - r"|(?:require)" - r"|(?:returns)" - r")[ \t]*(\{)", - bygroups(op_translate(Keyword), - LexBase.op_fixed(Whitespace, " ")), - "text-statement"), - (r"(?i)\\(" - r"(?:if)" - r"|(?:then)" - r"|(?:else)" - r"|(?:el(?:s(?:e)?)?if)" - r"|(?:do)" # as in WHILE ... DO not DO ... UNTIL - r"|(?:while)" - r"|(?:forall)" - r"|(?:for)" - r"|(?:from)" - r"|(?:to)" - r"|(?:step)" - r"|(?:in)" - r"|(?:loop)" - r"|(?:repeat)" - r"|(?:until)" - r"|(?:return)" - r")\b", - bygroups(op_translate(Keyword))), - (r"\\\n", Text), - (r"(?i)\\(" - r"(?:prog(?:ram)?)" - r"|(?:algo(?:rithm)?)" - r"|(?:proc(?:edure)?)" - r"|(?:func(?:tion)?|(?:fn))" - r"|(?:class)" - r")[ \t]*(\{)", - bygroups(op_translate(Keyword), - LexBase.op_fixed(Whitespace, " ")), - "entity-name"), - # ENDxxx keywords with optional entity name in two parts: - # 1. with name - (r"(?i)\\end(?:[_\-]|(?:[ \t]+))?(" - r"(?:prog(?:ram)?)" - r"|(?:algo(?:rithm)?)" - r"|(?:proc(?:edure)?)" - r"|(?:func(?:tion)?)" - r"|(?:fn)" - r"|(?:class)" - r")(?:[_\-]|(?:[\t ]+))?(\{)", - bygroups(op_opt_end_translate(Keyword), - op_opt_ignore_or_fixed(Whitespace, " ")), - "entity-name-end"), - # 2. without name - # 3. AND keywords that do not allow a param (e.g. endif) - (r"(?i)\\end(?:[_\-]|(?:[ \t]+))?(" - r"(?:prog(?:ram)?)" - r"|(?:algo(?:rithm)?)" - r"|(?:proc(?:edure)?)" - r"|(?:func(?:tion)?)" - r"|(?:fn)" - r"|(?:class)" - r"|(?:if)" - r"|(?:while)" - r"|(?:for)" - r"|(?:forall)" - r"|(?:loop)" - r")\b", - bygroups(op_opt_end_translate(Keyword))), - # - # A single begin or end that is never suppressed because - # it is supposed to be paired with begin - # - (r"(?i)\\(begin|end)\b", - bygroups(op_translate(Keyword))), - # Keywords - (r"(?i)\\(" - r"(?:is)" - r"|(?:with)" - r")\b", - bygroups(op_translate(Keyword))), - include("expr"), - include("unicode-separators"), - include("unicode-other"), - (r"[^\S\n]+", Text), - # (r".", Generic.Error), # tolerance for errors - (r".", Error), - ], - "remark": [ - (r"(?i)\\(remark|rem)\b(.*)$", - bygroups(op_remark, Comment.Single)), - ], - "entity-name": [ # may be multiline - (r"[^\\}]+", Name.Entity), - (r"\}", LexBase.op_ignore, "#pop"), - (r"\\\}", LexBase.op_fixed(Name.Entity, "}")), - (r"\\\\", LexBase.op_fixed(Name.Entity, "\\")), - (r"\\", LexBase.op_fixed(Generic.Error, "\\")), - ], - "entity-name-end": [ # may be multiline -- suppressed if no_end - (r"[^\\}]+", op_opt_ignore(Name.Entity)), - (r"\}", LexBase.op_ignore, "#pop"), - (r"\\\}", op_opt_ignore_or_fixed(Name.Entity, "}")), - (r"\\\\", op_opt_ignore_or_fixed(Name.Entity, "\\")), - (r"\\", op_opt_ignore_or_fixed(Generic.Error, "\\")), - ], - "expr": [ - include("math-symbols"), # must be before punctuation - include("ascii-punctuation"), - include("unicode-punctuation"), - include("escaped-string-start"), - include("py-strings"), - include("py-numbers"), - (r"(?i)\\(call|name)[ \t]*(\{)", LexBase.op_ignore, "entity-name"), - (r"(?i)\\gets\b", op_gets), - (r"(?i)\\text[ \t]*\{", LexBase.op_ignore, "text-in-expr"), - include("explicit-tokentype"), - include("remark"), - include("keyword-constants"), - include("word-operators"), - include("math-builtins"), - include("py-name"), - ], - "expr-in-braces": [ - include("math-symbols"), # must be before punctuation - include("ascii-punctuation-in-braces"), - include("unicode-punctuation"), - include("escaped-string-start"), - include("py-strings"), - include("py-numbers"), - (r"(?i)\\(call|name)[ \t]*(\{)", LexBase.op_ignore, "entity-name"), - (r"(?i)\\gets\b", op_gets), - (r"(?i)\\text[ \t]*\{", LexBase.op_ignore, "text-in-expr"), - include("explicit-tokentype"), - include("remark"), - include("keyword-constants"), - include("word-operators"), - include("math-builtins"), - include("py-name"), - ], - "block-expr": [ # somewhat similar to "root" - (r"\}", LexBase.op_ignore, "#pop"), - (r"\n", Whitespace), - include("expr-in-braces"), - (r"\\\\", LexBase.op_fixed(Text, "\\")), - (r"\\", LexBase.op_fixed(Generic.Error, "\\")), - include("unicode-separators"), - include("unicode-other"), - (r"[^\S\n]+", Text), - (r".", Error), - ], - "text-statement": [ # like block but default to text-mode - (r"[^\\}\n]+", Text), - (r"\}", LexBase.op_ignore, "#pop"), - (r"\n", Whitespace), - (r"\\\}", LexBase.op_fixed(Text, "}")), - (r"(?i)\\expr(?:ession)?[ \t]*\{", - LexBase.op_ignore, - "block-expr"), - include("explicit-tokentype"), - include("remark"), - (r"\\\\", LexBase.op_fixed(Text, "\\")), - (r"\\", LexBase.op_fixed(Text, "\\")), # in text-mode: leave Text - (r".", Error), - ], - "text-in-expr": [ - (r"[^\\}\n]+", Text), - (r"\}", LexBase.op_ignore, "#pop"), - (r"\n", Whitespace), - (r"\\\}", LexBase.op_fixed(Text, "}")), - (r"(?i)\\expr(?:ession)?[ \t]*\{", - LexBase.op_ignore, - "block-expr"), - include("explicit-tokentype"), - include("remark"), - (r"\\\\", LexBase.op_fixed(Text, "\\")), - (r"\\", LexBase.op_fixed(Text, "\\")), # in text-mode: leave Text - (r".", Error), - ], - "math-builtins": [ - (words(("sqrt", "pow", "cos", "sin", "tan", "arcos", "arcsin", - "arctan", "arctan2", "mod", "exp", "ln", "log", - "min", "max"), - prefix=r"(?|<->|<-|->|=>|<=|>=|<>|!=|:=|=:|\?=", op_symbol(Operator)), - (r"[!&<>=+\-*/%|~]", Operator), # ASCII - (u"[%s]" % (uniprops.Sm,), Operator), # other Unicode - ], - "word-operators": [ - (words(("IN", "In", "in", - "IS", "Is", "is", - "AND", "And", "and", - "OR", "Or", "or", - "XOR", "Xor", "xor", - "NOT", "Not", "not"), - prefix=r"(?[a-zA-Z0-9_-]+?)(?P[/:|=*+!\$~])" - r"(?P(.|\n)+?)(?P=sep)", - op_explicit_tokentype), - (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\{(?P[^}]+?)\}", - op_explicit_tokentype), - (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\((?P[^)]+?)\)", - op_explicit_tokentype), - (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)<(?P[^>]+?)>", - op_explicit_tokentype), - (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\[(?P[^\]]+?)\]", - op_explicit_tokentype), - - # Every character is possible: no escaping needed! - (r"\\tt-(?P[^/]+?)/(?P(?:.|\n))", - op_explicit_tokentype), - ], - } - - def __init__(self, **options): - self.no_end = pygments.util.get_bool_opt( - options, "no_end", default=False) - self.symbol_gets = options.get("gets", None) - if self.symbol_gets is None: - self.symbol_gets = self.SYMBOLS["<-"] # Default: "⟵" # U+27F5 - self.symbol_remark = options.get("remark", None) - if self.symbol_remark is None: - self.symbol_remark = self.SYMBOLS["REM"] # Default: "▷" # U+25B7 - LexBase.__init__(self, **options) - # - # Do this after calling the base because a "filters" option should be - # allowed to set **any** filter. - # - self.prohibit_raiseonerror_filter = pygments.util.get_bool_opt( - options, "prohibit_raiseonerror_filter", default=False) - - def add_filter(self, filter_, **options): - # - # May be called by Lexer.__init__ when - # self.prohibit_raiseonerror_filter is not yet set. - # This is intentionally so. - # - if getattr(self, "prohibit_raiseonerror_filter", False): - if filter_ in ("raiseonerror",): - return - LexBase.add_filter(self, filter_, **options) - - -class AlgPseudocodeLexer_DE(AlgPseudocodeLexer): - - """ - - .. seealso:: - - https://de.wikipedia.org/wiki/Pseudocode - - .. todo:: Complete german translations - - """ - - 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", - "IS": "IST", - "WITH": "MIT", - "IF": "WENN", - "THEN": "DANN", - "ELSE": "ANDERNFALLS", - "ELSEIF": "ANDERNFALLS WENN", - "ELSIF": "ANDERNFALLS WENN", - "ELIF": "ANDERNFALLS WENN", -# "DO": # XXX TBD # in WHILE WHILE ... DO # noqa # in WHILE ... DO - "WHILE": "SOLANGE", - "FOR": "FÜR", - "FORALL": "FÜR ALLE", - "FROM": "VON", - "TO": "BIS", - "IN": "IN", - "STEP": "SCHRITTWEITE", -# "LOOP": XXX TBD # noqa - "REPEAT": "WIEDERHOLE", - "UNTIL": "BIS", -# "RETURN": XXX TBD # noqa - "BEGIN": "START", - "END": "ENDE", - }) - END_TRANSLATIONS = AlgPseudocodeLexer.END_TRANSLATIONS.copy() - END_TRANSLATIONS.update({ - "PROG": "ENDE DES PROGRAMMS", - "PROGRAM": "ENDE DES PROGRAMMS", - "ALGO": "ENDE DES ALGORITHMUS", - "ALGORITHM": "ENDE DES ALGORITHMUS", - "PROC": "ENDE DER PROZEDUR", - "PROCEDURE": "ENDE DER PROZEDUR", - "FUNC": "ENDE DER FUNKTION", - "FUNCTION": "ENDE DER FUNKTION", - "FN": "ENDE DER FUNKTION", - "CLASS": "ENDE DER KLASSE", - "IF": "ENDE WENN", - "WHILE": "ENDE SOLANGE", - "FOR": "ENDE FÜR", - "FORALL": "ENDE FÜR ALLE", -# "LOOP": "ENDE XXX", # XXX TBD # noqa - }) - DEFAULT_END_PREFIX = "ENDE VON " - - -class AlgPseudocodeLexer_FR(AlgPseudocodeLexer): - - """ - - .. seealso:: - - https://info.blaisepascal.fr/pseudo-code/ - - https://fr.wikipedia.org/wiki/Pseudo-code - - https://fr.wikipedia.org/wiki/Structure_de_contr%C3%B4le - - .. todo:: Complete french translations - - """ - - name = "AlgPseudocodeFR" - aliases = ["algpseudocode-fr", "algpseudo-fr"] - filenames = ["*.algpseudo-fr", "*.algpseudocode-fr"] - - LANG = "fr" - 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", - "IS": "EST", - "WITH": "AVEC", - "IF": "SI", - "THEN": "ALORS", - "ELSE": "SINON", - "ELSEIF": "SINONSI", - "ELSIF": "SINONSI", - "ELIF": "SINONSI", - "DO": "FAIRE", # as in in WHILE ... DO (not DO ... UNTIL) - "WHILE": "TANTQUE", - "FOR": "POUR", - "FORALL": "POUR CHAQUE", - "FROM": "DE", - "TO": "JUSQU'À", # or just "À", - "IN": "DANS", # as in FOR ... IN - "STEP": "PAR PAS DE", - "LOOP": "BOUCLE", # XXX FIXME??? - "REPEAT": "RÉPÉTER", - "UNTIL": "JUSQUACEQUE", - "RETURN": "RENVOYER", - "BEGIN": "DÉBUT", - "END": "FIN", - }) - END_TRANSLATIONS = AlgPseudocodeLexer.END_TRANSLATIONS.copy() - END_TRANSLATIONS.update({ - "PROG": "FIN DE PROGRAMME", - "PROGRAM": "FIN DE PROGRAMME", - "ALGO": "FIN D'ALGORITHME", - "ALGORITHM": "FIN D'ALGORITHME", - "PROC": "FIN DE PROCÉDURE", - "PROCEDURE": "FIN DE PROCÉDURE", - "FUNC": "FIN DE FONCTION", - "FUNCTION": "FIN DE FOUNCTION", - "FN": "FIN DE FONCTION", - "CLASS": "FIN DE CLASSE", - "SI": "FIN SI", - "FOR": "FIN POUR", - "FORALL": "FIN POUR CHAQUE", - "WHILE": "FIN TANTQUE", - "LOOP": "FIN BOUCLE", - }) - DEFAULT_END_PREFIX = "FIN DE " diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/bases.py --- a/pygments_lexer_pseudocode2/bases.py Fri May 08 19:49:08 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -# -*- coding: utf-8 -*- -# :- -# SPDX-FileCopyrightText: © 2026 Franz Glasner -# SPDX-License-Identifier: MIT -# :- -r"""Some common bases for the lexers.""" - -__all__ = ["LexBase", "uni_name", "py_innerstring_rules", "py_name_rules"] - - -import sys - -from pygments import unistring -from pygments.lexer import RegexLexer, combined, bygroups, include -from pygments.token import (Comment, Error, Name, Number, Other, String) - - -PY2 = sys.version_info[0] <= 2 - - -# -# SPDX-SnippetBegin -# SPDX-License-Identifier: BSD-2-Clause -# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team -# SPDX-SnippetCopyrightText: Copyright 2026 by Franz Glasner -# - -uni_name = "[%s][%s]*" % (unistring.xid_start, unistring.xid_continue) - - -"""PY3 allows no @staticmethod but PY2 needs it.""" -if PY2: - _staticmethod = staticmethod -else: - def _staticmethod(fn): - return fn - - -def py_innerstring_rules(ttype): - return [ - # the old style '%s' % (...) string formatting (still valid in Py3) - (r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?' - '[hlL]?[E-GXc-giorsaux%]', String.Interpol), - # the new style '{}'.format(...) string formatting - (r'\{' - r'((\w+)((\.\w+)|(\[[^\]]+\]))*)?' # field name - r'(\![sra])?' # conversion - r'(\:(.?[<>=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?' - r'\}', String.Interpol), - # - # backslashes, quotes and formatting signs must be parsed - # one at a time - # - (r'[^\\\'"%{\n]+', ttype), - (r'[\'"\\]', ttype), - # unhandled string formatting sign - (r'%|(\{{1,2})', ttype) - # newlines are an error (use "nl" state) - ] - - -def py_name_rules(ttype, deco_ttype=Name.Decorator): - return [ - # We recognize decorator syntax here - (r'@' + uni_name, deco_ttype), - # - # Python's new matrix multiplication operator: - # not used here in pseudocode - # (r'@', Operator), - (uni_name, ttype), - ] - -# SPDX-SnippetEnd - - -class LexBase(RegexLexer): - - """A base that defines some common lexer states. - - Default flags are not important. - - """ - - def op_ignore(lexer, match, ctx=None): - """Unconditionally ignore the match.""" - if False: - yield match.start(), Other, "" - if ctx: - ctx.pos = match.end() - - @_staticmethod - def op_fixed(toktype, value): - """Unconditionally yield a given token type and value.""" - - def _op_fixed(lexer, match, ctx=None): - yield match.start(), toktype, value - if ctx: - ctx.pos = match.end() - - return _op_fixed - - tokens = { -# -# These states are borrowed from Pygment's Python lexer. -# Their names have been prefixed with `py-'. -# -# SPDX-SnippetBegin -# SPDX-License-Identifier: BSD-2-Clause -# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team -# SPDX-SnippetCopyrightText: Copyright 2026 by Franz Glasner -# - 'py-numbers': [ - (r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)' - r'([eE][+-]?\d(?:_?\d)*)?', Number.Float), - (r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float), - (r'0[oO](?:_?[0-7])+', Number.Oct), - (r'0[bB](?:_?[01])+', Number.Bin), - (r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex), - (r'\d(?:_?\d)*', Number.Integer), - ], - 'py-strings': [ - # non-raw strings - ('([uU]?)(""")', bygroups(String.Affix, String.Double), - combined('py-stringescape', 'py-tdqs')), - ("([uU]?)(''')", bygroups(String.Affix, String.Single), - combined('py-stringescape', 'py-tsqs')), - ('([uU]?)(")', bygroups(String.Affix, String.Double), - combined('py-stringescape', 'py-dqs')), - ("([uU]?)(')", bygroups(String.Affix, String.Single), - combined('py-stringescape', 'py-sqs')), - # non-raw bytes - ('([bB])(""")', bygroups(String.Affix, String.Double), - combined('py-bytesescape', 'py-tdqs')), - ("([bB])(''')", bygroups(String.Affix, String.Single), - combined('py-bytesescape', 'py-tsqs')), - ('([bB])(")', bygroups(String.Affix, String.Double), - combined('py-bytesescape', 'py-dqs')), - ("([bB])(')", bygroups(String.Affix, String.Single), - combined('py-bytesescape', 'py-sqs')), - ], - 'py-stringescape': [ - (r'\\(N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8})', String.Escape), - include('py-bytesescape') - ], - 'py-bytesescape': [ - (r'\\([\\abfnrtv"\']|\n|x[a-fA-F0-9]{2}|[0-7]{1,3})', - String.Escape) - ], - 'py-dqs': [ - (r'"', String.Double, '#pop'), - (r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings - include('py-strings-double'), - (r'\n', Error), # added by fag - ], - 'py-sqs': [ - (r"'", String.Single, '#pop'), - (r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings - include('py-strings-single'), - (r'\n', Error), # added by fag - ], - 'py-tdqs': [ - (r'"""', String.Double, '#pop'), - include('py-strings-double'), - (r'\n', String.Double) - ], - 'py-tsqs': [ - (r"'''", String.Single, '#pop'), - include('py-strings-single'), - (r'\n', String.Single) - ], - 'py-strings-single': py_innerstring_rules(String.Single), - 'py-strings-double': py_innerstring_rules(String.Double), - 'py-name': py_name_rules(Name.Entity), -# SPDX-SnippetEnd - # This snippet is from the Pygments' documentation "Write your own lexer" - 'multiline-nested-comment': [ - (r'[^*/]+', Comment.Multiline), - (r'/\*', Comment.Multiline, '#push'), - (r'\*/', Comment.Multiline, '#pop'), - (r'[*/]', Comment.Multiline), - ], - 'multiline-nested-comment-alt': [ - (r'[^*()]+', Comment.Multiline), - (r'\(\*', Comment.Multiline, '#push'), - (r'\*\)', Comment.Multiline, '#pop'), - (r'[*()]', Comment.Multiline), - ] - } diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/fr_pseudocode.py --- a/pygments_lexer_pseudocode2/fr_pseudocode.py Fri May 08 19:49:08 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -# -*- coding: utf-8 -*- -# :- -# SPDX-FileCopyrightText: © 2015 Simon Wachter -# SPDX-FileCopyrightText: © 2026 Franz Glasner -# SPDX-License-Identifier: MIT -# :- -r""" -:Author: Simon Wachter -:Author: Franz Glasner -:Copyright: © 2015 Simon Wachter -:Copyright: © 2026 Franz Glasner -:License: MIT License. - See :file:`MIT.txt` for details. - If you cannot find MIT.txt see - . -""" - -__all__ = ["FrPseudocodeLexer"] - - -import re - -from pygments.lexer import RegexLexer, include -from pygments.token import Punctuation, Whitespace, Comment, Operator, Keyword, Name, String, Number - - -class FrPseudocodeLexer(RegexLexer): - ''' - A Pseudo code (fr) lexer - ''' - name = 'FrPseudocode' - aliases = ['fr-pseudocode', 'fr-pseudo', 'fr-algorithm', 'fr-algo'] - filenames = ['*.fr-algo', '*.fr-pseudocode'] - mimetypes = [] - flags = re.MULTILINE - - REPLACEMENTS = { - '<=': '≤', - '>=': '≥', - '<>': '≠', - '!=': '≠', - '<-': '←', - '->': '→', - '=>': '⇒', - '<->': '↔', - '<=>': '⇔', - '^': '↑', - } - - def op_replace(lexer, match): - op = match.group(0) - yield match.start(), Operator, lexer.REPLACEMENTS.get(op, op) - - def scomment(lexer, match): - s = match.group(1).lower().strip() - c = Comment - - directives = ['passage par copie', 'passage par valeur', 'passage par référence', 'passage par reference', 'passage par adresse', 've', 'vs', 've/s'] - - if s in directives: - c = Comment.Special - - yield match.start(), c, match.group(0) - - tokens = { - 'root': [ - (r'\/\*.*\*\/', Comment), - (r'(\/\/|#).*\n', Comment), - (r'\|', Comment), - (r'\{(.*)\}', scomment), - include('strings'), - include('core'), - (r'(?i)[a-zéàùçèÉÀÙÇÈ][a-z0-9éàùçèÉÀÙÇÈ_]*', Name.Variable), - include('numbers'), - (r'[\s]+', Whitespace) - ], - 'core': [ # Statements - (r'(?i)\b(debut|début|fin|si|alors|sinon|fin[_ ]si|tant[ _]que|tantque|fin[ _]tantque|faire|répéter|' - r'repeter|type|structure|fin[ _]structure|fonction|procédure|procedure|retourner|renvoyer|' - r'pour|fin[ _]pour|à|déclarations?|juqsque|spécialise|specialise|comporte|super|public|privé|protégé|' - r'classe' - r')\s*\b', Keyword), - - # Data Types - (r'(?i)\b(entiers?|chaines?|chaînes?|réels?|reels?|caractères?|caracteres?|booléens?|' - r'booleens?|tableaux?|rien)\s*\b', - Keyword.Type), - - (r'(?i)\b(vrai|faux|nil)\s*\b', - Name.Constant), - - # Operators - (r'(?i)(<->|<=>|<=|>=|<>|!=|<-|->|=>|\^|\*|\+|-|\/|<|>|=|\\\\|mod|←|↑|≤|≥|≠|÷|×|\.\.|\[|\]|\.|non|xou|et|ou)', - op_replace), - - (r'(\(|\)|\,|\;|:)', - Punctuation), - - #(r'\b(\[(VE|VS|VE/S)\])\s*\b', - # Keyword.Declaration), - - # Intrinsics - (r'(?i)\b(sqrt|pow|cos|sin|tan|arccos|arcsin|arctan|arctan2|lire|ecrire|écrire|' - r'exp|ln|log|détruire|detruire' - r')\s*\b', Name.Builtin) - ], - - 'strings': [ - (r'"([^"])*"', String.Double), - (r"'([^'])*'", String.Single), - ], -# -# This is stolen from the Pygment's Python lexer. -# -# SPDX-SnippetBegin -# SPDX-License-Identifier: BSD-2-Clause -# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team - 'numbers': [ - (r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)' - r'([eE][+-]?\d(?:_?\d)*)?', Number.Float), - (r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float), - (r'0[oO](?:_?[0-7])+', Number.Oct), - (r'0[bB](?:_?[01])+', Number.Bin), - (r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex), - (r'\d(?:_?\d)*', Number.Integer), - ], -# SPDX-SnippetEnd - } diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/lexers/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygments_lexer_pseudocode2/lexers/__init__.py Fri May 08 21:19:54 2026 +0200 @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# :- +# SPDX-FileCopyrightText: © 2026 Franz Glasner +# SPDX-License-Identifier: MIT +# :- +r"Sub-package for all lexers.""" diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/lexers/algpseudocode.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygments_lexer_pseudocode2/lexers/algpseudocode.py Fri May 08 21:19:54 2026 +0200 @@ -0,0 +1,691 @@ +# -*- 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 logging +import re + +import pygments.util +from pygments.lexer import bygroups, include, words +from pygments.token import (Comment, Error, Generic, Keyword, Name, Operator, + Punctuation, 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.lexers.bases import LexBase +from pygments_lexer_pseudocode2.utils import REVERSED_STANDARD_TYPES +from pygments_lexer_pseudocode2 import uniprops + +# +# As in the local imports: use an explicit name because __name__ is +# __builtins__ +# +_logger = logging.getLogger("pygments_lexer_pseudocode2.algpseudocode") + + +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", + "INPUT": "Input:", + "INPUTS": "Inputs:", + "OUTPUT": "Output:", + "OUTPUTS": "Outputs:", + "RETURNS": "Returns:", + "ENSURE": "Ensure:", + "REQUIRE": "Require:", + "IS": "IS", + "WITH": "WITH", + "IF": "IF", + "THEN": "THEN", + "ELSE": "ELSE", + "ELSEIF": "ELSE IF", + "ELSIF": "ELSE IF", + "ELIF": "ELSE IF", + "DO": "DO", # in WHILE ... DO + "WHILE": "WHILE", + "FOR": "FOR", + "FORALL": "FOR ALL", + "FROM": "FROM", + "TO": "TO", + "IN": "IN", # as in FOR ... IN + "STEP": "STEP", + "LOOP": "LOOP", + "REPEAT": "REPEAT", + "UNTIL": "UNTIL", + "RETURN": "RETURN", + "BEGIN": "BEGIN", + "END": "END", # not in END_TRANSLATIONS + } + END_TRANSLATIONS = { + "PROG": "END OF PROGRAM", + "PROGRAM": "END OF PROGRAM", + "ALGO": "END OF ALGORITHM", + "ALGORITHM": "END OF ALGORITHM", + "PROC": "END OF PROCEDURE", + "PROCEDURE": "END OF PROCEDURE", + "FUNC": "END OF FUNCTION", + "FUNCTION": "END OF FUNCTION", + "FN": "END OF FUNCTION", + "CLASS": "END OF CLASS", + "IF": "END IF", + "WHILE": "END WHILE", + "FOR": "END FOR", + "FORALL": "END FOR ALL", + "LOOP": "END LOOP", + } + DEFAULT_END_PREFIX = "END OF " + SYMBOL_REMARK = u"▷" # U+25B7: Unicode 1.0 (Geometric Shapes) + # SYMBOL_REMARK = u"▻" # U+25BB: Unicode 1.0 (Geometric Shapes) + # SYMBOL_REMARK = u"⍝" # U+235D: Unicode 1.1 (Misc. Technical, APL) + SYMBOL_BLOCK = u"◆" # U+25C6: Unicode 1.0 (Geometric Shapes) + # SYMBOL_BLOCK = u"┃" # U+2503: Unicode 1.0 (Bow Drawing) + # SYMBOL_BLOCK = u"●" # U+25CF: Unicode 1.0 (Geometric Shapes) + SYMBOL_TEXTSTATEMENT = u"▪" # U+25AA: Unicode 1.0 (Geometric Shapes) + # SYMBOL_TEXTSTATEMENT = u"■" # U+25A0: Unicode 1.0 (Geometric Shapes) + SYMBOLS = { + # Group REMARK + "REMARK": SYMBOL_REMARK, + "REM": SYMBOL_REMARK, + # Group STATEMENT + "STATEMENT": SYMBOL_BLOCK, + "STATE": SYMBOL_BLOCK, + "BLOCK": SYMBOL_BLOCK, + # Group TEXTSTATEMENT + "TEXTSTATEMENT": SYMBOL_TEXTSTATEMENT, + "TEXTSTATE": SYMBOL_TEXTSTATEMENT, + "TSTATEMENT": SYMBOL_TEXTSTATEMENT, + "TSTATE": SYMBOL_TEXTSTATEMENT, + "TEXTBLOCK": SYMBOL_TEXTSTATEMENT, + "TBLOCK": SYMBOL_TEXTSTATEMENT, + "<-": u"⟵", # U+27F5: Unicode 3.2 (Supplemental Arrows-A) + "->": u"⟶", # U+27F6: Unicode 3.2 (Supplemental Arrows-A) + "<->": u"⟷", # U+27F7: Unicode 3.2 (Supplemental Arrows-A) + # "=>": u"⟹", # U+27F9: Unicode 3.2 (Supplemental Arrows-A) + # "<=>": u"⟺", # U+27FA: Unicode 3.2 (Supplemental Arrows-A) + # "<-": u"←", # U+2190: Unicode 1.0 (Arrows) + # "->": u"→", # U+2192: Unicode 1.0 (Arrows) + # "<->": u"↔", # U+2194: Unicode 1.0 (Arrows) + "=>": u"⇒", # U+21D2: Unicode 1.0 (Arrows) + "<=>": u"⇔", # U+21D4: Unicode 1.0 (Arrows) + "<=": u"≤", # U+2264: Unicode 1.0 (Mathematical Operators) + ">=": u"≥", # U+2265: Unicode 1.0 (Mathematical Operators) + "<>": u"≠", # U+2260: Unicode 1.0 (Mathematical Operators) + "!=": u"≠", # U+2260: Unicode 1.0 (Mathematical Operators) + ":=": u"∶=", # "≔" U+2254 not recognizable in my (small) mono font + "=:": u"=∶", # "≕" U+2255 not recognizable in my (small) mono font + "?=": u"≟", # U+225F: Unicode 1.0 (Mathematical Operators) + } + + def op_translate(toktype): + + def _op_translate(lexer, match, ctx=None): + kw = match.group().upper() + yield match.start(), toktype, lexer.TRANSLATIONS.get(kw, kw) + if ctx: + ctx.pos = match.end() + + return _op_translate + + def op_opt_end_translate(toktype): + + def _op_end_translate(lexer, match, ctx=None): + if not lexer.no_end: + kw = match.group().upper() + yield (match.start(), + toktype, + lexer.END_TRANSLATIONS.get( + kw, + lexer.DEFAULT_END_PREFIX + kw)) + if ctx: + ctx.pos = match.end() + + return _op_end_translate + + def op_opt_ignore(toktype): + + def _op_opt_ignore(lexer, match, ctx=None): + if not lexer.no_end: + yield match.start(), toktype, match.group() + if ctx: + ctx.pos = match.end() + + return _op_opt_ignore + + def op_opt_ignore_or_fixed(toktype, value): + """Yield a fixed given token type and value or -- if the lexer's + `no_end` setting evals to ``True`` nothing. + + """ + + def _op_opt_ignore_or_fixed(lexer, match, ctx=None): + if not lexer.no_end: + yield match.start(), toktype, value + if ctx: + ctx.pos = match.end() + + return _op_opt_ignore_or_fixed + + def op_gets(lexer, match, ctx=None): + yield match.start(), Operator, lexer.symbol_gets + + def op_remark(lexer, match, ctx=None): + yield match.start(), Comment.Single, lexer.symbol_remark + + def op_symbol(toktype): + + def _op_symbol(lexer, match, ctx=None): + kw = match.group().upper() + yield match.start(), toktype, lexer.SYMBOLS.get(kw, kw) + if ctx: + ctx.pos = match.end() + + return _op_symbol + + def op_explicit_tokentype(lexer, match, ctx=None): + needed_css = match.group("type") + toktype = REVERSED_STANDARD_TYPES.get(needed_css, None) + if toktype is None: + # Be more error friendly + toktype = Generic.Error + val = match.group() + _logger.warning("Unhandled explicit token type: %s", val) + else: + val = match.group("character") + yield match.start(), toktype, val + if ctx: + ctx.pos = match.end() + + tokens = { + "root": [ + (r"\n", Whitespace), + (r"/\*", Comment.Multiline, "multiline-nested-comment"), + (r"\(\*", Comment.Multiline, "multiline-nested-comment-alt"), + (r"(//|#).*$", Comment.Single), + include("remark"), + (r"(?i)\\(block|state(?:ment)?)[ \t]*(\{)", + bygroups(op_symbol(Text), LexBase.op_fixed(Whitespace, " ")), + "block-expr"), + (r"(?i)\\(" + r"(?:textstate(?:ment)?)" + r"|(?:tstate(?:ment)?)" + r"|(?:textblock)" + r"|(?:tblock)" + r")[ \t]*(\{)", + bygroups(op_symbol(Text), LexBase.op_fixed(Whitespace, " ")), + "text-statement"), + (r"(?i)\\(" + r"(?:input(?:s)?)" + r"|(?:output(?:s)?)" + r"|(?:ensure)" + r"|(?:require)" + r"|(?:returns)" + r")[ \t]*(\{)", + bygroups(op_translate(Keyword), + LexBase.op_fixed(Whitespace, " ")), + "text-statement"), + (r"(?i)\\(" + r"(?:if)" + r"|(?:then)" + r"|(?:else)" + r"|(?:el(?:s(?:e)?)?if)" + r"|(?:do)" # as in WHILE ... DO not DO ... UNTIL + r"|(?:while)" + r"|(?:forall)" + r"|(?:for)" + r"|(?:from)" + r"|(?:to)" + r"|(?:step)" + r"|(?:in)" + r"|(?:loop)" + r"|(?:repeat)" + r"|(?:until)" + r"|(?:return)" + r")\b", + bygroups(op_translate(Keyword))), + (r"\\\n", Text), + (r"(?i)\\(" + r"(?:prog(?:ram)?)" + r"|(?:algo(?:rithm)?)" + r"|(?:proc(?:edure)?)" + r"|(?:func(?:tion)?|(?:fn))" + r"|(?:class)" + r")[ \t]*(\{)", + bygroups(op_translate(Keyword), + LexBase.op_fixed(Whitespace, " ")), + "entity-name"), + # ENDxxx keywords with optional entity name in two parts: + # 1. with name + (r"(?i)\\end(?:[_\-]|(?:[ \t]+))?(" + r"(?:prog(?:ram)?)" + r"|(?:algo(?:rithm)?)" + r"|(?:proc(?:edure)?)" + r"|(?:func(?:tion)?)" + r"|(?:fn)" + r"|(?:class)" + r")(?:[_\-]|(?:[\t ]+))?(\{)", + bygroups(op_opt_end_translate(Keyword), + op_opt_ignore_or_fixed(Whitespace, " ")), + "entity-name-end"), + # 2. without name + # 3. AND keywords that do not allow a param (e.g. endif) + (r"(?i)\\end(?:[_\-]|(?:[ \t]+))?(" + r"(?:prog(?:ram)?)" + r"|(?:algo(?:rithm)?)" + r"|(?:proc(?:edure)?)" + r"|(?:func(?:tion)?)" + r"|(?:fn)" + r"|(?:class)" + r"|(?:if)" + r"|(?:while)" + r"|(?:for)" + r"|(?:forall)" + r"|(?:loop)" + r")\b", + bygroups(op_opt_end_translate(Keyword))), + # + # A single begin or end that is never suppressed because + # it is supposed to be paired with begin + # + (r"(?i)\\(begin|end)\b", + bygroups(op_translate(Keyword))), + # Keywords + (r"(?i)\\(" + r"(?:is)" + r"|(?:with)" + r")\b", + bygroups(op_translate(Keyword))), + include("expr"), + include("unicode-separators"), + include("unicode-other"), + (r"[^\S\n]+", Text), + # (r".", Generic.Error), # tolerance for errors + (r".", Error), + ], + "remark": [ + (r"(?i)\\(remark|rem)\b(.*)$", + bygroups(op_remark, Comment.Single)), + ], + "entity-name": [ # may be multiline + (r"[^\\}]+", Name.Entity), + (r"\}", LexBase.op_ignore, "#pop"), + (r"\\\}", LexBase.op_fixed(Name.Entity, "}")), + (r"\\\\", LexBase.op_fixed(Name.Entity, "\\")), + (r"\\", LexBase.op_fixed(Generic.Error, "\\")), + ], + "entity-name-end": [ # may be multiline -- suppressed if no_end + (r"[^\\}]+", op_opt_ignore(Name.Entity)), + (r"\}", LexBase.op_ignore, "#pop"), + (r"\\\}", op_opt_ignore_or_fixed(Name.Entity, "}")), + (r"\\\\", op_opt_ignore_or_fixed(Name.Entity, "\\")), + (r"\\", op_opt_ignore_or_fixed(Generic.Error, "\\")), + ], + "expr": [ + include("math-symbols"), # must be before punctuation + include("ascii-punctuation"), + include("unicode-punctuation"), + include("escaped-string-start"), + include("py-strings"), + include("py-numbers"), + (r"(?i)\\(call|name)[ \t]*(\{)", LexBase.op_ignore, "entity-name"), + (r"(?i)\\gets\b", op_gets), + (r"(?i)\\text[ \t]*\{", LexBase.op_ignore, "text-in-expr"), + include("explicit-tokentype"), + include("remark"), + include("keyword-constants"), + include("word-operators"), + include("math-builtins"), + include("py-name"), + ], + "expr-in-braces": [ + include("math-symbols"), # must be before punctuation + include("ascii-punctuation-in-braces"), + include("unicode-punctuation"), + include("escaped-string-start"), + include("py-strings"), + include("py-numbers"), + (r"(?i)\\(call|name)[ \t]*(\{)", LexBase.op_ignore, "entity-name"), + (r"(?i)\\gets\b", op_gets), + (r"(?i)\\text[ \t]*\{", LexBase.op_ignore, "text-in-expr"), + include("explicit-tokentype"), + include("remark"), + include("keyword-constants"), + include("word-operators"), + include("math-builtins"), + include("py-name"), + ], + "block-expr": [ # somewhat similar to "root" + (r"\}", LexBase.op_ignore, "#pop"), + (r"\n", Whitespace), + include("expr-in-braces"), + (r"\\\\", LexBase.op_fixed(Text, "\\")), + (r"\\", LexBase.op_fixed(Generic.Error, "\\")), + include("unicode-separators"), + include("unicode-other"), + (r"[^\S\n]+", Text), + (r".", Error), + ], + "text-statement": [ # like block but default to text-mode + (r"[^\\}\n]+", Text), + (r"\}", LexBase.op_ignore, "#pop"), + (r"\n", Whitespace), + (r"\\\}", LexBase.op_fixed(Text, "}")), + (r"(?i)\\expr(?:ession)?[ \t]*\{", + LexBase.op_ignore, + "block-expr"), + include("explicit-tokentype"), + include("remark"), + (r"\\\\", LexBase.op_fixed(Text, "\\")), + (r"\\", LexBase.op_fixed(Text, "\\")), # in text-mode: leave Text + (r".", Error), + ], + "text-in-expr": [ + (r"[^\\}\n]+", Text), + (r"\}", LexBase.op_ignore, "#pop"), + (r"\n", Whitespace), + (r"\\\}", LexBase.op_fixed(Text, "}")), + (r"(?i)\\expr(?:ession)?[ \t]*\{", + LexBase.op_ignore, + "block-expr"), + include("explicit-tokentype"), + include("remark"), + (r"\\\\", LexBase.op_fixed(Text, "\\")), + (r"\\", LexBase.op_fixed(Text, "\\")), # in text-mode: leave Text + (r".", Error), + ], + "math-builtins": [ + (words(("sqrt", "pow", "cos", "sin", "tan", "arcos", "arcsin", + "arctan", "arctan2", "mod", "exp", "ln", "log", + "min", "max"), + prefix=r"(?|<->|<-|->|=>|<=|>=|<>|!=|:=|=:|\?=", op_symbol(Operator)), + (r"[!&<>=+\-*/%|~]", Operator), # ASCII + (u"[%s]" % (uniprops.Sm,), Operator), # other Unicode + ], + "word-operators": [ + (words(("IN", "In", "in", + "IS", "Is", "is", + "AND", "And", "and", + "OR", "Or", "or", + "XOR", "Xor", "xor", + "NOT", "Not", "not"), + prefix=r"(?[a-zA-Z0-9_-]+?)(?P[/:|=*+!\$~])" + r"(?P(.|\n)+?)(?P=sep)", + op_explicit_tokentype), + (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\{(?P[^}]+?)\}", + op_explicit_tokentype), + (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\((?P[^)]+?)\)", + op_explicit_tokentype), + (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)<(?P[^>]+?)>", + op_explicit_tokentype), + (r"\\ttx\-(?P[a-zA-Z0-9_-]+?)\[(?P[^\]]+?)\]", + op_explicit_tokentype), + + # Every character is possible: no escaping needed! + (r"\\tt-(?P[^/]+?)/(?P(?:.|\n))", + op_explicit_tokentype), + ], + } + + def __init__(self, **options): + self.no_end = pygments.util.get_bool_opt( + options, "no_end", default=False) + self.symbol_gets = options.get("gets", None) + if self.symbol_gets is None: + self.symbol_gets = self.SYMBOLS["<-"] # Default: "⟵" # U+27F5 + self.symbol_remark = options.get("remark", None) + if self.symbol_remark is None: + self.symbol_remark = self.SYMBOLS["REM"] # Default: "▷" # U+25B7 + LexBase.__init__(self, **options) + # + # Do this after calling the base because a "filters" option should be + # allowed to set **any** filter. + # + self.prohibit_raiseonerror_filter = pygments.util.get_bool_opt( + options, "prohibit_raiseonerror_filter", default=False) + + def add_filter(self, filter_, **options): + # + # May be called by Lexer.__init__ when + # self.prohibit_raiseonerror_filter is not yet set. + # This is intentionally so. + # + if getattr(self, "prohibit_raiseonerror_filter", False): + if filter_ in ("raiseonerror",): + return + LexBase.add_filter(self, filter_, **options) + + +class AlgPseudocodeLexer_DE(AlgPseudocodeLexer): + + """ + + .. seealso:: + - https://de.wikipedia.org/wiki/Pseudocode + + .. todo:: Complete german translations + + """ + + 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", + "IS": "IST", + "WITH": "MIT", + "IF": "WENN", + "THEN": "DANN", + "ELSE": "ANDERNFALLS", + "ELSEIF": "ANDERNFALLS WENN", + "ELSIF": "ANDERNFALLS WENN", + "ELIF": "ANDERNFALLS WENN", +# "DO": # XXX TBD # in WHILE WHILE ... DO # noqa # in WHILE ... DO + "WHILE": "SOLANGE", + "FOR": "FÜR", + "FORALL": "FÜR ALLE", + "FROM": "VON", + "TO": "BIS", + "IN": "IN", + "STEP": "SCHRITTWEITE", +# "LOOP": XXX TBD # noqa + "REPEAT": "WIEDERHOLE", + "UNTIL": "BIS", +# "RETURN": XXX TBD # noqa + "BEGIN": "START", + "END": "ENDE", + }) + END_TRANSLATIONS = AlgPseudocodeLexer.END_TRANSLATIONS.copy() + END_TRANSLATIONS.update({ + "PROG": "ENDE DES PROGRAMMS", + "PROGRAM": "ENDE DES PROGRAMMS", + "ALGO": "ENDE DES ALGORITHMUS", + "ALGORITHM": "ENDE DES ALGORITHMUS", + "PROC": "ENDE DER PROZEDUR", + "PROCEDURE": "ENDE DER PROZEDUR", + "FUNC": "ENDE DER FUNKTION", + "FUNCTION": "ENDE DER FUNKTION", + "FN": "ENDE DER FUNKTION", + "CLASS": "ENDE DER KLASSE", + "IF": "ENDE WENN", + "WHILE": "ENDE SOLANGE", + "FOR": "ENDE FÜR", + "FORALL": "ENDE FÜR ALLE", +# "LOOP": "ENDE XXX", # XXX TBD # noqa + }) + DEFAULT_END_PREFIX = "ENDE VON " + + +class AlgPseudocodeLexer_FR(AlgPseudocodeLexer): + + """ + + .. seealso:: + - https://info.blaisepascal.fr/pseudo-code/ + - https://fr.wikipedia.org/wiki/Pseudo-code + - https://fr.wikipedia.org/wiki/Structure_de_contr%C3%B4le + + .. todo:: Complete french translations + + """ + + name = "AlgPseudocodeFR" + aliases = ["algpseudocode-fr", "algpseudo-fr"] + filenames = ["*.algpseudo-fr", "*.algpseudocode-fr"] + + LANG = "fr" + 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", + "IS": "EST", + "WITH": "AVEC", + "IF": "SI", + "THEN": "ALORS", + "ELSE": "SINON", + "ELSEIF": "SINONSI", + "ELSIF": "SINONSI", + "ELIF": "SINONSI", + "DO": "FAIRE", # as in in WHILE ... DO (not DO ... UNTIL) + "WHILE": "TANTQUE", + "FOR": "POUR", + "FORALL": "POUR CHAQUE", + "FROM": "DE", + "TO": "JUSQU'À", # or just "À", + "IN": "DANS", # as in FOR ... IN + "STEP": "PAR PAS DE", + "LOOP": "BOUCLE", # XXX FIXME??? + "REPEAT": "RÉPÉTER", + "UNTIL": "JUSQUACEQUE", + "RETURN": "RENVOYER", + "BEGIN": "DÉBUT", + "END": "FIN", + }) + END_TRANSLATIONS = AlgPseudocodeLexer.END_TRANSLATIONS.copy() + END_TRANSLATIONS.update({ + "PROG": "FIN DE PROGRAMME", + "PROGRAM": "FIN DE PROGRAMME", + "ALGO": "FIN D'ALGORITHME", + "ALGORITHM": "FIN D'ALGORITHME", + "PROC": "FIN DE PROCÉDURE", + "PROCEDURE": "FIN DE PROCÉDURE", + "FUNC": "FIN DE FONCTION", + "FUNCTION": "FIN DE FOUNCTION", + "FN": "FIN DE FONCTION", + "CLASS": "FIN DE CLASSE", + "SI": "FIN SI", + "FOR": "FIN POUR", + "FORALL": "FIN POUR CHAQUE", + "WHILE": "FIN TANTQUE", + "LOOP": "FIN BOUCLE", + }) + DEFAULT_END_PREFIX = "FIN DE " diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/lexers/bases.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygments_lexer_pseudocode2/lexers/bases.py Fri May 08 21:19:54 2026 +0200 @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +# :- +# SPDX-FileCopyrightText: © 2026 Franz Glasner +# SPDX-License-Identifier: MIT +# :- +r"""Some common bases for the lexers.""" + +__all__ = ["LexBase", "uni_name", "py_innerstring_rules", "py_name_rules"] + + +import sys + +from pygments import unistring +from pygments.lexer import RegexLexer, combined, bygroups, include +from pygments.token import (Comment, Error, Name, Number, Other, String) + + +PY2 = sys.version_info[0] <= 2 + + +# +# SPDX-SnippetBegin +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team +# SPDX-SnippetCopyrightText: Copyright 2026 by Franz Glasner +# + +uni_name = "[%s][%s]*" % (unistring.xid_start, unistring.xid_continue) + + +"""PY3 allows no @staticmethod but PY2 needs it.""" +if PY2: + _staticmethod = staticmethod +else: + def _staticmethod(fn): + return fn + + +def py_innerstring_rules(ttype): + return [ + # the old style '%s' % (...) string formatting (still valid in Py3) + (r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?' + '[hlL]?[E-GXc-giorsaux%]', String.Interpol), + # the new style '{}'.format(...) string formatting + (r'\{' + r'((\w+)((\.\w+)|(\[[^\]]+\]))*)?' # field name + r'(\![sra])?' # conversion + r'(\:(.?[<>=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?' + r'\}', String.Interpol), + # + # backslashes, quotes and formatting signs must be parsed + # one at a time + # + (r'[^\\\'"%{\n]+', ttype), + (r'[\'"\\]', ttype), + # unhandled string formatting sign + (r'%|(\{{1,2})', ttype) + # newlines are an error (use "nl" state) + ] + + +def py_name_rules(ttype, deco_ttype=Name.Decorator): + return [ + # We recognize decorator syntax here + (r'@' + uni_name, deco_ttype), + # + # Python's new matrix multiplication operator: + # not used here in pseudocode + # (r'@', Operator), + (uni_name, ttype), + ] + +# SPDX-SnippetEnd + + +class LexBase(RegexLexer): + + """A base that defines some common lexer states. + + Default flags are not important. + + """ + + def op_ignore(lexer, match, ctx=None): + """Unconditionally ignore the match.""" + if False: + yield match.start(), Other, "" + if ctx: + ctx.pos = match.end() + + @_staticmethod + def op_fixed(toktype, value): + """Unconditionally yield a given token type and value.""" + + def _op_fixed(lexer, match, ctx=None): + yield match.start(), toktype, value + if ctx: + ctx.pos = match.end() + + return _op_fixed + + tokens = { +# +# These states are borrowed from Pygment's Python lexer. +# Their names have been prefixed with `py-'. +# +# SPDX-SnippetBegin +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team +# SPDX-SnippetCopyrightText: Copyright 2026 by Franz Glasner +# + 'py-numbers': [ + (r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)' + r'([eE][+-]?\d(?:_?\d)*)?', Number.Float), + (r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float), + (r'0[oO](?:_?[0-7])+', Number.Oct), + (r'0[bB](?:_?[01])+', Number.Bin), + (r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex), + (r'\d(?:_?\d)*', Number.Integer), + ], + 'py-strings': [ + # non-raw strings + ('([uU]?)(""")', bygroups(String.Affix, String.Double), + combined('py-stringescape', 'py-tdqs')), + ("([uU]?)(''')", bygroups(String.Affix, String.Single), + combined('py-stringescape', 'py-tsqs')), + ('([uU]?)(")', bygroups(String.Affix, String.Double), + combined('py-stringescape', 'py-dqs')), + ("([uU]?)(')", bygroups(String.Affix, String.Single), + combined('py-stringescape', 'py-sqs')), + # non-raw bytes + ('([bB])(""")', bygroups(String.Affix, String.Double), + combined('py-bytesescape', 'py-tdqs')), + ("([bB])(''')", bygroups(String.Affix, String.Single), + combined('py-bytesescape', 'py-tsqs')), + ('([bB])(")', bygroups(String.Affix, String.Double), + combined('py-bytesescape', 'py-dqs')), + ("([bB])(')", bygroups(String.Affix, String.Single), + combined('py-bytesescape', 'py-sqs')), + ], + 'py-stringescape': [ + (r'\\(N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8})', String.Escape), + include('py-bytesescape') + ], + 'py-bytesescape': [ + (r'\\([\\abfnrtv"\']|\n|x[a-fA-F0-9]{2}|[0-7]{1,3})', + String.Escape) + ], + 'py-dqs': [ + (r'"', String.Double, '#pop'), + (r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings + include('py-strings-double'), + (r'\n', Error), # added by fag + ], + 'py-sqs': [ + (r"'", String.Single, '#pop'), + (r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings + include('py-strings-single'), + (r'\n', Error), # added by fag + ], + 'py-tdqs': [ + (r'"""', String.Double, '#pop'), + include('py-strings-double'), + (r'\n', String.Double) + ], + 'py-tsqs': [ + (r"'''", String.Single, '#pop'), + include('py-strings-single'), + (r'\n', String.Single) + ], + 'py-strings-single': py_innerstring_rules(String.Single), + 'py-strings-double': py_innerstring_rules(String.Double), + 'py-name': py_name_rules(Name.Entity), +# SPDX-SnippetEnd + # This snippet is from the Pygments' documentation "Write your own lexer" + 'multiline-nested-comment': [ + (r'[^*/]+', Comment.Multiline), + (r'/\*', Comment.Multiline, '#push'), + (r'\*/', Comment.Multiline, '#pop'), + (r'[*/]', Comment.Multiline), + ], + 'multiline-nested-comment-alt': [ + (r'[^*()]+', Comment.Multiline), + (r'\(\*', Comment.Multiline, '#push'), + (r'\*\)', Comment.Multiline, '#pop'), + (r'[*()]', Comment.Multiline), + ] + } diff -r 315cfe0a836f -r a4317957148b pygments_lexer_pseudocode2/lexers/fr_pseudocode.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pygments_lexer_pseudocode2/lexers/fr_pseudocode.py Fri May 08 21:19:54 2026 +0200 @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +# :- +# SPDX-FileCopyrightText: © 2015 Simon Wachter +# SPDX-FileCopyrightText: © 2026 Franz Glasner +# SPDX-License-Identifier: MIT +# :- +r""" +:Author: Simon Wachter +:Author: Franz Glasner +:Copyright: © 2015 Simon Wachter +:Copyright: © 2026 Franz Glasner +:License: MIT License. + See :file:`MIT.txt` for details. + If you cannot find MIT.txt see + . +""" + +__all__ = ["FrPseudocodeLexer"] + + +import re + +from pygments.lexer import RegexLexer, include +from pygments.token import Punctuation, Whitespace, Comment, Operator, Keyword, Name, String, Number + + +class FrPseudocodeLexer(RegexLexer): + ''' + A Pseudo code (fr) lexer + ''' + name = 'FrPseudocode' + aliases = ['fr-pseudocode', 'fr-pseudo', 'fr-algorithm', 'fr-algo'] + filenames = ['*.fr-algo', '*.fr-pseudocode'] + mimetypes = [] + flags = re.MULTILINE + + REPLACEMENTS = { + '<=': '≤', + '>=': '≥', + '<>': '≠', + '!=': '≠', + '<-': '←', + '->': '→', + '=>': '⇒', + '<->': '↔', + '<=>': '⇔', + '^': '↑', + } + + def op_replace(lexer, match): + op = match.group(0) + yield match.start(), Operator, lexer.REPLACEMENTS.get(op, op) + + def scomment(lexer, match): + s = match.group(1).lower().strip() + c = Comment + + directives = ['passage par copie', 'passage par valeur', 'passage par référence', 'passage par reference', 'passage par adresse', 've', 'vs', 've/s'] + + if s in directives: + c = Comment.Special + + yield match.start(), c, match.group(0) + + tokens = { + 'root': [ + (r'\/\*.*\*\/', Comment), + (r'(\/\/|#).*\n', Comment), + (r'\|', Comment), + (r'\{(.*)\}', scomment), + include('strings'), + include('core'), + (r'(?i)[a-zéàùçèÉÀÙÇÈ][a-z0-9éàùçèÉÀÙÇÈ_]*', Name.Variable), + include('numbers'), + (r'[\s]+', Whitespace) + ], + 'core': [ # Statements + (r'(?i)\b(debut|début|fin|si|alors|sinon|fin[_ ]si|tant[ _]que|tantque|fin[ _]tantque|faire|répéter|' + r'repeter|type|structure|fin[ _]structure|fonction|procédure|procedure|retourner|renvoyer|' + r'pour|fin[ _]pour|à|déclarations?|juqsque|spécialise|specialise|comporte|super|public|privé|protégé|' + r'classe' + r')\s*\b', Keyword), + + # Data Types + (r'(?i)\b(entiers?|chaines?|chaînes?|réels?|reels?|caractères?|caracteres?|booléens?|' + r'booleens?|tableaux?|rien)\s*\b', + Keyword.Type), + + (r'(?i)\b(vrai|faux|nil)\s*\b', + Name.Constant), + + # Operators + (r'(?i)(<->|<=>|<=|>=|<>|!=|<-|->|=>|\^|\*|\+|-|\/|<|>|=|\\\\|mod|←|↑|≤|≥|≠|÷|×|\.\.|\[|\]|\.|non|xou|et|ou)', + op_replace), + + (r'(\(|\)|\,|\;|:)', + Punctuation), + + #(r'\b(\[(VE|VS|VE/S)\])\s*\b', + # Keyword.Declaration), + + # Intrinsics + (r'(?i)\b(sqrt|pow|cos|sin|tan|arccos|arcsin|arctan|arctan2|lire|ecrire|écrire|' + r'exp|ln|log|détruire|detruire' + r')\s*\b', Name.Builtin) + ], + + 'strings': [ + (r'"([^"])*"', String.Double), + (r"'([^'])*'", String.Single), + ], +# +# This is stolen from the Pygment's Python lexer. +# +# SPDX-SnippetBegin +# SPDX-License-Identifier: BSD-2-Clause +# SPDX-SnippetCopyrightText: Copyright 2006-2023 by the Pygments team + 'numbers': [ + (r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)' + r'([eE][+-]?\d(?:_?\d)*)?', Number.Float), + (r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float), + (r'0[oO](?:_?[0-7])+', Number.Oct), + (r'0[bB](?:_?[01])+', Number.Bin), + (r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex), + (r'\d(?:_?\d)*', Number.Integer), + ], +# SPDX-SnippetEnd + } diff -r 315cfe0a836f -r a4317957148b pyproject.toml --- a/pyproject.toml Fri May 08 19:49:08 2026 +0200 +++ b/pyproject.toml Fri May 08 21:19:54 2026 +0200 @@ -45,14 +45,15 @@ [project.entry-points.'pygments.lexers'] # The mostly original and somewhat extended Pseudocode lexer (fr) -fr_pseudocodelexer = "pygments_lexer_pseudocode2.fr_pseudocode:FrPseudocodeLexer" -algpseudocodelexer = "pygments_lexer_pseudocode2.algpseudocode:AlgPseudocodeLexer" -algpseudocodelexer_de = "pygments_lexer_pseudocode2.algpseudocode:AlgPseudocodeLexer_DE" -algpseudocodelexer_fr = "pygments_lexer_pseudocode2.algpseudocode:AlgPseudocodeLexer_FR" +fr_pseudocodelexer = "pygments_lexer_pseudocode2.lexers.fr_pseudocode:FrPseudocodeLexer" +algpseudocodelexer = "pygments_lexer_pseudocode2.lexers.algpseudocode:AlgPseudocodeLexer" +algpseudocodelexer_de = "pygments_lexer_pseudocode2.lexers.algpseudocode:AlgPseudocodeLexer_DE" +algpseudocodelexer_fr = "pygments_lexer_pseudocode2.lexers.algpseudocode:AlgPseudocodeLexer_FR" [tool.setuptools] packages = [ "pygments_lexer_pseudocode2", + "pygments_lexer_pseudocode2.lexers", ] platforms = ["any"] zip-safe = true diff -r 315cfe0a836f -r a4317957148b tests/_tsetup.py --- a/tests/_tsetup.py Fri May 08 19:49:08 2026 +0200 +++ b/tests/_tsetup.py Fri May 08 21:19:54 2026 +0200 @@ -28,10 +28,12 @@ sys.path.insert(0, PROJECTDIR) FRLEXERFILENAME = os.path.join(PROJECTDIR, "pygments_lexer_pseudocode2", + "lexers", "fr_pseudocode.py") FRLEXERCLASS = "FrPseudocodeLexer" ALGLEXERFILENAME = os.path.join(PROJECTDIR, "pygments_lexer_pseudocode2", + "lexers", "algpseudocode.py") ALGLEXERCLASS = "AlgPseudocodeLexer" TESTSNIPPETSDIR = os.path.join( diff -r 315cfe0a836f -r a4317957148b tox.ini --- a/tox.ini Fri May 08 19:49:08 2026 +0200 +++ b/tox.ini Fri May 08 21:19:54 2026 +0200 @@ -3,10 +3,10 @@ [flake8] per-file-ignores = # E122: continuation line missing indentation or outdented - pygments_lexer_pseudocode2/bases.py: E122 + pygments_lexer_pseudocode2/lexers/bases.py: E122 # E122: continuation line missing indentation or outdented # E131: continuation line unaligned for hanging indent # E261: at least two spaces before inline comment # E265: block comment should start with '# ' # E501: line too long - pygments_lexer_pseudocode2/fr_pseudocode.py:E122,E131,E261,E265,E501 + pygments_lexer_pseudocode2/lexers/fr_pseudocode.py:E122,E131,E261,E265,E501