>> Allan Rae writes:

  >>  class PainterWriter : Writer { writeInsetUrl(<data args in
  >> inseturl>) { painter.drawButton(text text); } };
  >> 
  >> Think of a verbatim inset:
  >> 
  >> InsetVerbatim::write(Writer wri) {
  >> wri.writeInsetVerbatim(vector<verbatimvalidobjects> vec); }
  >> 
  >> LaTeXWriter::writeInsetVerbatim(vector<verbatimvalidobjects> vec)
  >> { filestr << "\\begin{verbatim}" << endl for (a = vec.begin(); a
  >> != vec.end(); ++a) { (*a).write(this);

  AR> What exactly is in a (*a)? I'd have thought it would be an

There is a declaration missing:

vector<verbatimvalidobjects>::iterator a;

  AR> LString but it looks like you are having other insets -- hmmm...
  AR> multiple paragraphs in a verbatim inset one insetparagraph each
  AR> perhaps?

  >> } filestr.endineol(); filestr << "\\end{verbatim}" << endl; }
  >> 
  >> Well I don't know anymore, but it seemed like nice idea when I
  >> was taking a shower. Especially since it hid all the hairy stuff.

  AR> Trying to come up with an alternate scheme is difficult. Below
  AR> is a scheme that tries to push the writers and insets to be more
  AR> independent. It does however introduce some complications for

I am not sure if I see this scheme separating writer and inset more. I
will claim that my solution using only public methods of the insets
separates them more.

  AR> the writers (and maybe maintenance difficulties later -- unless
  AR> we are careful in implementing the state machines). It all
  AR> involves making writers look like ostreams. I'll show you some
  AR> code (no warranty implied ;) :

  AR> class Writer { enum {command_start, command_end,
  AR> command_option_start, command_option_end,verbatim_start,
  AR> verbatim_end...} WriterStyles; Writer(LString const &);
  AR> //filename virtual Writer & operator<< (LString const &) = 0;
  AR> virtual Writer & operator<< (int const &) = 0; virtual Writer &
  AR> operator<< (WriterStyles const &) = 0; ... }

  AR> class LaTeXWriter : Writer { public: LaTeXWriter(LString const
  AR> &); // filename virtual Writer & operator<< (LString const &);
  AR> virtual Writer & operator<< (int const &); virtual Writer &
  AR> operator<< (WriterStyles const &); ... private:
  AR> auto_ptr<ostream> our_output_file; }

  AR> Writer & LaTeXWriter::operator<< (WriterStyles const & ws) {
  AR> static LWriterState state = default_state; switch (state) { case

this state thing is not something I care a lot for.

  AR> default_state: switch (ws) { case verbatim_start: state =
  AR> in_environment; *our_output_file << "\\begin{verbatim}"; // we
  AR> could get fancy and use a number of different // optimizations
  AR> such as: // enviro_name = "verbatim"; // and then catching all
  AR> environment ends and // only having one output statement. break;
  AR> case *_end: // error no _end's allowed in default_state ...
  AR> break; ... } case in_environment: switch (ws) { case
  AR> verbatim_end: state = default_state; *our_output_file <<
  AR> "\\end{verbatim}" << endl; // another thing we'd probably do is
  AR> to do our // initial output to an LString buffer like we do //
  AR> now so we can look backwards in the output // and break long
  AR> lines or add/remove '\n'. break; ... } ... } return *this; }

  AR> class InsetVerbatim : Inset { virtual write(Writer &) const; ...
  AR> }

  AR> Writer & InsetVerbatim::write(Writer & wr) const { return wr <<
  AR> WriterStyles::verbatim_start << contents <<
  AR> WriterStyles::verbatim_end; }

So for every kind of environment we will need a *_start and *_end ?

  AR> Of course it'd be nice to be able to write: LaTeXWriter
  AR> lwr("somefile.tex") << preamble_and_stuff(); //
  AR> preamble_and_stuff() could actually be in an // InsetPreamble or
  AR> something similar. for (document_structure::const_iterator iter
  AR> = buffer.begin(); iter != buffer.end(); ++iter) { lwr <<
  AR> (*iter); } lwr << closing_of_document();
        
Buffer.write(Writer*w);

Sounds nice.

  AR> where (*iter) is effectively any inset. So we therefore need to
  AR> add:

  AR> Writer & operator<< (Writer & wr, InsetVerbatim const & iv) {
  AR> return iv.write(wr); }

  AR> and likewise for all the other different insets *or* I think the
  AR> following will work:

  AR> Writer & operator<< (Writer & wr, Inset const & inset) { return
  AR> inset.write(wr); }

inset.write(this); 

Hmm, unless you write this a non-members of course.

