latest patch from Georg: support a syntax table for unsupported commands

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8104 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Jean-Marc Lasgouttes 2003-11-19 10:35:50 +00:00
parent 25b208aa25
commit f5d5eebe3c
8 changed files with 164 additions and 33 deletions

View File

@ -1,3 +1,16 @@
2003-11-18 Georg Baum <Georg.Baum@post.rwth-aachen.de>
* 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 argumnts correctly.
* preamble.C:
* table.C:
* text.C:
* tex2lyx.C:
* texparser.C
* math.C: change size() to !empty() where it was used as bool
2003-11-03 Georg Baum <Georg.Baum@post.rwth-aachen.de> 2003-11-03 Georg Baum <Georg.Baum@post.rwth-aachen.de>
* math.C: * math.C:

View File

@ -121,7 +121,7 @@ void parse_math(Parser & p, ostream & os, unsigned flags, const mode_type mode)
} }
else if (t.cat() == catComment) { else if (t.cat() == catComment) {
if (t.cs().size()) if (!t.cs().empty())
cerr << "Ignoring comment: " << t.asInput(); cerr << "Ignoring comment: " << t.asInput();
else else
// "%\n" combination // "%\n" combination

View File

@ -131,7 +131,7 @@ void handle_package(string const & name, string const & options)
h_language = name; h_language = name;
h_quotes_language = name; h_quotes_language = name;
} else { } else {
if (options.size()) if (!options.empty())
h_preamble << "\\usepackage[" << options << "]{" << name << "}\n"; h_preamble << "\\usepackage[" << options << "]{" << name << "}\n";
else else
h_preamble << "\\usepackage{" << name << "}\n"; h_preamble << "\\usepackage{" << name << "}\n";
@ -146,7 +146,7 @@ void end_preamble(ostream & os, LyXTextClass const & /*textclass*/)
<< "\\lyxformat 225\n" << "\\lyxformat 225\n"
<< "\\textclass " << h_textclass << "\n" << "\\textclass " << h_textclass << "\n"
<< "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n"; << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
if (h_options.size()) if (!h_options.empty())
os << "\\options " << h_options << "\n"; os << "\\options " << h_options << "\n";
os << "\\language " << h_language << "\n" os << "\\language " << h_language << "\n"
<< "\\inputencoding " << h_inputencoding << "\n" << "\\inputencoding " << h_inputencoding << "\n"
@ -319,7 +319,7 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force
trim(name); trim(name);
int nargs = 0; int nargs = 0;
string opts = p.getOpt(); string opts = p.getOpt();
if (opts.size()) { if (!opts.empty()) {
istringstream is(string(opts, 1)); istringstream is(string(opts, 1));
//cerr << "opt: " << is.str() << "\n"; //cerr << "opt: " << is.str() << "\n";
is >> nargs; is >> nargs;
@ -361,13 +361,13 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force
h_preamble << "\\begin{" << name << "}"; h_preamble << "\\begin{" << name << "}";
} }
else if (t.cs().size()) else if (!t.cs().empty())
h_preamble << '\\' << t.cs(); h_preamble << '\\' << t.cs();
} }
p.skip_spaces(); p.skip_spaces();
// Force textclass if the user wanted it // Force textclass if the user wanted it
if (forceclass.size()) { if (!forceclass.empty()) {
h_textclass = forceclass; h_textclass = forceclass;
} }
string layoutfilename = LibFileSearch("layouts", h_textclass, "layout"); string layoutfilename = LibFileSearch("layouts", h_textclass, "layout");
@ -377,7 +377,7 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force
} }
LyXTextClass textclass; LyXTextClass textclass;
textclass.Read(layoutfilename); textclass.Read(layoutfilename);
if (! h_papersides.size()) { if (h_papersides.empty()) {
ostringstream ss; ostringstream ss;
ss << textclass.sides(); ss << textclass.sides();
h_papersides = ss.str(); h_papersides = ss.str();

View File

@ -299,7 +299,7 @@ void handle_tabular(Parser & p, ostream & os,
Context & context) Context & context)
{ {
string posopts = p.getOpt(); string posopts = p.getOpt();
if (posopts.size()) if (!posopts.empty())
cerr << "vertical tabular positioning '" << posopts << "' ignored\n"; cerr << "vertical tabular positioning '" << posopts << "' ignored\n";
vector<ColInfo> colinfo; vector<ColInfo> colinfo;
@ -484,9 +484,9 @@ void handle_tabular(Parser & p, ostream & os,
os << " leftline=\"true\""; os << " leftline=\"true\"";
if (colinfo[col].rightline) if (colinfo[col].rightline)
os << " rightline=\"true\""; os << " rightline=\"true\"";
if (colinfo[col].width.size()) if (!colinfo[col].width.empty())
os << " width=\"" << colinfo[col].width << "\""; os << " width=\"" << colinfo[col].width << "\"";
if (colinfo[col].special.size()) if (!colinfo[col].special.empty())
os << " special=\"" << colinfo[col].special << "\""; os << " special=\"" << colinfo[col].special << "\"";
os << ">\n"; os << ">\n";
} }

View File

@ -43,6 +43,7 @@ using std::ostringstream;
using std::stringstream; using std::stringstream;
using std::string; using std::string;
using std::vector; using std::vector;
using std::map;
using lyx::support::system_lyxdir; using lyx::support::system_lyxdir;
using lyx::support::user_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 documentclass;
string syntaxfile;
bool overwrite_files = false; bool overwrite_files = false;
@ -130,7 +187,8 @@ int parse_help(string const &, string const &)
"\t-f Force creation of .lyx files even if they exist already\n" "\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-userdir dir try to set user directory to dir\n"
"\t-sysdir dir try to set system 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); exit(0);
} }
@ -146,6 +204,17 @@ int parse_class(string const & arg, string const &)
} }
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 &) int parse_sysdir(string const & arg, string const &)
{ {
if (arg.empty()) { if (arg.empty()) {
@ -177,10 +246,11 @@ int parse_force(string const &, string const &)
void easyParse(int & argc, char * argv[]) void easyParse(int & argc, char * argv[])
{ {
std::map<string, cmd_helper> cmdmap; map<string, cmd_helper> cmdmap;
cmdmap["-c"] = parse_class; cmdmap["-c"] = parse_class;
cmdmap["-f"] = parse_force; cmdmap["-f"] = parse_force;
cmdmap["-s"] = parse_syntaxfile;
cmdmap["-help"] = parse_help; cmdmap["-help"] = parse_help;
cmdmap["--help"] = parse_help; cmdmap["--help"] = parse_help;
cmdmap["-sysdir"] = parse_sysdir; cmdmap["-sysdir"] = parse_sysdir;
@ -208,6 +278,8 @@ void easyParse(int & argc, char * argv[])
} }
} }
} // anonymous namespace
void tex2lyx(std::istream &is, std::ostream &os) void tex2lyx(std::istream &is, std::ostream &os)
{ {
@ -267,6 +339,15 @@ int main(int argc, char * argv[])
lyx::support::os::init(&argc, &argv); lyx::support::os::init(&argc, &argv);
lyx::support::setLyxPaths(); 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.empty())
read_syntaxfile(syntaxfile);
if (!IsFileReadable(argv[1])) { if (!IsFileReadable(argv[1])) {
cerr << "Could not open input file \"" << argv[1] cerr << "Could not open input file \"" << argv[1]
<< "\" for reading." << endl; << "\" for reading." << endl;

View File

@ -19,6 +19,7 @@
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
class Context; class Context;
@ -60,6 +61,15 @@ char const ** is_known(std::string const & str, char const ** what);
extern std::vector<std::string> active_environments; extern std::vector<std::string> active_environments;
std::string active_environment(); 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. /*! Reads tex input from \a is and writes lyx output to \a os.
* Uses some common settings for the preamble, so this should only * Uses some common settings for the preamble, so this should only
* be used more than once for included documents. * be used more than once for included documents.

View File

@ -250,7 +250,7 @@ string Parser::getArg(char left, char right)
while ((c = getChar()) != right && good()) { while ((c = getChar()) != right && good()) {
// Ignore comments // Ignore comments
if (curr_token().cat() == catComment) { if (curr_token().cat() == catComment) {
if (curr_token().cs().size()) if (!curr_token().cs().empty())
cerr << "Ignoring comment: " << curr_token().asInput(); cerr << "Ignoring comment: " << curr_token().asInput();
} }
else if (curr_token().cat() == catSpace || curr_token().cat() == catNewline) else if (curr_token().cat() == catSpace || curr_token().cat() == catNewline)

View File

@ -294,6 +294,43 @@ void check_space(Parser const & p, ostream & os, Context & context)
os << ' '; 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, void parse_environment(Parser & p, ostream & os, bool outer,
Context & parent_context) Context & parent_context)
{ {
@ -377,11 +414,11 @@ void parse_environment(Parser & p, ostream & os, bool outer,
// lyx can't handle length variables // lyx can't handle length variables
ostringstream ss; ostringstream ss;
ss << "\\begin{minipage}"; ss << "\\begin{minipage}";
if (latex_position.size()) if (!latex_position.empty())
ss << '[' << latex_position << ']'; ss << '[' << latex_position << ']';
if (latex_height.size()) if (!latex_height.empty())
ss << '[' << latex_height << ']'; ss << '[' << latex_height << ']';
if (latex_inner_pos.size()) if (!latex_inner_pos.empty())
ss << '[' << latex_inner_pos << ']'; ss << '[' << latex_inner_pos << ']';
ss << "{" << width << "}"; ss << "{" << width << "}";
handle_ert(os, ss.str(), parent_context); handle_ert(os, ss.str(), parent_context);
@ -628,7 +665,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
else if (t.cat() == catComment) { else if (t.cat() == catComment) {
context.check_layout(os); context.check_layout(os);
if (t.cs().size()) { if (!t.cs().empty()) {
handle_comment(os, '%' + t.cs(), context); handle_comment(os, '%' + t.cs(), context);
if (p.next_token().cat() == catNewline) { if (p.next_token().cat() == catNewline) {
// A newline after a comment line starts a new paragraph // A newline after a comment line starts a new paragraph
@ -696,7 +733,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
handle_ert(os, "[", context); handle_ert(os, "[", context);
os << s; os << s;
handle_ert(os, "]", context); handle_ert(os, "]", context);
} else if (s.size()) { } else if (!s.empty()) {
// The space is needed to separate the item from the rest of the sentence. // The space is needed to separate the item from the rest of the sentence.
os << s << ' '; os << s << ' ';
p.skip_spaces(); p.skip_spaces();
@ -781,7 +818,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
if (opt.find('t') != string::npos) ss << "Top"; if (opt.find('t') != string::npos) ss << "Top";
if (opt.find('b') != string::npos) ss << "Bottom"; if (opt.find('b') != string::npos) ss << "Bottom";
if (opt.find('B') != string::npos) ss << "Baseline"; if (opt.find('B') != string::npos) ss << "Baseline";
if (ss.str().size()) if (!ss.str().empty())
os << "\trotateOrigin " << ss.str() << '\n'; os << "\trotateOrigin " << ss.str() << '\n';
else else
cerr << "Warning: Ignoring unknown includegraphics origin argument '" << opt << "'\n"; cerr << "Warning: Ignoring unknown includegraphics origin argument '" << opt << "'\n";
@ -838,7 +875,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
if (opts.find("command") != opts.end()) if (opts.find("command") != opts.end())
special << "command=" << opts["command"] << ','; special << "command=" << opts["command"] << ',';
string s_special = special.str(); string s_special = special.str();
if (s_special.size()) { if (!s_special.empty()) {
// We had special arguments. Remove the trailing ','. // We had special arguments. Remove the trailing ','.
os << "\tspecial " << s_special.substr(0, s_special.size() - 1) << '\n'; os << "\tspecial " << s_special.substr(0, s_special.size() - 1) << '\n';
} }
@ -1187,7 +1224,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
begin_inset(os, "LatexCommand "); begin_inset(os, "LatexCommand ");
os << "\\bibtex"; os << "\\bibtex";
// Do we have a bibliographystyle set? // Do we have a bibliographystyle set?
if (bibliographystyle.size()) { if (!bibliographystyle.empty()) {
os << '[' << bibliographystyle << ']'; os << '[' << bibliographystyle << ']';
} }
os << '{' << p.verbatim_item() << "}\n"; os << '{' << p.verbatim_item() << "}\n";
@ -1223,16 +1260,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
// next paragraph. // 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 { else {
//cerr << "#: " << t << " mode: " << mode << endl; //cerr << "#: " << t << " mode: " << mode << endl;
// heuristic: read up to next non-nested space // heuristic: read up to next non-nested space
@ -1247,14 +1274,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
cerr << "found ERT: " << s << endl; cerr << "found ERT: " << s << endl;
handle_ert(os, s + ' ', context); handle_ert(os, s + ' ', context);
*/ */
context.check_layout(os);
string name = t.asInput(); string name = t.asInput();
if (p.next_token().asInput() == "*") { if (p.next_token().asInput() == "*") {
// Starred commands like \vspace*{} // Starred commands like \vspace*{}
p.get_token(); // Eat '*' p.get_token(); // Eat '*'
name += '*'; name += '*';
} }
handle_ert(os, name, context); if (! parse_command(t.asInput(), p, os, outer, context))
handle_ert(os, name, context);
} }
if (flags & FLAG_LEAVE) { if (flags & FLAG_LEAVE) {