The following patch is something I wanted to do for a long time and
should work towards fixing bug 19 (!).

Basically, it recognizes the comments output by LyX and acts on them
as follows:

%% LyX <foo> created this file.  For more info, see http://www.lyx.org/.

-> this detects that we have a LyX file

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.

-> any of these (if we are in a LyX file) tell us that we are in
   LyX-generated code. We parse it, but do not output anything to
   h_preamble.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.

-> puts us outside of LyX-generated code. Code is output to h_preamble
   as usual.

This approach allows to remove all the hardcoded LyX strings that we
had, which is really a good thing. OTOH, it is quite heuristic and
probably fragile. It may be that the real-world use of LyX is outside
of what this algorithm can understand.

One possibility would be to add a flag to disable this 'smart' checking.

The only real bug I am aware of is that there is no mark in the
LaTeX/LyX format indicating the end of the user preamble. This is why
we always have a final \makeatother at the end of preamble. I could
get rid of it since we track the catcode of @. Also, the special
language commands as defined in lib/language will be kept in preamble.
This breaks round trip with some languages.

Comments very welcome (Georg?). I am not planning to apply it to
1.4.3, so don't worry too much yet.

JMarc

Index: src/tex2lyx/preamble.C
===================================================================
--- src/tex2lyx/preamble.C	(revision 14807)
+++ src/tex2lyx/preamble.C	(working copy)
@@ -20,6 +20,8 @@
 #include "support/filetools.h"
 #include "support/lstrings.h"
 
+#include <boost/regex.hpp>
+
 #include <algorithm>
 #include <iostream>
 #include <sstream>
@@ -27,6 +29,9 @@
 #include <vector>
 #include <map>
 
+using boost::regex;
+using boost::smatch;
+
 using std::istringstream;
 using std::ostream;
 using std::ostringstream;
@@ -164,7 +169,8 @@
 }
 
 
-void handle_package(string const & name, string const & opts)
+void handle_package(string const & name, string const & opts,
+		    bool in_lyx_preamble)
 {
 	vector<string> options = split_options(opts);
 	add_package(name, options);
@@ -215,11 +221,14 @@
 		}
 	} else if (name == "jurabib") {
 		h_cite_engine = "jurabib";
-	} else if (options.empty())
-		h_preamble << "\\usepackage{" << name << "}\n";
-	else {
-		h_preamble << "\\usepackage[" << opts << "]{" << name << "}\n";
-		options.clear();
+	} else if (!in_lyx_preamble) {
+		if (options.empty())
+			h_preamble << "\\usepackage{" << name << "}\n";
+		else {
+			h_preamble << "\\usepackage[" << opts << "]{" 
+				   << name << "}\n";
+			options.clear();
+		}
 	}
 
 	// We need to do something with the options...
@@ -275,6 +284,8 @@
 	// initialize fixed types
 	special_columns['D'] = 3;
 	bool is_full_document = false;
