changeset 160:b4028838e0c8

Implement lexer option "prohibit_raiseonerror_filter". Sphinx raises by default when an Error token is seen (by means of the "raiseonerror" filter that is applied by default to lexers in Sphinx). This option skips this and allows error locations to be seen and highlighted properly. While there convert most Generic.Error tokens to Error tokens because now they can be handled by a lexer with "prohibit_raiseonerror_filter=True".
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 08 May 2026 17:46:28 +0200
parents 4ee0b1536ea6
children 00a432d14508
files docs/conf.py docs/details-algpseudocode.rst pygments_lexer_pseudocode2/algpseudocode.py
diffstat 3 files changed, 38 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/docs/conf.py	Fri May 08 17:13:26 2026 +0200
+++ b/docs/conf.py	Fri May 08 17:46:28 2026 +0200
@@ -92,3 +92,7 @@
     #
     app.add_lexer("NoEndAlgPseudocode",
                   functools.partial(AlgPseudocodeLexer, no_end=True))
+    # For developing a lexer with smoother error handling
+    app.add_lexer("no-raiseonerror-algpseudocode",
+                  functools.partial(AlgPseudocodeLexer,
+                                    prohibit_raiseonerror_filter=True))
--- a/docs/details-algpseudocode.rst	Fri May 08 17:13:26 2026 +0200
+++ b/docs/details-algpseudocode.rst	Fri May 08 17:46:28 2026 +0200
@@ -10,6 +10,18 @@
 Lexer Options
 =============
 
+  .. describe:: prohibit_raiseonerror_filter
+
+     **Type:** `bool`
+
+     **Default:** `False`
+
+     If ``True`` the `raiseonerror` filter is not allowed to be applied by
+     `Sphinx`_ when :py:meth:`Lexer.add_filter` is called.
+     
+     This setting does not apply to filters that are set by the standard
+     lexer option `filters`.
+
   .. describe:: no_end
 
      **Type:** `bool`
--- a/pygments_lexer_pseudocode2/algpseudocode.py	Fri May 08 17:13:26 2026 +0200
+++ b/pygments_lexer_pseudocode2/algpseudocode.py	Fri May 08 17:46:28 2026 +0200
@@ -17,7 +17,7 @@
 
 import pygments.util
 from pygments.lexer import bygroups, include, words
-from pygments.token import (Comment, Generic, Keyword, Name, Operator,
+from pygments.token import (Comment, Error, Generic, Keyword, Name, Operator,
                             Punctuation, Text, Whitespace)
 
 #
@@ -334,7 +334,8 @@
             include("unicode-separators"),
             include("unicode-other"),
             (r"[^\S\n]+", Text),
-            (r".", Generic.Error),     # tolerance for errors
+            # (r".", Generic.Error),     # tolerance for errors
+            (r".", Error),
         ],
         "remark": [
             (r"(?i)\\(remark|rem)\b(.*)$",
@@ -397,7 +398,7 @@
             include("unicode-separators"),
             include("unicode-other"),
             (r"[^\S\n]+", Text),
-            (r".", Generic.Error),     # tolerance for errors
+            (r".", Error),
         ],
         "text-statement": [  # like block but default to text-mode
             (r"[^\\}\n]+", Text),
@@ -411,7 +412,7 @@
             include("remark"),
             (r"\\\\", LexBase.op_fixed(Text, "\\")),
             (r"\\", LexBase.op_fixed(Text, "\\")),
-            (r".", Generic.Error),     # tolerance for errors
+            (r".", Error),
         ],
         "text-in-expr": [
             (r"[^\\}\n]+", Text),
@@ -425,7 +426,7 @@
             include("remark"),
             (r"\\\\", LexBase.op_fixed(Text, "\\")),
             (r"\\", LexBase.op_fixed(Text, "\\")),
-            (r".", Generic.Error),     # tolerance for errors
+            (r".", Error),
         ],
         "math-builtins": [
             (words(("sqrt", "pow", "cos", "sin", "tan", "arcos", "arcsin",
@@ -525,6 +526,22 @@
         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):