and drop one of the paramterters.

  AR> Thus giving us a double-dispatch but if we inline this one it
  AR> shouldn't cost much in time or space.

  AR> The scheme above makes the writers look somewhat uglier than
  AR> Lars scheme does but it should also be a bit more independent of
  AR> the insets. The hardest part is going to be the state machines
  AR> in each of the writers WriterStyles handlers. For example:

  AR> class PainterWriter : Writer { public: PainterWriter(Painter &);
  AR> virtual Writer & operator<< (LString const &); virtual Writer &
  AR> operator<< (int const &); virtual Writer & operator<<
  AR> (WriterStyles const &); ... private: enum {default_state,
  AR> in_button, ...} PWriterState; }
        
  AR> Writer & PainterWriter::operator<< (WriterStyles & ws) { static
  AR> PWriterState state = default_state; // we shouldn't need to know
  AR> the current state in any of // the other overloaded operator<<
  AR> but if we do we'll // need to make state into a member function
  AR> with a local // static PWriterState. Note that it *wouldn't* be
  AR> a // static member function. switch (state) { case in_button: //
  AR> everything until the next WriterStyle::*_end // will be in a
  AR> button -- of course there is an // implicit assumption here that
  AR> we can't have // buttons within buttons. switch (ws) { case
  AR> ref_end: case url_end: case label_end: painter.drawButton(data);
  AR> // where data is a variable that we filled // with incoming data
  AR> while waiting for // an *_end. state = default_state; } break;
  AR> ... } }

  AR> Unfortunately whatever we come up with is going to have some
  AR> ugly bits or hairy stuff. The best thing about this scheme is

Let's try to hide those ugly parts far down in the implementation so
that new insets/writers will not see it.

  AR> that state machines are fairly easy to develop and are self
  AR> documenting. In fact we could use an external tool to maintain
  AR> the state machine design and generate skeleton code.

  AR> The third option which I'm still inclined to prefer (for its
  AR> simplicity) is to have each Inset provide writer specific

Then I would claim that my method is not more complex, with the added
benefit of a simpler inset.

  AR> methods. Such a scheme wouldn't make it any harder for the
  AR> writer to keep a check of the output (to break lines at
  AR> appropriate points or insert extra spaces etc.). It would also
  AR> be possible to use an ostream syntax for the writers. Let's call
  AR> this Option3.

But this is excatly what we want to avoid.

  AR> Now to analyse some other considerations: Adding a new inset:
  AR> Lars' scheme: each writer needs a new writeInsetXXX hence a
  AR> change to writer.h and a recompile of everything

Who cares about recompilation?

  AR> Difficulties:
  AR> how to reuse common areas of code?

Note that I have said nothing about how the writing will actually be
done. Look at Asgers proposal, a lot of reuse of code there. However
he tries to abstract all writing, and I don't think that is easily
feasible or maintainable.

  AR> Allan's scheme: Probably add
  AR> new WriterStyles (and support for them) Probably recompile
  AR> everything. Difficulties: maybe an extra state in state machines
  AR> Option3: implement new inset compile only new inset (assumes we
  AR> don't need to implement any extra support in writers -- if we do
  AR> we'll end up recompiling everything.)

  AR> Adding a new writer: Allan's scheme: Lars' scheme: implement new
  AR> writer class compile only new writer class Difficulties: Lars'
  AR> scheme - each writeInset... Allan's scheme - each
  AR> <<(WriterStyles) since the other << methods are much simpler.
  AR> Option3: as above and add new methods for each and every inset.
  AR> Then recompile everything. Difficulties: each new writer
  AR> specific method.

I don't like this part of option 3.

  AR> How often do we add new writers? (If we start with ASCII, LaTeX,

Rather seldom.

  AR> SGMLDocBook and HTML4_0 would we need any others? (XML?) man
  AR> pages and a number of other things can be generated by SGMLTools
  AR> (either now or in the future) How often do we add new insets?

Pretty often.

  AR> (I'd say more often than new writers) Can any of these schemes
  AR> support generic writers or insets? (eg. embedding other
  AR> applications in an InsetExternApp)

I don't think this has much to do with writing.
(the external prog must provide latex or ps (or a another format that
the writers can use))

The only way we can make this happen is if we can find a way to
abstract the the inset writing. Hmm, when I think about it, my scheme
could almost make dynamic loadable writer modules work... How to make
dynamic loading of insets work?

  AR> Other comments: I like the iostream appearance of my scheme with
  AR> the overloaded operator<<. Unfortunately, I doubt we could
  AR> modify Lars' scheme to use overloaded operator<< unless we
  AR> changed it to being overloaded on inset types. I think my scheme
  AR> needs something better than the WriterStyles enum to configure
  AR> the Writer stream. Maybe something similar to the ostream
  AR> manipulators (setw() and the like).

Inset**::operator<<(Writer*w) { w.writeInset**();}

 
Or do you want a

Writer::operator<<(Inset*I) {
        i.write(this);
}

??

        Lgb

Reply via email to