Here comes the first part of the rework of InsetCommandParams I have been 
working on.

All parameters do now have a name, and the plan is to get rid of 
getOptions, getSecOptions, getContents etc. in a second step. That will 
make the inset and dialog code easier to understand (especially of the 
more complicated insets like InsetCitation). Right now it is not easy to 
see from the inset code what parameters an inset has. The new code makes 
this more clear, and it is now trivial to add support for commands like

\psfrag{placeholder}[cr][bl]{replacement with $\frac{a}{b}$ formula}

I did not use a map (or multi_map because we need sorted parameters) for 
the parameters, because we currently have at most 3 parameters, so 
searching in a vector is cheap. I don't expect that we get much more 
parameters in the future, but if that should happen one could still change 
the implementation.

Since the number and kind of parameters for a particular command is now 
always known we can now also do some stronger checking. I already found 
out this way that the second option of \cite is set from the frontend.

I have to check the parameter names of the cite commands, I believe that 
some need to be swapped. The command parser in lyx2lyx has also to be 
changed to something that understands nesting. I'll probably simply use 
the code from InsetCommandParams::scanCommand unless somebody has a better 
idea.

If I get no objections I will put this in next week, and after that change 
all code that uses the old getOptions() etc. methods to the new interface.
Then it will be easy to put in the new nomencl inset from Ugras.


Georg


Rework InsetCommandParams interface and file storage

        * src/insets/insetcommandparams.[Ch]:
        (operator[]): New, access a parameter
        (clear): New, clear all parameters
        (info_): New, store info about this command
        (cmdname): Rename to name_
        (contents, options, sec_options): Replace with params_. Parameters
        are now stored as docstring.
        (findInfo): New factor for command info for all commands
        (read, write): Use new syntax
        (parameter set and get methods): reimplemenmt for new parameter storage

        * src/insets/insetcommand.h
        (getParam): New, get a parameter
        (setParam): New, set a parameter
        (parameter set and get methods): Adjust to InsetCommandParams changes

        * src/insets/insetbibitem.[Ch]
        (write): Remove, not needed anymore
        (directWrite): ditto

        * src/insets/insetbibitem.C
        (InsetBibitem::read): Use InsetCommand::read

        * src/insets/insetref.C
        (InsetRef::latex): Use new InsetCommandParams interface

        * src/mathed/InsetMathHull.C
        (InsetMathHull::doDispatch): ditto

        * src/text3.C
        (LyXText::dispatch): ditto

        * src/factory.C
        (createInset): Create InsetCommandParams with command name
        (readInset): ditto
        (readInset): Remove error message for bibitem, since bibitem is
        now a normal command inset

        * src/buffer.C: Bump file format number

        * src/frontends/controllers/ControlCommand.[Ch]
        (ControlCommand): take an additional command name parameter

        * src/text.C
        (readParToken): Remove code for \bibitem

        * lib/lyx2lyx/LyX.py: Bump latest file format number

        * lib/lyx2lyx/lyx_1_5.py
        (convert_bibitem, convert_commandparams): new, convert to new format
        (revert_commandparams): new, convert to old format

        * development/FORMAT: document new format

        * many other files: Adjust to the changes above

