LyX file-format changes
-----------------------§
+2006-10-15 Georg Baum <Georg.Baum@post.rwth-aachen.de>
+
+ * format incremented to 252: 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-03 Jürgen Spitzmüller <j.spitzmueller@gmx.de>
* format incremented to 251: save show_label param for charstyles.
("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,252), generate_minor_versions("1.5" , 0))]
+ ("1_5", range(246,253), generate_minor_versions("1.5" , 0))]
def formats_list():
i = i + 1
+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", "before", "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
#
[248, []],
[249, [convert_utf8]],
[250, []],
- [251, []]]
+ [251, []],
+ [252, [convert_commandparams, convert_bibitem]]]
-revert = [[250, [revert_cs_label]],
+revert = [[251, [revert_commandparams]],
+ [250, [revert_cs_label]],
[249, []],
[248, [revert_utf8]],
[247, [revert_booktabs]],
src/frontends/qt4/QBranches.C
src/frontends/qt4/QChanges.C
src/frontends/qt4/QCharacter.C
+src/frontends/qt4/QCitationDialog.C
src/frontends/qt4/QCommandBuffer.C
src/frontends/qt4/QDelimiterDialog.C
src/frontends/qt4/QDocument.C
src/frontends/qt4/QTabularCreate.C
src/frontends/qt4/QTexinfo.C
src/frontends/qt4/QThesaurus.C
+src/frontends/qt4/QTocDialog.C
src/frontends/qt4/QVSpace.C
src/frontends/qt4/QWrap.C
src/frontends/qt4/Qt2BC.h
namespace {
-int const LYX_FORMAT = 251;
+int const LYX_FORMAT = 252;
} // namespace anon
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);
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);
// 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.
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));
ControlBibtex::ControlBibtex(Dialog & d)
- : ControlCommand(d, "bibtex")
+ : ControlCommand(d, "bibtex", "bibtex")
{}
ControlCitation::ControlCitation(Dialog & d)
- : ControlCommand(d, "citation")
+ : ControlCommand(d, "cite", "citation")
{}
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)
{}
void ControlCommand::clearParams()
{
- params_ = InsetCommandParams();
+ params_.clear();
}
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_; }
///
namespace frontend {
ControlInclude::ControlInclude(Dialog & parent)
- : Dialog::Controller(parent)
+ : Dialog::Controller(parent), params_("include")
{}
void ControlInclude::clearParams()
{
- params_ = InsetCommandParams();
+ params_.clear();
}
namespace frontend {
ControlRef::ControlRef(Dialog & d)
- : ControlCommand(d, "ref")
+ : ControlCommand(d, "ref", "ref")
{}
ControlToc::ControlToc(Dialog & d)
- : ControlCommand(d, "toc")
+ : ControlCommand(d, "tableofcontents", "toc")
{}
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") {
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")),
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")),
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") {
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") {
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:")));
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") {
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") {
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:")));
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") {
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();
}
-// 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
+void InsetBibitem::read(Buffer const & buf, LyXLex & lex)
{
- 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'");
+ InsetCommand::read(buf, lex);
if (prefixIs(getContents(), key_prefix)) {
int const key = convert<int>(getContents().substr(key_prefix.length()));
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);
///
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);
///
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);
class Cache {
public:
///
- Cache() : engine(lyx::biblio::ENGINE_BASIC) {}
+ Cache() : engine(lyx::biblio::ENGINE_BASIC), params("cite") {}
///
lyx::biblio::CiteEngine engine;
///
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)
{}
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();
string const & in,
InsetCommandParams & params)
{
- params = InsetCommandParams();
+ params.clear();
if (in.empty())
return;
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 &,
///
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_; }
* Licence details can be found in the file COPYING.
*
* \author Angus Leeming
+ * \author Georg Baum
*
* Full author contact details are available in file CREDITS.
*/
#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
+ // FIXME: Use is_possible_cite_command() in
+ // src/frontends/controllers/biblio.C, see comment in src/factory.C.
+ if (name == "cite" || 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*") {
+ // standard cite does only take one argument if jurabib is
+ // not used, but jurabib extends this to two arguments, so
+ // we have to allow both here. InsetCitation takes care that
+ // LaTeX output is nevertheless correct.
+ 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)
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. "
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." << endl;;
+ 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." << endl;;
+ 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." << endl;;
+}
+
+
+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." << endl;;
+}
+
+
+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_;
}
* Licence details can be found in the file COPYING.
*
* \author Angus Leeming
+ * \author Georg Baum
*
* Full author contact details are available in file CREDITS.
*/
#ifndef INSETCOMMANDPARAMS_H
#define INSETCOMMANDPARAMS_H
-#include <string>
+#include "support/docstring.h"
+
#include <iosfwd>
+#include <vector>
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 &);
};
InsetFloatList::InsetFloatList()
- : InsetCommand(InsetCommandParams(), "toc")
+ : InsetCommand(InsetCommandParams("floatlist"), "toc")
{}
InsetFloatList::InsetFloatList(string const & type)
- : InsetCommand(InsetCommandParams(), "toc")
+ : InsetCommand(InsetCommandParams("floatlist"), "toc")
{
setCmdName(type);
}
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());
void InsetIncludeMailer::string2params(string const & in,
InsetCommandParams & params)
{
- params = InsetCommandParams();
+ params.clear();
if (in.empty())
return;
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();
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;
}
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())
//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);
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") {
}
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()) {