+	bool is_lyx_file = false;
+	bool in_lyx_preamble = true;
 
 	// determine whether this is a full document or a fragment for inclusion
 	while (p.good()) {
@@ -297,35 +308,56 @@
 		//
 		// cat codes
 		//
-		if (t.cat() == catLetter ||
-			  t.cat() == catSuper ||
-			  t.cat() == catSub ||
-			  t.cat() == catOther ||
-			  t.cat() == catMath ||
-			  t.cat() == catActive ||
-			  t.cat() == catBegin ||
-			  t.cat() == catEnd ||
-			  t.cat() == catAlign ||
-			  t.cat() == catParameter)
+		if (!in_lyx_preamble &&
+		    (t.cat() == catLetter ||
+		     t.cat() == catSuper ||
+		     t.cat() == catSub ||
+		     t.cat() == catOther ||
+		     t.cat() == catMath ||
+		     t.cat() == catActive ||
+		     t.cat() == catBegin ||
+		     t.cat() == catEnd ||
+		     t.cat() == catAlign ||
+		     t.cat() == catParameter))
 		h_preamble << t.character();
 
-		else if (t.cat() == catSpace || t.cat() == catNewline)
+		else if (!in_lyx_preamble && 
+			 (t.cat() == catSpace || t.cat() == catNewline))
 			h_preamble << t.asInput();
 
-		else if (t.cat() == catComment)
-			h_preamble << t.asInput();
+		else if (t.cat() == catComment) {
+			// regex to parse comments
+			static regex const islyxfile("%% LyX .* created this file");
+			static regex const usercommands("User specified LaTeX commands");	
 
+			string const comment = t.asInput();
+			cerr << "Seen comment: " << comment << std::endl;
+			smatch sub;
+			if (regex_search(comment, sub, islyxfile))
+				is_lyx_file = true;
+			else if (is_lyx_file 
+				 && regex_search(comment, sub, usercommands))
+				in_lyx_preamble = false;
+			else if (!in_lyx_preamble)
+				h_preamble << t.asInput();
+			cerr << "lyx_file: " << is_lyx_file << ", lyx_preamble " << in_lyx_preamble << std::endl;
+		}
+
 		else if (t.cs() == "pagestyle")
 			h_paperpagestyle = p.verbatim_item();
 
 		else if (t.cs() == "makeatletter") {
+			if (!is_lyx_file || !in_lyx_preamble 
+			    || p.getCatCode('@') != catLetter)
+				h_preamble << "\\makeatletter";
 			p.setCatCode('@', catLetter);
-			h_preamble << "\\makeatletter";
 		}
 
 		else if (t.cs() == "makeatother") {
+			if (!is_lyx_file || !in_lyx_preamble 
+			    || p.getCatCode('@') != catOther)
+				h_preamble << "\\makeatother";
 			p.setCatCode('@', catOther);
-			h_preamble << "\\makeatother";
 		}
 
 		else if (t.cs() == "newcommand" || t.cs() == "renewcommand"
@@ -340,15 +372,7 @@
 			string const opt2 = p.getFullOpt();
 			string const body = p.verbatim_item();
 			// only non-lyxspecific stuff
-			if (   name != "\\noun"
-			    && name != "\\tabularnewline"
-			    && name != "\\LyX"
-			    && name != "\\lyxline"
-			    && name != "\\lyxaddress"
-			    && name != "\\lyxrightaddress"
-			    && name != "\\lyxdot"
-			    && name != "\\boldsymbol"
-			    && name != "\\lyxarrow") {
+			if (!in_lyx_preamble) {
 				ostringstream ss;
 				ss << '\\' << t.cs();
 				if (star)
@@ -392,9 +416,10 @@
 				vector<string>::const_iterator it  = vecnames.begin();
 				vector<string>::const_iterator end = vecnames.end();
 				for (; it != end; ++it)
-					handle_package(trim(*it), string());
+					handle_package(trim(*it), string(), 
+						       in_lyx_preamble);
 			} else {
-				handle_package(name, options);
+				handle_package(name, options, in_lyx_preamble);
 			}
 		}
 
@@ -406,9 +431,7 @@
 			ss << p.getOpt();
 			ss << '{' << p.verbatim_item() << '}';
 			ss << '{' << p.verbatim_item() << '}';
-			if (name != "lyxcode" && name != "lyxlist" &&
-			    name != "lyxrightadress" &&
-			    name != "lyxaddress" && name != "lyxgreyedout")
+			if (!in_lyx_preamble)
 				h_preamble << ss.str();
 		}
 
@@ -416,8 +439,9 @@
 			string name = p.get_token().cs();
 			while (p.next_token().cat() != catBegin)
 				name += p.get_token().asString();
-			h_preamble << "\\def\\" << name << '{'
-			           << p.verbatim_item() << "}";
+			if (!in_lyx_preamble)
+				h_preamble << "\\def\\" << name << '{'
+					   << p.verbatim_item() << "}";
 		}
 
 		else if (t.cs() == "newcolumntype") {
@@ -478,7 +502,7 @@
 			}
 		}
 
-		else if (!t.cs().empty())
+		else if (!t.cs().empty() && !in_lyx_preamble)
 			h_preamble << '\\' << t.cs();
 	}
 	p.skip_spaces();

Reply via email to