Index: src/insets/insetbibtex.C
===================================================================
--- src/insets/insetbibtex.C	(Revision 15336)
+++ src/insets/insetbibtex.C	(Arbeitskopie)
@@ -86,7 +86,7 @@ void InsetBibtex::doDispatch(LCursor & c
 	switch (cmd.action) {
 
 	case LFUN_INSET_MODIFY: {
-		InsetCommandParams p;
+		InsetCommandParams p("bibtex");
 		InsetCommandMailer::string2params("bibtex", lyx::to_utf8(cmd.argument()), p);
 		if (!p.getCmdName().empty()) {
 			setParams(p);
Index: src/insets/insetlabel.C
===================================================================
--- src/insets/insetlabel.C	(Revision 15336)
+++ src/insets/insetlabel.C	(Arbeitskopie)
@@ -64,7 +64,7 @@ void InsetLabel::doDispatch(LCursor & cu
 	switch (cmd.action) {
 
 	case LFUN_INSET_MODIFY: {
-		InsetCommandParams p;
+		InsetCommandParams p("label");
 		InsetCommandMailer::string2params("label", lyx::to_utf8(cmd.argument()), p);
 		if (p.getCmdName().empty()) {
 			cur.noUpdate();
Index: src/insets/insetcommandparams.C
===================================================================
--- src/insets/insetcommandparams.C	(Revision 15336)
+++ src/insets/insetcommandparams.C	(Arbeitskopie)
@@ -4,6 +4,7 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Angus Leeming
+ * \author Georg Baum
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -15,23 +16,154 @@
 #include "debug.h"
 #include "lyxlex.h"
 
+#include "support/lstrings.h"
+
+#include <boost/assert.hpp>
+
+
+using lyx::docstring;
+using lyx::support::findToken;
 
 using std::string;
 using std::endl;
 using std::ostream;
 
 
-InsetCommandParams::InsetCommandParams()
-{}
+InsetCommandParams::InsetCommandParams(string const & name)
+	: name_(name), preview_(false)
+{
+	info_ = findInfo(name);
+	BOOST_ASSERT(info_);
+	params_.resize(info_->n);
+}
+
+
+InsetCommandParams::CommandInfo const *
+InsetCommandParams::findInfo(std::string const & name)
+{
+	// No parameter may be named "preview", because that is a required
+	// flag for all commands.
+
+	// InsetBibitem
+	if (name == "bibitem") {
+		static const char * const paramnames[] = {"label", "key", ""};
+		static const bool isoptional[] = {true, false};
+		static const CommandInfo info = {2, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetBibtex
+	if (name == "bibtex") {
+		static const char * const paramnames[] =
+				{"options", "btprint", "bibfiles", ""};
+		static const bool isoptional[] = {true, true, false};
+		static const CommandInfo info = {3, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetCitation
+	if (name == "cite") {
+		static const char * const paramnames[] = {"after", "key", ""};
+		static const bool isoptional[] = {true, false};
+		static const CommandInfo info = {2, paramnames, isoptional};
+		return &info;
+	}
+	// FIXME: Use is_possible_cite_command() in
+	// src/frontends/controllers/biblio.C, see comment in src/factory.C.
+	if (name == "citet" || name == "citep" || name == "citealt" ||
+	    name == "citealp" || name == "citeauthor" || name == "citeyear" ||
+	    name == "citeyearpar" || name == "citet*" || name == "citep*" ||
+	    name == "citealt*" || name == "citealp*" ||
+	    name == "citeauthor*" || name == "Citet" || name == "Citep" ||
+	    name == "Citealt" || name == "Citealp" || name == "Citeauthor" ||
+	    name == "Citet*" || name == "Citep*" || name == "Citealt*" ||
+	    name == "Citealp*" || name == "Citeauthor*" ||
+	    name == "citefield" || name == "citetitle" || name == "cite*") {
+		static const char * const paramnames[] =
+				{"after", "before", "key", ""};
+		static const bool isoptional[] = {true, true, false};
+		static const CommandInfo info = {3, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetFloatlist
+	if (name == "floatlist") {
+		static const char * const paramnames[] = {"type", ""};
+		static const bool isoptional[] = {false};
+		static const CommandInfo info = {1, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetHfill
+	if (name == "hfill") {
+		static const char * const paramnames[] = {""};
+		static const CommandInfo info = {0, paramnames, 0};
+		return &info;
+	}
+
+	// InsetInclude
+	if (name == "include" || name == "input" || name == "verbatiminput" ||
+	    name == "verbatiminput*") {
+		static const char * const paramnames[] = {"filename", ""};
+		static const bool isoptional[] = {false};
+		static const CommandInfo info = {1, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetIndex, InsetPrintIndex, InsetLabel
+	if (name == "index" || name == "printindex" || name == "label") {
+		static const char * const paramnames[] = {"name", ""};
+		static const bool isoptional[] = {false};
+		static const CommandInfo info = {1, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetRef
+	if (name == "eqref" || name == "pageref" || name == "vpageref" ||
+	    name == "vref" || name == "prettyref" || name == "ref") {
+		static const char * const paramnames[] =
+				{"name", "reference", ""};
+		static const bool isoptional[] = {true, false};
+		static const CommandInfo info = {2, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetTOC
+	if (name == "tableofcontents") {
+		static const char * const paramnames[] = {"type", ""};
+		static const bool isoptional[] = {false};
+		static const CommandInfo info = {1, paramnames, isoptional};
+		return &info;
+	}
+
+	// InsetUrl
+	if (name == "htmlurl" || name == "url") {
+		static const char * const paramnames[] =
+				{"name", "target", ""};
+		static const bool isoptional[] = {true, false};
+		static const CommandInfo info = {2, paramnames, isoptional};
+		return &info;
+	}
+
+	return 0;
+}
 
 
-InsetCommandParams::InsetCommandParams(string const & n,
-					string const & c,
-					string const & o,
-					string const & s)
-	: cmdname(n), contents(c), options(o), sec_options(s),
-	preview_(false)
-{}
+void InsetCommandParams::setCmdName(string const & name)
+{
+	name_ = name;
+	CommandInfo const * const info = findInfo(name);
+	BOOST_ASSERT(info);
+	ParamVector params(info->n);
+	// Overtake parameters with the same name
+	for (size_t i = 0; i < info_->n; ++i) {
+		int j = findToken(info->paramnames, info_->paramnames[i]);
+		if (j >= 0)
+			params[j] = params_[i];
+	}
+	info_ = info;
+	std::swap(params, params_);
+}
 
 
 void InsetCommandParams::scanCommand(string const & cmd)
@@ -108,24 +240,32 @@ void InsetCommandParams::scanCommand(str
 
 void InsetCommandParams::read(LyXLex & lex)
 {
-	string token;
-
-	if (lex.eatLine()) {
-		token = lex.getString();
-		scanCommand(token);
-	} else {
-		lex.printError("InsetCommand: Parse error: `$$Token'");
+	if (lex.isOK()) {
+		lex.next();
+		name_ = lex.getString();
+		info_ = findInfo(name_);
+		if (!info_)
+			lex.printError("InsetCommand: Unknown inset name `$$Token'");
 	}
 
+	string token;
 	while (lex.isOK()) {
 		lex.next();
 		token = lex.getString();
 		if (token == "\\end_inset")
 			break;
+		// FIXME Why is preview_ read but not written?
 		if (token == "preview") {
 			lex.next();
 			preview_ = lex.getBool();
+			continue;
 		}
+		int const i = findToken(info_->paramnames, token);
+		if (i >= 0) {
+			lex.next(true);
+			params_[i] = lex.getDocString();
+		} else
+			lex.printError("Unknown parameter name `$$Token' for command " + name_);
 	}
 	if (token != "\\end_inset") {
 		lex.printError("Missing \\end_inset at this point. "
@@ -136,33 +276,151 @@ void InsetCommandParams::read(LyXLex & l
 
 void InsetCommandParams::write(ostream & os) const
 {
-	os << "LatexCommand " << getCommand() << "\n";
+	os << "LatexCommand " << name_ << '\n';
+	for (size_t i = 0; i < info_->n; ++i)
+		if (!params_[i].empty())
+			// FIXME UNICODE
+			os << info_->paramnames[i] << ' '
+			   << LyXLex::quoteString(lyx::to_utf8(params_[i]))
+			   << '\n';
 }
 
 
 string const InsetCommandParams::getCommand() const
 {
-	string s;
-	if (!getCmdName().empty()) s += '\\' + getCmdName();
-	if (!getOptions().empty()) s += '[' + getOptions() + ']';
-	if (!getSecOptions().empty()) {
-		// for cases like \command[][sec_option]{arg}
-		if (getOptions().empty()) s += "[]";
-	s += '[' + getSecOptions() + ']';
+	docstring s = '\\' + lyx::from_ascii(name_);
+	for (size_t i = 0; i < info_->n; ++i) {
+		if (info_->optional[i]) {
+			if (params_[i].empty()) {
+				// We need to write this parameter even if
+				// it is empty if nonempty optional parameters
+				// follow before the next required parameter.
+				for (size_t j = i + 1; j < info_->n; ++j) {
+					if (!info_->optional[j])
+						break;
+					if (!params_[j].empty()) {
+						s += "[]";
+						break;
+					}
+				}
+			} else
+				s += '[' + params_[i] + ']';
+		} else
+			s += '{' + params_[i] + '}';
 	}
-	s += '{' + getContents() + '}';
-	return s;
+	return lyx::to_utf8(s);
+}
+
+
+std::string const InsetCommandParams::getOptions() const
+{
+	for (size_t i = 0; i < info_->n; ++i)
+		if (info_->optional[i])
+			return lyx::to_utf8(params_[i]);
+	lyxerr << "Programming error: get nonexisting option in "
+	       << name_ << " inset."; 
+	return string();
+}
+
+
+std::string const InsetCommandParams::getSecOptions() const
+{
+	bool first = true;
+	for (size_t i = 0; i < info_->n; ++i)
+		if (info_->optional[i]) {
+			if (first)
+				first = false;
+			else
+				return lyx::to_utf8(params_[i]);
+		}
+	// Happens in InsetCitation
+	lyxerr << "Programming error: get nonexisting second option in "
+	       << name_ << " inset."; 
+	return string();
+}
+
+
+std::string const InsetCommandParams::getContents() const
+{
+	for (size_t i = 0; i < info_->n; ++i)
+		if (!info_->optional[i])
+			return lyx::to_utf8(params_[i]);
+	BOOST_ASSERT(false);
+	return string();
+}
+
+
+void InsetCommandParams::setOptions(std::string const & o)
+{
+	for (size_t i = 0; i < info_->n; ++i)
+		if (info_->optional[i]) {
+			params_[i] = lyx::from_utf8(o);
+			return;
+		}
+	lyxerr << "Programming error: set nonexisting option in "
+	       << name_ << " inset."; 
+}
+
+
+void InsetCommandParams::setSecOptions(std::string const & s)
+{
+	bool first = true;
+	for (size_t i = 0; i < info_->n; ++i)
+		if (info_->optional[i]) {
+			if (first)
+				first = false;
+			else {
+				params_[i] = lyx::from_utf8(s);
+				return;
+			}
+		}
+	// Happens in InsetCitation
+	lyxerr << "Programming error: set nonexisting second option in "
+	       << name_ << " inset."; 
+}
+
+
+void InsetCommandParams::setContents(std::string const & c)
+{
+	for (size_t i = 0; i < info_->n; ++i)
+		if (!info_->optional[i]) {
+			params_[i] = lyx::from_utf8(c);
+			return;
+		}
+	BOOST_ASSERT(false);
+}
+
+
+docstring const & InsetCommandParams::operator[](string const & name) const
+{
+	int const i = findToken(info_->paramnames, name);
+	BOOST_ASSERT(i >= 0);
+	return params_[i];
+}
+
+
+docstring & InsetCommandParams::operator[](string const & name)
+{
+	int const i = findToken(info_->paramnames, name);
+	BOOST_ASSERT(i >= 0);
+	return params_[i];
+}
+
+
+void InsetCommandParams::clear()
+{
+	for (size_t i = 0; i < info_->n; ++i)
+		params_[i].clear();
 }
 
 
 bool operator==(InsetCommandParams const & o1,
 		InsetCommandParams const & o2)
 {
-	return o1.getCmdName() == o2.getCmdName()
-		&& o1.getContents() == o2.getContents()
-		&& o1.getOptions() == o2.getOptions()
-		&& o1.getSecOptions() == o2.getSecOptions()
-		&& o1.preview() == o2.preview();
+	return o1.name_ == o2.name_ &&
+	       o1.info_ == o2.info_ &&
+	       o1.params_ == o2.params_ &&
+	       o1.preview_ == o2.preview_;
 }
 
 
Index: src/insets/insetcommand.h
===================================================================
--- src/insets/insetcommand.h	(Revision 15336)
+++ src/insets/insetcommand.h	(Arbeitskopie)
@@ -45,6 +45,7 @@ public:
 	virtual void read(Buffer const &, LyXLex & lex)
 		{ p_.read(lex); }
 	/// Can remove one InsetBibKey is modified
+	/// FIXME remove
 	void scanCommand(std::string const & c) { p_.scanCommand(c); };
 	///
 	virtual int latex(Buffer const &, std::ostream &,
@@ -60,20 +61,31 @@ public:
 
 	///
 	InsetCommandParams const & params() const { return p_; }
-	///
-	std::string const & getContents() const { return p_.getContents(); }
-	///
+	/// FIXME remove
+	std::string const getContents() const { return p_.getContents(); }
+	/// FIXME remove
 	void setContents(std::string const & c)
 	{
 		updateButtonLabel_ = true;
 		p_.setContents(c);
 	}
 	///
-	virtual void replaceContents(std::string const & from, std::string const & to);
-	///
-	std::string const & getOptions() const { return p_.getOptions(); }
+	void setParam(std::string const & name, lyx::docstring const & value)
+	{
+		updateButtonLabel_ = true;
+		p_[name] = value;
+	}
 	///
-	std::string const & getSecOptions() const { return p_.getSecOptions(); }
+	lyx::docstring const & getParam(std::string const & name) const
+	{
+		return p_[name];
+	}
+	/// FIXME remove
+	virtual void replaceContents(std::string const & from, std::string const & to);
+	/// FIXME remove
+	std::string const getOptions() const { return p_.getOptions(); }
+	/// FIXME remove
+	std::string const getSecOptions() const { return p_.getSecOptions(); }
 	///
 	RenderButton & button() const { return button_; }
 
Index: src/insets/insetcite.h
===================================================================
--- src/insets/insetcite.h	(Revision 15336)
+++ src/insets/insetcite.h	(Arbeitskopie)
@@ -58,7 +58,7 @@ private:
 	class Cache {
 	public:
 		///
-		Cache() : engine(lyx::biblio::ENGINE_BASIC) {}
+		Cache() : engine(lyx::biblio::ENGINE_BASIC), params("cite") {}
 		///
 		lyx::biblio::CiteEngine engine;
 		///
Index: src/insets/insetcommandparams.h
===================================================================
--- src/insets/insetcommandparams.h	(Revision 15336)
+++ src/insets/insetcommandparams.h	(Arbeitskopie)
@@ -5,6 +5,7 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Angus Leeming
+ * \author Georg Baum
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -12,8 +13,10 @@
 #ifndef INSETCOMMANDPARAMS_H
 #define INSETCOMMANDPARAMS_H
 
-#include <string>
+#include "support/docstring.h"
+
 #include <iosfwd>
+#include <vector>
 
 
 class LyXLex;
@@ -21,53 +24,74 @@ class LyXLex;
 
 class InsetCommandParams {
 public:
-	///
-	InsetCommandParams();
-	///
-	explicit InsetCommandParams(std::string const & n,
-			    std::string const & c = std::string(),
-			    std::string const & o = std::string(),
-			    std::string const & s = std::string());
+	/// Construct parameters for command \p name. \p name must be known.
+	explicit InsetCommandParams(std::string const & name);
 	///
 	void read(LyXLex &);
 	/// Parse the command
+	/// FIXME remove
 	void scanCommand(std::string const &);
 	///
 	void write(std::ostream &) const;
 	/// Build the complete LaTeX command
 	std::string const getCommand() const;
-	///
-	std::string const & getCmdName() const { return cmdname; }
-	///
-	std::string const & getOptions() const { return options; }
-	///
-	std::string const & getSecOptions() const { return sec_options; }
-	///
-	std::string const & getContents() const { return contents; }
-	///
-	void setCmdName(std::string const & n) { cmdname = n; }
-	///
-	void setOptions(std::string const & o) { options = o; }
-	///
-	void setSecOptions(std::string const & s) { sec_options = s; }
-	///
-	void setContents(std::string const & c) { contents = c; }
+	/// Return the command name
+	std::string const & getCmdName() const { return name_; }
+	/// FIXME remove
+	std::string const getOptions() const;
+	/// FIXME remove
+	std::string const getSecOptions() const;
+	/// FIXME remove
+	std::string const getContents() const;
+	/// Set the name to \p n. This must be a known name. All parameters
+	/// are cleared except those that exist also in the new command.
+	/// What matters here is the parameter name, not position.
+	void setCmdName(std::string const & n);
+	/// FIXME remove
+	void setOptions(std::string const &);
+	/// FIXME remove
+	void setSecOptions(std::string const &);
+	/// FIXME remove
+	void setContents(std::string const &);
+	/// get parameter \p name
+	lyx::docstring const & operator[](std::string const & name) const;
+	/// set parameter \p name
+	lyx::docstring & operator[](std::string const & name);
 	///
 	bool preview() const { return preview_; }
 	///
 	void preview(bool p) { preview_ = p; }
+	/// Clear the values of all parameters
+	void clear();
 
 private:
 	///
-	std::string cmdname;
-	///
-	std::string contents;
-	///
-	std::string options;
-	///
-	std::string sec_options;
+	struct CommandInfo {
+		/// Number of parameters
+		size_t n;
+		/// Parameter names. paramnames[n] must be "".
+		char const * const * paramnames;
+		/// Tells whether a parameter is optional
+		bool const * optional;
+	};
+	/// Get information for command \p name.
+	/// Returns 0 if the command is not known.
+	static CommandInfo const * findInfo(std::string const & name);
+	/// Description of all command properties
+	CommandInfo const * info_;
+	/// The name of this command as it appears in .lyx and .tex files
+	std::string name_;
+	///
+	typedef std::vector<lyx::docstring> ParamVector;
+	/// The parameters (both optional and required ones). The order is
+	/// the same that is required for LaTeX output. The size of params_
+	/// is always info_->n.
+	ParamVector params_;
 	///
 	bool preview_;
+	///
+	friend bool operator==(InsetCommandParams const &,
+			InsetCommandParams const &);
 };
 
 
Index: src/insets/insetbibitem.C
===================================================================
--- src/insets/insetbibitem.C	(Revision 15336)
+++ src/insets/insetbibitem.C	(Arbeitskopie)
@@ -57,7 +57,7 @@ void InsetBibitem::doDispatch(LCursor & 
 	switch (cmd.action) {
 
 	case LFUN_INSET_MODIFY: {
-		InsetCommandParams p;
+		InsetCommandParams p("bibitem");
 		InsetCommandMailer::string2params("bibitem", lyx::to_utf8(cmd.argument()), p);
 		if (p.getCmdName().empty()) {
  			cur.noUpdate();
@@ -82,27 +82,9 @@ void InsetBibitem::setCounter(int c)
 }
 
 
-// I'm sorry but this is still necessary because \bibitem is used also
-// as a LyX 2.x command, and lyxlex is not enough smart to understand
-// real LaTeX commands. Yes, that could be fixed, but would be a waste
-// of time cause LyX3 won't use lyxlex anyway.  (ale)
-void InsetBibitem::write(Buffer const &, std::ostream & os) const
-{
-	os << "\n\\bibitem ";
-	if (!getOptions().empty())
-		os << '[' << getOptions() << ']';
-	os << '{' << getContents() << "}\n";
-}
-
-
-// This is necessary here because this is written without begin_inset
-// This should be changed!!! (Jug)
-void InsetBibitem::read(Buffer const &, LyXLex & lex)
-{
-	if (lex.eatLine())
-		scanCommand(lex.getString());
-	else
-		lex.printError("InsetCommand: Parse error: `$$Token'");
+void InsetBibitem::read(Buffer const & buf, LyXLex & lex)
+{
+	InsetCommand::read(buf, lex);
 
 	if (prefixIs(getContents(), key_prefix)) {
 		int const key = convert<int>(getContents().substr(key_prefix.length()));
Index: src/insets/insetfloatlist.C
===================================================================
--- src/insets/insetfloatlist.C	(Revision 15336)
+++ src/insets/insetfloatlist.C	(Arbeitskopie)
@@ -36,12 +36,12 @@ using std::ostream;
 
 
 InsetFloatList::InsetFloatList()
-	: InsetCommand(InsetCommandParams(), "toc")
+	: InsetCommand(InsetCommandParams("floatlist"), "toc")
 {}
 
 
 InsetFloatList::InsetFloatList(string const & type)
-	: InsetCommand(InsetCommandParams(), "toc")
+	: InsetCommand(InsetCommandParams("floatlist"), "toc")
 {
 	setCmdName(type);
 }
Index: src/insets/insetref.C
===================================================================
--- src/insets/insetref.C	(Revision 15336)
+++ src/insets/insetref.C	(Arbeitskopie)
@@ -87,12 +87,10 @@ docstring const InsetRef::getScreenLabel
 int InsetRef::latex(Buffer const &, ostream & os,
 		    OutputParams const &) const
 {
-	if (getOptions().empty())
-		os << escape(getCommand());
-	else {
-		InsetCommandParams p(getCmdName(), getContents(), "");
-		os << escape(p.getCommand());
-	}
+	// Don't output p_["name"], this is only used in docbook
+	InsetCommandParams p(getCmdName());
+	p["reference"] = getParam("reference");
+	os << escape(p.getCommand());
 	return 0;
 }
 
Index: src/insets/insetcommand.C
===================================================================
--- src/insets/insetcommand.C	(Revision 15336)
+++ src/insets/insetcommand.C	(Arbeitskopie)
@@ -31,7 +31,7 @@ using std::ostringstream;
 
 InsetCommand::InsetCommand(InsetCommandParams const & p,
 			   string const & mailer_name)
-	: p_(p.getCmdName(), p.getContents(), p.getOptions(), p.getSecOptions()),
+	: p_(p),
 	  mailer_name_(mailer_name),
 	  updateButtonLabel_(true)
 {}
@@ -100,7 +100,7 @@ void InsetCommand::doDispatch(LCursor & 
 		break;
 
 	case LFUN_INSET_MODIFY: {
-		InsetCommandParams p;
+		InsetCommandParams p(p_.getCmdName());
 		InsetCommandMailer::string2params(mailer_name_, lyx::to_utf8(cmd.argument()), p);
 		if (p.getCmdName().empty())
 			cur.noUpdate();
@@ -172,7 +172,7 @@ void InsetCommandMailer::string2params(s
 				       string const & in,
 				       InsetCommandParams & params)
 {
-	params = InsetCommandParams();
+	params.clear();
 	if (in.empty())
 		return;
 
Index: src/insets/insetbibitem.h
===================================================================
--- src/insets/insetbibitem.h	(Revision 15336)
+++ src/insets/insetbibitem.h	(Arbeitskopie)
@@ -24,10 +24,6 @@ class InsetBibitem : public InsetCommand
 public:
 	///
 	InsetBibitem(InsetCommandParams const &);
-	/** Currently \bibitem is used as a LyX2.x command,
-	    so we need this method.
-	*/
-	void write(Buffer const &, std::ostream &) const;
 	///
 	void read(Buffer const &, LyXLex & lex);
 	///
@@ -36,8 +32,6 @@ public:
 	EDITABLE editable() const { return IS_EDITABLE; }
 	///
 	InsetBase::Code lyxCode() const { return InsetBase::BIBITEM_CODE; }
-	/// keep .lyx format compatible
-	bool directWrite() const { return true; }
 	///
 	void setCounter(int);
 	///
Index: src/insets/insetinclude.C
===================================================================
--- src/insets/insetinclude.C	(Revision 15336)
+++ src/insets/insetinclude.C	(Arbeitskopie)
@@ -126,7 +126,7 @@ void InsetInclude::doDispatch(LCursor & 
 	switch (cmd.action) {
 
 	case LFUN_INSET_MODIFY: {
-		InsetCommandParams p;
+		InsetCommandParams p("include");
 		InsetIncludeMailer::string2params(lyx::to_utf8(cmd.argument()), p);
 		if (!p.getCmdName().empty()) {
 			set(p, cur.buffer());
@@ -761,7 +761,7 @@ string const InsetIncludeMailer::inset2s
 void InsetIncludeMailer::string2params(string const & in,
 				       InsetCommandParams & params)
 {
-	params = InsetCommandParams();
+	params.clear();
 	if (in.empty())
 		return;
 
Index: src/mathed/InsetMathHull.C
===================================================================
--- src/mathed/InsetMathHull.C	(Revision 15336)
+++ src/mathed/InsetMathHull.C	(Arbeitskopie)
@@ -1088,15 +1088,14 @@ void InsetMathHull::doDispatch(LCursor &
 	case LFUN_LABEL_INSERT: {
 		recordUndoInset(cur);
 		row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
-		string old_label = label(r);
-		string const default_label =
-			(lyxrc.label_init_length >= 0) ? "eq:" : "";
+		docstring old_label = lyx::from_utf8(label(r));
+		docstring const default_label = lyx::from_ascii(
+			(lyxrc.label_init_length >= 0) ? "eq:" : "");
 		if (old_label.empty())
 			old_label = default_label;
-		string const contents = cmd.argument().empty() ?
-			old_label : lyx::to_utf8(cmd.argument());
 
-		InsetCommandParams p("label", contents);
+		InsetCommandParams p("label");
+		p["name"] = cmd.argument().empty() ? old_label : cmd.argument();
 		string const data = InsetCommandMailer::params2string("label", p);
 
 		if (cmd.argument().empty())
@@ -1112,7 +1111,7 @@ void InsetMathHull::doDispatch(LCursor &
 		//lyxerr << "arg: " << lyx::to_utf8(cmd.argument()) << endl;
 		string const name = cmd.getArg(0);
 		if (name == "label") {
-			InsetCommandParams p;
+			InsetCommandParams p("label");
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()), p);
 			string str = p.getContents();
 			recordUndoInset(cur);
Index: src/factory.C
===================================================================
--- src/factory.C	(Revision 15336)
+++ src/factory.C	(Arbeitskopie)
@@ -211,19 +211,19 @@ InsetBase * createInset(BufferView * bv,
 		string const name = cmd.getArg(0);
 
 		if (name == "bibitem") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetBibitem(icp);
 
 		} else if (name == "bibtex") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetBibtex(icp);
 
 		} else if (name == "citation") {
-			InsetCommandParams icp;
+			InsetCommandParams icp("cite");
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetCitation(icp);
@@ -252,36 +252,36 @@ InsetBase * createInset(BufferView * bv,
 			return inset.release();
 
 		} else if (name == "include") {
-			InsetCommandParams iip;
+			InsetCommandParams iip(name);
 			InsetIncludeMailer::string2params(lyx::to_utf8(cmd.argument()), iip);
 			return new InsetInclude(iip);
 
 		} else if (name == "index") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetIndex(icp);
 
 		} else if (name == "label") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetLabel(icp);
 
 		} else if (name == "ref") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetRef(icp, *bv->buffer());
 
 		} else if (name == "toc") {
-			InsetCommandParams icp;
+			InsetCommandParams icp("tableofcontents");
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetTOC(icp);
 
 		} else if (name == "url") {
-			InsetCommandParams icp;
+			InsetCommandParams icp(name);
 			InsetCommandMailer::string2params(name, lyx::to_utf8(cmd.argument()),
 							  icp);
 			return new InsetUrl(icp);
@@ -344,10 +344,12 @@ InsetBase * readInset(LyXLex & lex, Buff
 
 	// test the different insets
 	if (tmptok == "LatexCommand") {
-		InsetCommandParams inscmd;
-		inscmd.read(lex);
+		lex.next();
+		string const cmdName = lex.getString();
+		lex.pushToken(cmdName);
 
-		string const cmdName = inscmd.getCmdName();
+		InsetCommandParams inscmd(cmdName);
+		inscmd.read(lex);
 
 		// This strange command allows LyX to recognize "natbib" style
 		// citations: citet, citep, Citet etc.
@@ -360,7 +362,6 @@ InsetBase * readInset(LyXLex & lex, Buff
 		if (compare_ascii_no_case(cmdName.substr(0,4), "cite") == 0) {
 			inset.reset(new InsetCitation(inscmd));
 		} else if (cmdName == "bibitem") {
-			lex.printError("Wrong place for bibitem");
 			inset.reset(new InsetBibitem(inscmd));
 		} else if (cmdName == "bibtex") {
 			inset.reset(new InsetBibtex(inscmd));
Index: src/buffer.C
===================================================================
--- src/buffer.C	(Revision 15336)
+++ src/buffer.C	(Arbeitskopie)
@@ -144,7 +144,7 @@ using std::string;
 
 namespace {
 
-int const LYX_FORMAT = 250;
+int const LYX_FORMAT = 251;
 
 } // namespace anon
 
Index: src/frontends/gtk/Dialogs.C
===================================================================
--- src/frontends/gtk/Dialogs.C	(Revision 15336)
+++ src/frontends/gtk/Dialogs.C	(Arbeitskopie)
@@ -185,7 +185,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "bibitem") {
 		dialog->bc().view(new GBC(dialog->bc()));
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new GBibItem(*dialog));
 		dialog->bc().bp(new OkCancelReadOnlyPolicy);
 	} else if (name == "bibtex") {
@@ -260,7 +260,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->bc().bp(new OkApplyCancelReadOnlyPolicy);
 	} else if (name == "index") {
 		dialog->bc().view(new GBC(dialog->bc()));
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		// FIXME UNICODE
 		dialog->setView(new GText(*dialog,
 					  lyx::to_utf8(_("Index Entry")),
@@ -268,7 +268,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "label") {
 		dialog->bc().view(new GBC(dialog->bc()));
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		// FIXME UNICODE
 		dialog->setView(new GText(*dialog,
 					  lyx::to_utf8(_("Label")),
@@ -548,7 +548,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "url") {
 		dialog->bc().view(new GBC(dialog->bc()));
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new GUrl(*dialog));
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "vspace") {
Index: src/frontends/qt3/Dialogs.C
===================================================================
--- src/frontends/qt3/Dialogs.C	(Revision 15336)
+++ src/frontends/qt3/Dialogs.C	(Arbeitskopie)
@@ -150,7 +150,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QAbout(*dialog));
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "bibitem") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QBibitem(*dialog));
 		dialog->bc().bp(new OkCancelReadOnlyPolicy);
 	} else if (name == "bibtex") {
@@ -214,13 +214,13 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QInclude(*dialog));
 		dialog->bc().bp(new OkApplyCancelReadOnlyPolicy);
 	} else if (name == "index") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QIndex(*dialog,
 					   _("Index Entry"),
 					   qt_("&Keyword:")));
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "label") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QIndex(*dialog,
 					   _("Label"),
 					   qt_("&Label:")));
@@ -296,7 +296,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QToc(*dialog));
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "url") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QURL(*dialog));
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "vspace") {
Index: src/frontends/qt4/Dialogs.C
===================================================================
--- src/frontends/qt4/Dialogs.C	(Revision 15336)
+++ src/frontends/qt4/Dialogs.C	(Arbeitskopie)
@@ -146,7 +146,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QAbout(*dialog));
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "bibitem") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QBibitem(*dialog));
 		dialog->bc().bp(new OkCancelReadOnlyPolicy);
 	} else if (name == "bibtex") {
@@ -211,13 +211,13 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QInclude(*dialog));
 		dialog->bc().bp(new OkApplyCancelReadOnlyPolicy);
 	} else if (name == "index") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QIndex(*dialog,
 					   _("Index Entry"),
 					   qt_("&Keyword:")));
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "label") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new QIndex(*dialog,
 					   _("Label"),
 					   qt_("&Label:")));
@@ -295,7 +295,7 @@ Dialogs::DialogPtr Dialogs::build(string
 		dialog->setView(new QTocDialog(*dialog, qtoc));
 		dialog->bc().bp(new OkCancelPolicy);
 	} else if (name == "url") {
-		dialog->setController(new ControlCommand(*dialog, name));
+		dialog->setController(new ControlCommand(*dialog, name, name));
 		dialog->setView(new UrlView(*dialog));
 		dialog->bc().bp(new NoRepeatedApplyReadOnlyPolicy);
 	} else if (name == "vspace") {
Index: src/frontends/controllers/ControlBibtex.C
===================================================================
--- src/frontends/controllers/ControlBibtex.C	(Revision 15336)
+++ src/frontends/controllers/ControlBibtex.C	(Arbeitskopie)
@@ -44,7 +44,7 @@ namespace frontend {
 
 
 ControlBibtex::ControlBibtex(Dialog & d)
-	: ControlCommand(d, "bibtex")
+	: ControlCommand(d, "bibtex", "bibtex")
 {}
 
 
Index: src/frontends/controllers/ControlRef.C
===================================================================
--- src/frontends/controllers/ControlRef.C	(Revision 15336)
+++ src/frontends/controllers/ControlRef.C	(Arbeitskopie)
@@ -32,7 +32,7 @@ using support::makeDisplayPath;
 namespace frontend {
 
 ControlRef::ControlRef(Dialog & d)
-	: ControlCommand(d, "ref")
+	: ControlCommand(d, "ref", "ref")
 {}
 
 
Index: src/frontends/controllers/ControlCommand.C
===================================================================
--- src/frontends/controllers/ControlCommand.C	(Revision 15336)
+++ src/frontends/controllers/ControlCommand.C	(Arbeitskopie)
@@ -21,8 +21,9 @@ using std::string;
 namespace lyx {
 namespace frontend {
 
-ControlCommand::ControlCommand(Dialog & dialog, string const & lfun_name)
-	: Dialog::Controller(dialog),
+ControlCommand::ControlCommand(Dialog & dialog, string const & command_name,
+                               string const & lfun_name)
+	: Dialog::Controller(dialog), params_(command_name),
 	  lfun_name_(lfun_name)
 {}
 
@@ -38,7 +39,7 @@ bool ControlCommand::initialiseParams(st
 
 void ControlCommand::clearParams()
 {
-	params_ = InsetCommandParams();
+	params_.clear();
 }
 
 
Index: src/frontends/controllers/ControlInclude.C
===================================================================
--- src/frontends/controllers/ControlInclude.C	(Revision 15336)
+++ src/frontends/controllers/ControlInclude.C	(Arbeitskopie)
@@ -42,7 +42,7 @@ using support::onlyPath;
 namespace frontend {
 
 ControlInclude::ControlInclude(Dialog & parent)
-	: Dialog::Controller(parent)
+	: Dialog::Controller(parent), params_("include")
 {}
 
 
@@ -55,7 +55,7 @@ bool ControlInclude::initialiseParams(st
 
 void ControlInclude::clearParams()
 {
-	params_ = InsetCommandParams();
+	params_.clear();
 }
 
 
Index: src/frontends/controllers/ControlToc.C
===================================================================
--- src/frontends/controllers/ControlToc.C	(Revision 15336)
+++ src/frontends/controllers/ControlToc.C	(Arbeitskopie)
@@ -29,7 +29,7 @@ namespace frontend {
 
 
 ControlToc::ControlToc(Dialog & d)
-	: ControlCommand(d, "toc")
+	: ControlCommand(d, "tableofcontents", "toc")
 {}
 
 
Index: src/frontends/controllers/ControlCitation.C
===================================================================
--- src/frontends/controllers/ControlCitation.C	(Revision 15336)
+++ src/frontends/controllers/ControlCitation.C	(Arbeitskopie)
@@ -28,7 +28,7 @@ vector<biblio::CiteStyle> ControlCitatio
 
 
 ControlCitation::ControlCitation(Dialog & d)
-	: ControlCommand(d, "citation")
+	: ControlCommand(d, "cite", "citation")
 {}
 
 
Index: src/frontends/controllers/ControlCommand.h
===================================================================
--- src/frontends/controllers/ControlCommand.h	(Revision 15336)
+++ src/frontends/controllers/ControlCommand.h	(Arbeitskopie)
@@ -26,9 +26,11 @@ class ControlCommand : public Dialog::Co
 public:
 	/** LFUN_INSET_APPLY requires a name, "citation", "ref" etc so that
 	    it knows what to do with the rest of the contents.
-	    An empty name indicates that no action will occur on 'Apply'.
+	    An empty \p lfun_name indicates that no action will occur on
+	    'Apply'.
 	 */
-	ControlCommand(Dialog &, std::string const & lfun_name = std::string());
+	ControlCommand(Dialog &, std::string const & command_name,
+	               std::string const & lfun_name);
 	///
 	InsetCommandParams & params() { return params_; }
 	///
Index: src/text3.C
===================================================================
--- src/text3.C	(Revision 15336)
+++ src/text3.C	(Arbeitskopie)
@@ -1099,11 +1099,12 @@ void LyXText::dispatch(LCursor & cur, Fu
 	}
 
 	case LFUN_LABEL_INSERT: {
+		InsetCommandParams p("label");
 		// Try to generate a valid label
-		string const contents = cmd.argument().empty() ?
-			cur.getPossibleLabel() : lyx::to_utf8(cmd.argument());
-
-		InsetCommandParams p("label", contents);
+		p["name"] = (cmd.argument().empty()) ?
+			// FIXME UNICODE
+			lyx::from_utf8(cur.getPossibleLabel()) :
+			cmd.argument();
 		string const data = InsetCommandMailer::params2string("label", p);
 
 		if (cmd.argument().empty()) {
Index: src/text.C
===================================================================
--- src/text.C	(Revision 15336)
+++ src/text.C	(Arbeitskopie)
@@ -314,11 +314,6 @@ void readParToken(Buffer const & buf, Pa
 		auto_ptr<InsetBase> inset(new InsetTabular(buf));
 		inset->read(buf, lex);
 		par.insertInset(par.size(), inset.release(), font, change);
-	} else if (token == "\\bibitem") {
-		InsetCommandParams p("bibitem", "dummy");
-		auto_ptr<InsetBibitem> inset(new InsetBibitem(p));
-		inset->read(buf, lex);
-		par.insertInset(par.size(), inset.release(), font, change);
 	} else if (token == "\\hfill") {
 		par.insertInset(par.size(), new InsetHFill, font, change);
 	} else if (token == "\\lyxline") {
Index: lib/lyx2lyx/LyX.py
===================================================================
--- lib/lyx2lyx/LyX.py	(Revision 15336)
+++ lib/lyx2lyx/LyX.py	(Arbeitskopie)
@@ -73,7 +73,7 @@ format_relation = [("0_06",    [200], ge
                    ("1_2",     [220], generate_minor_versions("1.2" , 4)),
                    ("1_3",     [221], generate_minor_versions("1.3" , 7)),
                    ("1_4", range(222,246), generate_minor_versions("1.4" , 3)),
-                   ("1_5", range(246,251), generate_minor_versions("1.5" , 0))]
+                   ("1_5", range(246,252), generate_minor_versions("1.5" , 0))]
 
 
 def formats_list():
Index: lib/lyx2lyx/lyx_1_5.py
===================================================================
--- lib/lyx2lyx/lyx_1_5.py	(Revision 15336)
+++ lib/lyx2lyx/lyx_1_5.py	(Arbeitskopie)
@@ -231,6 +231,193 @@ def revert_utf8(document):
     document.encoding = get_encoding(document.language, document.inputencoding, 248)
 
 
+def convert_bibitem(document):
+    """ Convert
+\bibitem [option]{argument}
+
+to
+
+\begin_inset LatexCommand bibitem
+label "option"
+key "argument"
+
+\end_inset
+
+This must be called after convert_commandparams.
+"""
+    regex = re.compile(r'\S+\s*(\[[^\[\{]*\])?(\{[^}]*\})')
+    i = 0
+    while 1:
+        i = find_token(document.body, "\\bibitem", i)
+        if i == -1:
+            break
+        match = re.match(regex, document.body[i])
+        option = match.group(1)
+        argument = match.group(2)
+        lines = ['\\begin_inset LatexCommand bibitem']
+	if not option == None:
+            lines.append('label "%s"' % option[1:-1].replace('"', '\\"'))
+        lines.append('key "%s"' % argument[1:-1].replace('"', '\\"'))
+        lines.append('')
+        lines.append('\\end_inset')
+        document.body[i:i+1] = lines
+        i = i + 1
+
+
+commandparams_info = {
+    # command : [option1, option2, argument]
+    "bibitem" : ["label", "", "key"],
+    "bibtex" : ["options", "btprint", "bibfiles"],
+    "cite"        : ["after", "",       "key"],
+    "citet"       : ["after", "before", "key"],
+    "citep"       : ["after", "before", "key"],
+    "citealt"     : ["after", "before", "key"],
+    "citealp"     : ["after", "before", "key"],
+    "citeauthor"  : ["after", "before", "key"],
+    "citeyear"    : ["after", "before", "key"],
+    "citeyearpar" : ["after", "before", "key"],
+    "citet*"      : ["after", "before", "key"],
+    "citep*"      : ["after", "before", "key"],
+    "citealt*"    : ["after", "before", "key"],
+    "citealp*"    : ["after", "before", "key"],
+    "citeauthor*" : ["after", "before", "key"],
+    "Citet"       : ["after", "before", "key"],
+    "Citep"       : ["after", "before", "key"],
+    "Citealt"     : ["after", "before", "key"],
+    "Citealp"     : ["after", "before", "key"],
+    "Citeauthor"  : ["after", "before", "key"],
+    "Citet*"      : ["after", "before", "key"],
+    "Citep*"      : ["after", "before", "key"],
+    "Citealt*"    : ["after", "before", "key"],
+    "Citealp*"    : ["after", "before", "key"],
+    "Citeauthor*" : ["after", "before", "key"],
+    "citefield"   : ["after", "before", "key"],
+    "citetitle"   : ["after", "before", "key"],
+    "cite*"       : ["after", "before", "key"],
+    "hfill" : ["", "", ""],
+    "index"      : ["", "", "name"],
+    "printindex" : ["", "", "name"],
+    "label" : ["", "", "name"],
+    "eqref"     : ["name", "", "reference"],
+    "pageref"   : ["name", "", "reference"],
+    "prettyref" : ["name", "", "reference"],
+    "ref"       : ["name", "", "reference"],
+    "vpageref"  : ["name", "", "reference"],
+    "vref"      : ["name", "", "reference"],
+    "tableofcontents" : ["", "", "type"],
+    "htmlurl" : ["name", "", "target"],
+    "url"     : ["name", "", "target"]}
+
+
+def convert_commandparams(document):
+    """ Convert
+
+ \begin_inset LatexCommand \cmdname[opt1][opt2]{arg}
+ \end_inset
+
+ to
+
+ \begin_inset LatexCommand cmdname
+ name1 "opt1"
+ name2 "opt2"
+ name3 "arg"
+ \end_inset
+
+ name1, name2 and name3 can be different for each command.
+"""
+    # \begin_inset LatexCommand bibitem was not the official version (see
+    # convert_bibitem()), but could be read in, so we convert it here, too.
+
+    # FIXME: Handle things like \command[foo[bar]]{foo{bar}}
+    # we need a real parser here.
+    regex = re.compile(r'\\([^\[\{]+)(\[[^\[\{]*\])?(\[[^\[\{]*\])?(\{[^}]*\})?')
+    i = 0
+    while 1:
+        i = find_token(document.body, "\\begin_inset LatexCommand", i)
+        if i == -1:
+            break
+        command = document.body[i][26:].strip()
+        match = re.match(regex, command)
+        name = match.group(1)
+        option1 = match.group(2)
+        option2 = match.group(3)
+        argument = match.group(4)
+        lines = ["\\begin_inset LatexCommand %s" % name]
+        if option1 != None:
+            if commandparams_info[name][0] == "":
+                document.warning("Ignoring invalid option `%s' of command `%s'." % (option1[1:-1], name))
+            else:
+                lines.append('%s "%s"' % (commandparams_info[name][0], option1[1:-1].replace('"', '\"')))
+        if option2 != None:
+            if commandparams_info[name][1] == "":
+                document.warning("Ignoring invalid second option `%s' of command `%s'." % (option2[1:-1], name))
+            else:
+                lines.append('%s "%s"' % (commandparams_info[name][1], option2[1:-1].replace('"', '\"')))
+        if argument != None:
+            if commandparams_info[name][2] == "":
+                document.warning("Ignoring invalid argument `%s' of command `%s'." % (argument[1:-1], name))
+            else:
+                lines.append('%s "%s"' % (commandparams_info[name][2], argument[1:-1].replace('"', '\"')))
+        document.body[i:i+1] = lines
+        i = i + 1
+
+
+def revert_commandparams(document):
+    regex = re.compile(r'(\S+)\s+(.+)')
+    i = 0
+    while 1:
+        i = find_token(document.body, "\\begin_inset LatexCommand", i)
+        if i == -1:
+            break
+        name = document.body[i].split()[2]
+        j = find_end_of_inset(document.body, i + 1)
+        preview_line = ""
+        option1 = ""
+        option2 = ""
+        argument = ""
+        for k in range(i + 1, j):
+            match = re.match(regex, document.body[k])
+            if match:
+                pname = match.group(1)
+                pvalue = match.group(2)
+                if pname == "preview":
+                    preview_line = document.body[k]
+                elif (commandparams_info[name][0] != "" and
+                      pname == commandparams_info[name][0]):
+                    option1 = pvalue.strip('"').replace('\\"', '"')
+                elif (commandparams_info[name][1] != "" and
+                      pname == commandparams_info[name][1]):
+                    option2 = pvalue.strip('"').replace('\\"', '"')
+                elif (commandparams_info[name][2] != "" and
+                      pname == commandparams_info[name][2]):
+                    argument = pvalue.strip('"').replace('\\"', '"')
+            elif document.body[k].strip() != "":
+                document.warning("Ignoring unknown contents `%s' in command inset %s." % (document.body[k], name))
+        if name == "bibitem":
+            if option1 == "":
+                lines = ["\\bibitem {%s}" % argument]
+            else:
+                lines = ["\\bibitem [%s]{%s}" % (option1, argument)]
+        else:
+            if option1 == "":
+                if option2 == "":
+                    lines = ["\\begin_inset LatexCommand \\%s{%s}" % (name, argument)]
+                else:
+                    lines = ["\\begin_inset LatexCommand \\%s[][%s]{%s}" % (name, option2, argument)]
+            else:
+                if option2 == "":
+                    lines = ["\\begin_inset LatexCommand \\%s[%s]{%s}" % (name, option1, argument)]
+                else:
+                    lines = ["\\begin_inset LatexCommand \\%s[%s][%s]{%s}" % (name, option1, option2, argument)]
+        if name != "bibitem":
+            if preview_line != "":
+                lines.append(preview_line)
+            lines.append('')
+            lines.append('\\end_inset')
+        document.body[i:j+1] = lines
+        i = j + 1
+
+
 ##
 # Conversion hub
 #
@@ -240,9 +427,11 @@ convert = [[246, []],
            [247, [convert_font_settings]],
            [248, []],
            [249, [convert_utf8]],
-           [250, []]]
+           [250, []],
+           [251, [convert_commandparams, convert_bibitem]]]
 
-revert =  [[249, []],
+revert =  [[250, [revert_commandparams]],
+           [249, []],
            [248, [revert_utf8]],
            [247, [revert_booktabs]],
            [246, [revert_font_settings]],
Index: development/FORMAT
===================================================================
--- development/FORMAT	(Revision 15336)
+++ development/FORMAT	(Arbeitskopie)
@@ -1,5 +1,33 @@
 LyX file-format changes
 -----------------------ยง
+
+2006-10-15  Georg Baum  <[EMAIL PROTECTED]>
+
+	* format incremented to 251: changed command inset syntax
+
+	Old:
+
+	\begin_inset LatexCommand \cmdname[opt1][opt2]{arg}
+	preview true
+	\end_inset
+
+	and
+
+	\bibitem [opt1]{arg}
+
+
+	New:
+
+	\begin_inset LatexCommand cmdname
+	name1 "opt1"
+	name2 "opt2"
+	name3 "arg"
+	preview true
+	\end_inset
+
+	The order of the parameters and for each parameter the name and
+	optional/required bit is now stored in InsetCommandParams.
+
 2006-10-12  Martin Vermeer <[EMAIL PROTECTED]>
 
 	* Format incremented to 250: allow optional arg to environments

Reply via email to