]> git.lyx.org Git - lyx.git/blobdiff - src/paragraph_funcs.C
fix some C++ parsing bugs
[lyx.git] / src / paragraph_funcs.C
index a7b5c4546b7fab1326517057326eded97333d029..36b4cc0337b66165ea4dd83e25a431ad52aeb08b 100644 (file)
 #include "ParagraphParameters.h"
 #include "lyxtextclasslist.h"
 #include "debug.h"
+#include "gettext.h"
 #include "language.h"
 #include "encoding.h"
 #include "lyxrc.h"
+#include "lyxlex.h"
+#include "BoostFormat.h"
+#include "factory.h"
 #include "support/lstrings.h"
 #include "insets/insetoptarg.h"
+#include "insets/insetcommandparams.h"
+#include "insets/insetbibitem.h"
+#include "insets/insetspecialchar.h"
+#include "insets/insetlatexaccent.h"
+#include "insets/insettabular.h"
+#include "insets/insethfill.h"
+#include "insets/inseterror.h"
+#include "insets/insetnewline.h"
 
 extern string bibitemWidest(Buffer const *);
 
@@ -250,9 +262,24 @@ int getEndLabel(Paragraph * para, BufferParams const & bparams)
 #endif
 
 
+namespace {
+
+ParagraphList::iterator
+TeXEnvironment(Buffer const * buf,
+              ParagraphList const & paragraphs,
+              ParagraphList::iterator pit,
+              ostream & os, TexRow & texrow);
+
+ParagraphList::iterator
+TeXOnePar(Buffer const * buf,
+         ParagraphList const & paragraphs,
+         ParagraphList::iterator pit,
+         ostream & os, TexRow & texrow,
+         bool moving_arg);
+
+
 ParagraphList::iterator
 TeXDeeper(Buffer const * buf,
-         BufferParams const & bparams,
          ParagraphList const & paragraphs,
          ParagraphList::iterator pit,
          ostream & os, TexRow & texrow)
@@ -262,10 +289,10 @@ TeXDeeper(Buffer const * buf,
 
        while (par != paragraphs.end()&& par->params().depth() == pit->params().depth()) {
                if (par->layout()->isEnvironment()) {
-                       par = TeXEnvironment(buf, bparams, paragraphs, par,
+                       par = TeXEnvironment(buf, paragraphs, par,
                                                  os, texrow);
                } else {
-                       par = TeXOnePar(buf, bparams, paragraphs, par,
+                       par = TeXOnePar(buf, paragraphs, par,
                                             os, texrow, false);
                }
        }
@@ -277,13 +304,14 @@ TeXDeeper(Buffer const * buf,
 
 ParagraphList::iterator
 TeXEnvironment(Buffer const * buf,
-              BufferParams const & bparams,
               ParagraphList const & paragraphs,
               ParagraphList::iterator pit,
               ostream & os, TexRow & texrow)
 {
        lyxerr[Debug::LATEX] << "TeXEnvironment...     " << &*pit << endl;
 
+       BufferParams const & bparams = buf->params;
+
        LyXLayout_ptr const & style = pit->layout();
 
        Language const * language = pit->getParLanguage(bparams);
@@ -338,7 +366,7 @@ TeXEnvironment(Buffer const * buf,
        }
        ParagraphList::iterator par = pit;
        do {
-               par = TeXOnePar(buf, bparams, paragraphs, par, os, texrow, false);
+               par = TeXOnePar(buf, paragraphs, par, os, texrow, false);
 
                if (par != paragraphs.end()&& par->params().depth() > pit->params().depth()) {
                            if (par->layout()->isParagraph()) {
@@ -360,7 +388,7 @@ TeXEnvironment(Buffer const * buf,
                                os << '\n';
                                texrow.newline();
                        }
-                       par = TeXDeeper(buf, bparams, paragraphs, par, os, texrow);
+                       par = TeXDeeper(buf, paragraphs, par, os, texrow);
                }
        } while (par != paragraphs.end()
                 && par->layout() == pit->layout()
@@ -382,8 +410,6 @@ TeXEnvironment(Buffer const * buf,
 }
 
 
-namespace {
-
 InsetOptArg * optArgInset(Paragraph const & par)
 {
        // Find the entry.
@@ -398,18 +424,17 @@ InsetOptArg * optArgInset(Paragraph const & par)
        return 0;
 }
 
-} // end namespace
-
 
 ParagraphList::iterator
 TeXOnePar(Buffer const * buf,
-         BufferParams const & bparams,
          ParagraphList const & paragraphs,
          ParagraphList::iterator pit,
          ostream & os, TexRow & texrow,
          bool moving_arg)
 {
        lyxerr[Debug::LATEX] << "TeXOnePar...     " << &*pit << endl;
+       BufferParams const & bparams = buf->params;
+
        Inset const * in = pit->inInset();
        bool further_blank_line = false;
        LyXLayout_ptr style;
@@ -636,6 +661,8 @@ TeXOnePar(Buffer const * buf,
        return ++pit;
 }
 
+} // anon namespace
+
 
 //
 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
@@ -693,12 +720,12 @@ void latexParagraphs(Buffer const * buf,
                        if (layout->isEnvironment() ||
                                !par->params().leftIndent().zero())
                        {
-                               par = TeXEnvironment(buf, buf->params, paragraphs, par, ofs, texrow);
+                               par = TeXEnvironment(buf, paragraphs, par, ofs, texrow);
                        } else {
-                               par = TeXOnePar(buf, buf->params, paragraphs, par, ofs, texrow, moving_arg);
+                               par = TeXOnePar(buf, paragraphs, par, ofs, texrow, moving_arg);
                        }
                } else {
-                       par = TeXOnePar(buf, buf->params, paragraphs, par, ofs, texrow, moving_arg);
+                       par = TeXOnePar(buf, paragraphs, par, ofs, texrow, moving_arg);
                }
        }
        // It might be that we only have a title in this document
@@ -714,3 +741,286 @@ void latexParagraphs(Buffer const * buf,
                texrow.newline();
        }
 }
+
+
+namespace {
+
+int readParToken(Buffer & buf, Paragraph & par, LyXLex & lex, string const & token)
+{
+       static LyXFont font;
+       static Change change;
+
+       BufferParams const & bp = buf.params;
+
+       if (token[0] != '\\') {
+               string::const_iterator cit = token.begin();
+               for (; cit != token.end(); ++cit) {
+                       par.insertChar(par.size(), (*cit), font, change);
+               }
+       } else if (token == "\\layout") {
+               lex.eatLine();
+               string layoutname = lex.getString();
+
+               font = LyXFont(LyXFont::ALL_INHERIT, bp.language);
+               change = Change();
+
+               LyXTextClass const & tclass = bp.getLyXTextClass();
+
+               if (layoutname.empty()) {
+                       layoutname = tclass.defaultLayoutName();
+               }
+
+               bool hasLayout = tclass.hasLayout(layoutname);
+
+               if (!hasLayout) {
+                       lyxerr << "Layout '" << layoutname << "' does not"
+                              << " exist in textclass '" << tclass.name()
+                              << "'." << endl;
+                       lyxerr << "Trying to use default layout instead."
+                              << endl;
+                       layoutname = tclass.defaultLayoutName();
+               }
+
+#ifdef USE_CAPTION
+               // The is the compability reading of layout caption.
+               if (compare_ascii_no_case(layoutname, "caption") == 0) {
+                       // We expect that the par we are now working on is
+                       // really inside a InsetText inside a InsetFloat.
+                       // We also know that captions can only be
+                       // one paragraph. (Lgb)
+
+                       // We should now read until the next "\layout"
+                       // is reached.
+                       // This is probably not good enough, what if the
+                       // caption is the last par in the document (Lgb)
+                       istream & ist = lex.getStream();
+                       stringstream ss;
+                       string line;
+                       int begin = 0;
+                       while (true) {
+                               getline(ist, line);
+                               if (prefixIs(line, "\\layout")) {
+                                       lex.pushToken(line);
+                                       break;
+                               }
+                               if (prefixIs(line, "\\begin_inset"))
+                                       ++begin;
+                               if (prefixIs(line, "\\end_inset")) {
+                                       if (begin)
+                                               --begin;
+                                       else {
+                                               lex.pushToken(line);
+                                               break;
+                                       }
+                               }
+
+                               ss << line << '\n';
+                       }
+
+                       // Now we should have the whole layout in ss
+                       // we should now be able to give this to the
+                       // caption inset.
+                       ss << "\\end_inset\n";
+
+                       // This seems like a bug in stringstream.
+                       // We really should be able to use ss
+                       // directly. (Lgb)
+                       istringstream is(ss.str());
+                       LyXLex tmplex(0, 0);
+                       tmplex.setStream(is);
+                       Inset * inset = new InsetCaption;
+                       inset->Read(this, tmplex);
+                       par.insertInset(pos, inset, font);
+                       ++pos;
+               } else {
+#endif
+                       par.layout(bp.getLyXTextClass()[layoutname]);
+
+                       // Test whether the layout is obsolete.
+                       LyXLayout_ptr const & layout = par.layout();
+                       if (!layout->obsoleted_by().empty())
+                               par.layout(bp.getLyXTextClass()[layout->obsoleted_by()]);
+
+                       par.params().read(lex);
+#if USE_CAPTION
+               }
+#endif
+
+       } else if (token == "\\end_inset") {
+               lyxerr << "Solitary \\end_inset in line " << lex.getLineNo() << "\n"
+                      << "Missing \\begin_inset?.\n";
+               // Simply ignore this. The insets do not have
+               // to read this.
+               // But insets should read it, it is a part of
+               // the inset isn't it? Lgb.
+       } else if (token == "\\begin_inset") {
+               Inset * i = readInset(lex, buf);
+               par.insertInset(par.size(), i, font, change);
+       } else if (token == "\\family") {
+               lex.next();
+               font.setLyXFamily(lex.getString());
+       } else if (token == "\\series") {
+               lex.next();
+               font.setLyXSeries(lex.getString());
+       } else if (token == "\\shape") {
+               lex.next();
+               font.setLyXShape(lex.getString());
+       } else if (token == "\\size") {
+               lex.next();
+               font.setLyXSize(lex.getString());
+       } else if (token == "\\lang") {
+               lex.next();
+               string const tok = lex.getString();
+               Language const * lang = languages.getLanguage(tok);
+               if (lang) {
+                       font.setLanguage(lang);
+               } else {
+                       font.setLanguage(bp.language);
+                       lex.printError("Unknown language `$$Token'");
+               }
+       } else if (token == "\\numeric") {
+               lex.next();
+               font.setNumber(font.setLyXMisc(lex.getString()));
+       } else if (token == "\\emph") {
+               lex.next();
+               font.setEmph(font.setLyXMisc(lex.getString()));
+       } else if (token == "\\bar") {
+               lex.next();
+               string const tok = lex.getString();
+
+               if (tok == "under")
+                       font.setUnderbar(LyXFont::ON);
+               else if (tok == "no")
+                       font.setUnderbar(LyXFont::OFF);
+               else if (tok == "default")
+                       font.setUnderbar(LyXFont::INHERIT);
+               else
+                       lex.printError("Unknown bar font flag "
+                                      "`$$Token'");
+       } else if (token == "\\noun") {
+               lex.next();
+               font.setNoun(font.setLyXMisc(lex.getString()));
+       } else if (token == "\\color") {
+               lex.next();
+               font.setLyXColor(lex.getString());
+       } else if (token == "\\SpecialChar") {
+               LyXLayout_ptr const & layout = par.layout();
+
+               // Insets don't make sense in a free-spacing context! ---Kayvan
+               if (layout->free_spacing || par.isFreeSpacing()) {
+                       if (lex.isOK()) {
+                               lex.next();
+                               string const next_token = lex.getString();
+                               if (next_token == "\\-") {
+                                       par.insertChar(par.size(), '-', font, change);
+                               } else if (next_token == "~") {
+                                       par.insertChar(par.size(), ' ', font, change);
+                               } else {
+                                       lex.printError("Token `$$Token' "
+                                                      "is in free space "
+                                                      "paragraph layout!");
+                               }
+                       }
+               } else {
+                       Inset * inset = new InsetSpecialChar;
+                       inset->read(&buf, lex);
+                       par.insertInset(par.size(), inset, font, change);
+               }
+       } else if (token == "\\i") {
+               Inset * inset = new InsetLatexAccent;
+               inset->read(&buf, lex);
+               par.insertInset(par.size(), inset, font, change);
+       } else if (token == "\\backslash") {
+               par.insertChar(par.size(), '\\', font, change);
+       } else if (token == "\\newline") {
+               Inset * inset = new InsetNewline;
+               inset->read(&buf, lex);
+               par.insertInset(par.size(), inset, font, change);
+       } else if (token == "\\LyXTable") {
+               Inset * inset = new InsetTabular(buf);
+               inset->read(&buf, lex);
+               par.insertInset(par.size(), inset, font, change);
+       } else if (token == "\\bibitem") {
+               InsetCommandParams p("bibitem", "dummy");
+               InsetBibitem * inset = new InsetBibitem(p);
+               inset->read(&buf, lex);
+               par.insertInset(par.size(), inset, font, change);
+       } else if (token == "\\hfill") {
+               par.insertInset(par.size(), new InsetHFill(), font, change);
+       } else if (token == "\\change_unchanged") {
+               // Hack ! Needed for empty paragraphs :/
+               // FIXME: is it still ??
+               if (!par.size())
+                       par.cleanChanges();
+               change = Change(Change::UNCHANGED);
+       } else if (token == "\\change_inserted") {
+               lex.nextToken();
+               istringstream istr(lex.getString());
+               int aid;
+               lyx::time_type ct;
+               istr >> aid;
+               istr >> ct;
+               change = Change(Change::INSERTED, bp.author_map[aid], ct);
+       } else if (token == "\\change_deleted") {
+               lex.nextToken();
+               istringstream istr(lex.getString());
+               int aid;
+               lyx::time_type ct;
+               istr >> aid;
+               istr >> ct;
+               change = Change(Change::DELETED, bp.author_map[aid], ct);
+       } else {
+               lex.eatLine();
+#if USE_BOOST_FORMAT
+               boost::format fmt(_("Unknown token: %1$s %2$s\n"));
+               fmt % token % lex.text();
+               string const s = fmt.str();
+#else
+               string const s = _("Unknown token: ") + token
+                       + ' ' + lex.text() + '\n';
+#endif
+               // we can do this here this way because we're actually reading
+               // the buffer and don't care about LyXText right now.
+               InsetError * inset = new InsetError(s);
+               par.insertInset(par.size(), inset, font);
+               return 1;
+       }
+       return 0;
+}
+
+}
+
+
+int readParagraph(Buffer & buf, Paragraph & par, LyXLex & lex)
+{
+       int unknown = 0;
+
+       lex.nextToken();
+       string token = lex.getString();
+
+       while (lex.isOK()) {
+
+               unknown += readParToken(buf, par, lex, token);
+
+               lex.nextToken();
+               token = lex.getString();
+
+               if (token.empty())
+                       continue;
+
+               lyxerr[Debug::PARSER] << "Handling paragraph token: `"
+                                     << token << '\'' << endl;
+
+               // reached the next paragraph. FIXME: really we should
+               // change the file format to indicate the end of a par
+               // clearly, but for now, this hack will do
+               if (token == "\\layout" || token == "\\the_end"
+                   || token == "\\end_inset" || token == "\\begin_deeper"
+                   || token == "\\end_deeper") {
+                       lex.pushToken(token);
+                       break;
+               }
+       }
+
+       return unknown;
+}