Am Freitag, 14. November 2003 21:11 schrieb Georg Baum: > Yes. We can even steal the list of 'known' commands from > lib/reLyX/syntax.default. Creating this list was the main thing that I > did not like with this solution.
It turned out to be rather easy. I have used the syntax.default file from reLyX directly. Georg
Index: src/tex2lyx/ChangeLog =================================================================== RCS file: /cvs/lyx/lyx-devel/src/tex2lyx/ChangeLog,v retrieving revision 1.41 diff -u -p -r1.41 ChangeLog --- src/tex2lyx/ChangeLog 2003/11/05 10:14:12 1.41 +++ src/tex2lyx/ChangeLog 2003/11/15 17:09:53 @@ -1,3 +1,10 @@ +2003-11-15 Georg Baum <[EMAIL PROTECTED]> + + * tex2lyx.C: + * tex2lyx.h: + * text.C: Read a list of commands and their arguments from a reLyX + compatible syntax file in order to parse optional arguments correctly. + 2003-11-03 Georg Baum <[EMAIL PROTECTED]> * math.C: Index: src/tex2lyx/tex2lyx.C =================================================================== RCS file: /cvs/lyx/lyx-devel/src/tex2lyx/tex2lyx.C,v retrieving revision 1.53 diff -u -p -r1.53 tex2lyx.C --- src/tex2lyx/tex2lyx.C 2003/11/05 10:14:13 1.53 +++ src/tex2lyx/tex2lyx.C 2003/11/15 17:09:57 @@ -43,6 +43,7 @@ using std::ostringstream; using std::stringstream; using std::string; using std::vector; +using std::map; using lyx::support::system_lyxdir; using lyx::support::user_lyxdir; @@ -114,7 +115,63 @@ string active_environment() } +map<string, vector<ArgumentType> > known_commands; + + +namespace { + + +/*! + * Read a list of TeX commands from a reLyX compatible syntax file. + * Since this list is used after all commands that have a LyX counterpart + * are handled, it does not matter that the "syntax.default" file from reLyX + * has almost all of them listed. For the same reason the reLyX-specific + * reLyXre environment is ignored. + */ +void read_syntaxfile(string const & file_name) +{ + if (!IsFileReadable(file_name)) { + cerr << "Could not open syntax file \"" << file_name + << "\" for reading." << endl; + exit(2); + } + ifstream is(file_name.c_str()); + // We can use our TeX parser, since the syntax of the layout file is + // modeled after TeX. + // Unknown tokens are just silently ignored, this helps us to skip some + // reLyX specific things. + Parser p(is); + while (p.good()) { + Token const & t = p.get_token(); + if (t.cat() == catEscape) { + string command = t.asInput(); + if (p.next_token().asInput() == "*") { + p.get_token(); + command += '*'; + } + p.skip_spaces(); + vector<ArgumentType> arguments; + while (p.next_token().cat() == catBegin || + p.next_token().asInput() == "[") { + if (p.next_token().cat() == catBegin) { + string const arg = p.getArg('{', '}'); + if (arg == "translate") + arguments.push_back(required); + else + arguments.push_back(verbatim); + } else { + p.getArg('[', ']'); + arguments.push_back(optional); + } + } + known_commands[command] = arguments; + } + } +} + + string documentclass; +string syntaxfile; bool overwrite_files = false; @@ -130,7 +187,8 @@ int parse_help(string const &, string co "\t-f Force creation of .lyx files even if they exist already\n" "\t-userdir dir try to set user directory to dir\n" "\t-sysdir dir try to set system directory to dir\n" - "\t-c textclass declare the textclass" << endl; + "\t-c textclass declare the textclass\n" + "\t-s syntaxfile read additional syntax file" << endl; exit(0); } @@ -146,6 +204,17 @@ int parse_class(string const & arg, stri } +int parse_syntaxfile(string const & arg, string const &) +{ + if (arg.empty()) { + cerr << "Missing syntaxfile string after -s switch" << endl; + exit(1); + } + syntaxfile = arg; + return 1; +} + + int parse_sysdir(string const & arg, string const &) { if (arg.empty()) { @@ -177,10 +246,11 @@ int parse_force(string const &, string c void easyParse(int & argc, char * argv[]) { - std::map<string, cmd_helper> cmdmap; + map<string, cmd_helper> cmdmap; cmdmap["-c"] = parse_class; cmdmap["-f"] = parse_force; + cmdmap["-s"] = parse_syntaxfile; cmdmap["-help"] = parse_help; cmdmap["--help"] = parse_help; cmdmap["-sysdir"] = parse_sysdir; @@ -208,6 +278,8 @@ void easyParse(int & argc, char * argv[] } } +} // anonymous namespace + void tex2lyx(std::istream &is, std::ostream &os) { @@ -266,6 +338,15 @@ int main(int argc, char * argv[]) lyx::support::os::init(&argc, &argv); lyx::support::setLyxPaths(); + + string const system_syntaxfile = lyx::support::LibFileSearch("reLyX", "syntax.default"); + if (system_syntaxfile.empty()) { + cerr << "Error: Could not find syntax file \"syntax.default\"." << endl; + exit(1); + } + read_syntaxfile(system_syntaxfile); + if(syntaxfile.size()) + read_syntaxfile(syntaxfile); if (!IsFileReadable(argv[1])) { cerr << "Could not open input file \"" << argv[1] Index: src/tex2lyx/tex2lyx.h =================================================================== RCS file: /cvs/lyx/lyx-devel/src/tex2lyx/tex2lyx.h,v retrieving revision 1.12 diff -u -p -r1.12 tex2lyx.h --- src/tex2lyx/tex2lyx.h 2003/11/05 10:14:13 1.12 +++ src/tex2lyx/tex2lyx.h 2003/11/15 17:09:57 @@ -19,6 +19,7 @@ #include <iosfwd> #include <string> #include <vector> +#include <map> class Context; @@ -59,6 +60,15 @@ char const ** is_known(std::string const // Access to environment stack extern std::vector<std::string> active_environments; std::string active_environment(); + +enum ArgumentType { + required, + verbatim, + optional +}; + +/// Known TeX commands with arguments that get parsed into ERT. +extern std::map<std::string, std::vector<ArgumentType> > known_commands; /*! Reads tex input from \a is and writes lyx output to \a os. * Uses some common settings for the preamble, so this should only Index: src/tex2lyx/text.C =================================================================== RCS file: /cvs/lyx/lyx-devel/src/tex2lyx/text.C,v retrieving revision 1.27 diff -u -p -r1.27 text.C --- src/tex2lyx/text.C 2003/11/05 10:14:13 1.27 +++ src/tex2lyx/text.C 2003/11/15 17:10:02 @@ -294,6 +310,43 @@ void check_space(Parser const & p, ostre os << ' '; } + +/*! + * Check wether \param command is a known command. If yes, + * handle the command with all arguments. + * \return true if the command was parsed, false otherwise. + */ +bool parse_command(string const & command, Parser & p, ostream & os, + bool outer, Context & context) +{ + if (known_commands.find(command) != known_commands.end()) { + vector<ArgumentType> const & template_arguments = known_commands[command]; + string ert = command; + size_t no_arguments = template_arguments.size(); + for (size_t i = 0; i < no_arguments; ++i) { + switch (template_arguments[i]) { + case required: + // This argument contains regular LaTeX + handle_ert(os, ert + '{', context); + parse_text(p, os, FLAG_ITEM, outer, context); + ert = "}"; + break; + case verbatim: + // This argument may contain special characters + ert += '{' + p.verbatim_item() + '}'; + break; + case optional: + ert += p.getOpt(); + break; + } + } + handle_ert(os, ert, context); + return true; + } + return false; +} + + void parse_environment(Parser & p, ostream & os, bool outer, Context & parent_context) { @@ -1223,16 +1321,6 @@ void parse_text(Parser & p, ostream & os // next paragraph. } - else if (t.cs() == "psfrag") { - // psfrag{ps-text}[ps-pos][tex-pos]{tex-text} - // TODO: Generalize this! - string arguments = p.getArg('{', '}'); - arguments += '}'; - arguments += p.getOpt(); - arguments += p.getOpt(); - handle_ert(os, "\\psfrag{" + arguments, context); - } - else { //cerr << "#: " << t << " mode: " << mode << endl; // heuristic: read up to next non-nested space @@ -1247,14 +1335,14 @@ void parse_text(Parser & p, ostream & os cerr << "found ERT: " << s << endl; handle_ert(os, s + ' ', context); */ - context.check_layout(os); string name = t.asInput(); if (p.next_token().asInput() == "*") { // Starred commands like \vspace*{} p.get_token(); // Eat '*' name += '*'; } - handle_ert(os, name, context); + if (! parse_command(t.asInput(), p, os, outer, context)) + handle_ert(os, name, context); } if (flags & FLAG_LEAVE) {