[LyX/2.5.x] Error on @ catcode mismatch by layout definitions (#13275)

Juergen Spitzmueller <[email protected]> Thu, 23 Apr 2026 16:35:26 +0000
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit bdca8838fdc30b2916bd4bae8aef5d77b7bd78af
Author: Juergen Spitzmueller <[email protected]>
Date:   Sun Jan 18 11:29:06 2026 +0100

    Error on @ catcode mismatch by layout definitions (#13275)
    
    (cherry picked from commit e16b9a61ac40baeb4be3080cd1d5026d32886995)
---
 src/BufferParams.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index e781f3ef89..32360a9e1c 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -27,9 +27,11 @@
 #include "ColorSet.h"
 #include "Converter.h"
 #include "Encoding.h"
+#include "ErrorList.h"
 #include "Format.h"
 #include "IndicesList.h"
 #include "Language.h"
+#include "LaTeX.h"
 #include "LaTeXColors.h"
 #include "LaTeXFeatures.h"
 #include "LaTeXFonts.h"
@@ -2073,6 +2075,52 @@ void BufferParams::validate(LaTeXFeatures & features) const
 }
 
 
+namespace{
+
+/// This function checks whether the catcode of @
+/// is `other' (11) rather than `letter' (11)
+/// It also returns the context of the change
+bool isAtOther(docstring const passage, docstring & context)
+{
+	// we assume `letter' catcode initially
+	bool cc = false;
+	istringstream ss(to_utf8(passage));
+	Lexer lex;
+	lex.setStream(ss);
+	lex.setCommentChar('%');
+	int lineno = lex.lineNumber();
+	int prev_lineno = lineno;
+
+	while (lex.isOK()) {
+		lineno = lex.lineNumber();
+		string token;
+		lex >> token;
+		token = rtrim(token, "%");
+
+		if (lineno == prev_lineno)
+			context += from_ascii(" ");
+		else if (lineno > 0)
+			context += from_ascii("\n");
+		prev_lineno = lineno;
+
+		if (token == "\\makeatletter") {
+			context = from_ascii(token);
+			cc = false;
+			continue;
+		}
+		if (token == "\\makeatother") {
+			context += from_ascii(token);
+			cc = true;
+			continue;
+		}
+		context += from_ascii(token);
+	}
+	return cc;
+}
+
+}// anon namespace
+
+
 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 			      FileName const & filepath) const
 {
@@ -2767,11 +2815,25 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 	// the text class specific preamble
 	{
 		docstring tmppreamble = features.getTClassPreamble();
-		if (!tmppreamble.empty())
+		if (!tmppreamble.empty()) {
 			atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
 			                 "Textclass specific LaTeX commands.\n"
 			              << tmppreamble
 			              << '\n';
+			docstring context;
+			if (isAtOther(tmppreamble, context)) {
+				TeXErrors terr;
+	
+				ErrorList & errorList = features.buffer().errorList("Export");
+				errorList.clear();
+				docstring const s = bformat(_("A layout definition sets the catcode of '@' to 12 ('other') "
+							      "in a context where it should remain 11 ('letter'):\n"
+							      "%1$s"
+							      "Please fix or report!"), context);
+				errorList.push_back(ErrorItem(_("Catcode mismatch"), s));
+				features.buffer().bufferErrors(terr, errorList);
+			}
+		}
 	}
 	// suppress date if selected
 	// use \@ifundefined because we cannot be sure that every document class
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs