Andre Poenitz wrote: > Have you considered changing that params2string interface to ... > (or when we are at it even > > ostream & InsetBranchMailer::operator<<(ostream & os, > InsetBranchParams const &) > { > os << name << ' '; > os << name_ << ' '; > params.write(os); > // Add all_branches parameter to data: > os << params.branchlist.allBranches() << "\n"; > return os; > } > > one concept less to grasp and even better re-usable...)
Let's think about this a little more, and let's illustrate this with examples of the code in use in the core. 1. Example usage of params2string, in LyXFunc::dispatch: case LFUN_DIALOG_SHOW_NEW_INSET: { string const name = func.getArg(0); string data = trim(func.argument.substr(name.size())); if (name == "foo") { ... } else if (name == "box") { // \c data == "Boxed" || "Frameless" etc InsetBoxParams p(data); data = InsetBoxMailer::params2string(p); } owner->getDialogs().show(name, data, 0); break; } 2. Example usage of string2params, in factory.C's createInset: case LFUN_INSET_INSERT: { string const name = cmd.getArg(0); if (name == "bibitem") { InsetCommandParams icp; InsetCommandMailer::string2params(cmd.argument, icp); return new InsetBibitem(icp); } else ... In (1) I am turning an 'empty' InsetBoxParams into a string that can be 'mailed' to the dialog. Ie, it contains all the default values needed to initialze the dialog. In (2) I am using the string passed to dispatch from the frontend to fill an instance of InsetCommandParams. So, is the code that USES these interfaces ugly? I don't think it is. Nonetheless, let's proceed and consider whether we could use a stream-based interface rather than the current string-based one. The first point to note is that the two functions params2string and string2params are STATIC. Ie, really they are independent of the concept of the Mailer which handles communication from the core to the dialogs. If we want to use operator>>() syntax then I think that we new classes to do so: struct InsetCommandStreamer { // Note that these constructors must be passed \c name // because many InsetCommand-derived insets will use this. // InsetBoxStreamer would not need a \c name argument // to be passed to the constructors. // Use this constructor when filling \c params from // a std::istream. InsetCommandStreamer(string const & name_) : name(name_) {} // Use this constructor when filling a std::ostream // from params. InsetCommandStreamer(string const & name_, InsetCommandParams const & params_) : name(name_), params(params_) {} string const name; InsetCommandParams params; }; std::ostream & operator<<(std::ostream & os, InsetCommandStreamer const & ics) { os << ics.name << ' '; ics.params.write(os); os << "\\end_inset\n"; return os; } std::istream & operator>>(std::istream & is, InsetCommandStreamer & ics) { ics.params = InsetCommandParams(); string name; is >> name; if (!is || name != ics.name) { lyxerr << "Bogus data" << std::endl; return is; } // This is part of the inset proper that is usually swallowed // by LyXText::readInset string id; is >> id; if (!is || id != "LatexCommand") { lyxerr << "Bogus data" << std::endl; return is; } // Inset::read takes a LyXLex, not an istream LyXLex lex(0,0); lex.setStream(is); ics.params.read(lex); return is; } So, the implementation code is quite neat (but little more so than it would be if I used your new interface to LyXLex). How about the code that would use this? 1. Replacement for params2string. Assume that Dialogs::show's second arument is now 'ostream &' rather than 'string const &' case LFUN_DIALOG_SHOW_NEW_INSET: { string const name = func.getArg(0); string data = trim(func.argument.substr(name.size())); ostringstream ss; if (name == "foo") { ... } else if (name == "box") { // \c data == "Boxed" || "Frameless" etc ss << InsetBoxStreamer(InsetBoxParams(data)); } owner->getDialogs().show(name, ss, 0); break; } 2. Replacement for string2params. case LFUN_INSET_INSERT: { string const name = cmd.getArg(0); if (name == "bibitem") { istringstream is(cmd.argument); InsetCommandStreamer ics(name); is >> ics; return new InsetBibitem(ics.params); } else ... Is this demonstrably better than the interface above? I don't think that there's much in it actually. My personal conclusion is that the present interface is sufficient, but I'm willing to hear your arguments too. -- Angus