2 * \file paragraph_funcs.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * Full author contact details are available in file CREDITS.
13 #include "paragraph_funcs.h"
16 #include "bufferparams.h"
20 #include "errorlist.h"
23 #include "iterators.h"
27 #include "paragraph_pimpl.h"
30 #include "insets/insetbibitem.h"
31 #include "insets/insethfill.h"
32 #include "insets/insetlatexaccent.h"
33 #include "insets/insetnewline.h"
34 #include "insets/insetoptarg.h"
35 #include "insets/insetspace.h"
36 #include "insets/insetspecialchar.h"
37 #include "insets/insettabular.h"
39 #include "support/LAssert.h"
40 #include "support/lstrings.h"
42 #include "support/std_sstream.h"
44 using namespace lyx::support;
47 //using lyx::layout_type;
49 using std::istringstream;
52 extern string bibitemWidest(Buffer const &);
57 bool moveItem(Paragraph & from, Paragraph & to,
58 BufferParams const & params, pos_type i, pos_type j)
60 char const tmpchar = from.getChar(i);
61 LyXFont tmpfont = from.getFontSettings(params, i);
63 if (tmpchar == Paragraph::META_INSET) {
64 InsetOld * tmpinset = 0;
65 if (from.getInset(i)) {
66 // the inset is not in a paragraph anymore
67 tmpinset = from.insetlist.release(i);
70 if (!to.insetAllowed(tmpinset->lyxCode()))
72 to.insertInset(j, tmpinset, tmpfont);
74 if (!to.checkInsertChar(tmpfont))
76 to.insertChar(j, tmpchar, tmpfont);
84 void breakParagraph(BufferParams const & bparams,
85 ParagraphList & paragraphs,
86 ParagraphList::iterator par,
90 // create a new paragraph, and insert into the list
91 ParagraphList::iterator tmp = paragraphs.insert(boost::next(par),
94 // without doing that we get a crash when typing <Return> at the
96 tmp->layout(bparams.getLyXTextClass().defaultLayout());
97 // remember to set the inset_owner
98 tmp->setInsetOwner(par->inInset());
100 if (bparams.tracking_changes)
103 // this is an idea for a more userfriendly layout handling, I will
104 // see what the users say
106 // layout stays the same with latex-environments
108 tmp->layout(par->layout());
109 tmp->setLabelWidthString(par->params().labelWidthString());
112 bool const isempty = (par->allowEmpty() && par->empty());
114 if (!isempty && (par->size() > pos || par->empty() || flag == 2)) {
115 tmp->layout(par->layout());
116 tmp->params().align(par->params().align());
117 tmp->setLabelWidthString(par->params().labelWidthString());
119 tmp->params().lineBottom(par->params().lineBottom());
120 par->params().lineBottom(false);
121 tmp->params().pagebreakBottom(par->params().pagebreakBottom());
122 par->params().pagebreakBottom(false);
123 tmp->params().spaceBottom(par->params().spaceBottom());
124 par->params().spaceBottom(VSpace(VSpace::NONE));
126 tmp->params().depth(par->params().depth());
127 tmp->params().noindent(par->params().noindent());
129 // copy everything behind the break-position
130 // to the new paragraph
133 #warning this seems wrong
135 /* FIXME: if !keepempty, empty() == true, then we reach
136 * here with size() == 0. So pos_end becomes - 1. Why
137 * doesn't this cause problems ???
139 pos_type pos_end = par->size() - 1;
143 for (; i <= pos_end; ++i) {
144 Change::Type change = par->lookupChange(i);
145 if (moveItem(*par, *tmp, bparams, i, j - pos)) {
146 tmp->setChange(j - pos, change);
151 for (i = pos_end; i >= pos; --i)
158 tmp->params().lineTop(par->params().lineTop());
159 tmp->params().pagebreakTop(par->params().pagebreakTop());
160 tmp->params().spaceTop(par->params().spaceTop());
161 par->params().clear();
163 par->layout(bparams.getLyXTextClass().defaultLayout());
165 // layout stays the same with latex-environments
167 par->layout(tmp->layout());
168 par->setLabelWidthString(tmp->params().labelWidthString());
169 par->params().depth(tmp->params().depth());
172 // subtle, but needed to get empty pars working right
173 if (bparams.tracking_changes) {
176 } else if (!tmp->size()) {
183 void breakParagraphConservative(BufferParams const & bparams,
184 ParagraphList & paragraphs,
185 ParagraphList::iterator par,
188 // create a new paragraph
189 ParagraphList::iterator tmp = paragraphs.insert(boost::next(par),
191 tmp->makeSameLayout(*par);
193 // When can pos > size()?
194 // I guess pos == size() is possible.
195 if (par->size() > pos) {
196 // copy everything behind the break-position to the new
198 pos_type pos_end = par->size() - 1;
200 for (pos_type i = pos, j = pos; i <= pos_end; ++i)
201 if (moveItem(*par, *tmp, bparams, i, j - pos))
204 for (pos_type k = pos_end; k >= pos; --k)
210 void mergeParagraph(BufferParams const & bparams,
211 ParagraphList & paragraphs,
212 ParagraphList::iterator par)
214 ParagraphList::iterator the_next = boost::next(par);
216 // first the DTP-stuff
217 par->params().lineBottom(the_next->params().lineBottom());
218 par->params().spaceBottom(the_next->params().spaceBottom());
219 par->params().pagebreakBottom(the_next->params().pagebreakBottom());
221 pos_type pos_end = the_next->size() - 1;
222 pos_type pos_insert = par->size();
224 // ok, now copy the paragraph
225 for (pos_type i = 0, j = 0; i <= pos_end; ++i)
226 if (moveItem(*the_next, *par, bparams, i, pos_insert + j))
229 paragraphs.erase(the_next);
233 ParagraphList::iterator depthHook(ParagraphList::iterator pit,
234 ParagraphList const & plist,
235 Paragraph::depth_type depth)
237 ParagraphList::iterator newpit = pit;
238 ParagraphList::iterator beg = const_cast<ParagraphList&>(plist).begin();
243 while (newpit != beg && newpit->getDepth() > depth) {
247 if (newpit->getDepth() > depth)
254 ParagraphList::iterator outerHook(ParagraphList::iterator pit,
255 ParagraphList const & plist)
257 if (!pit->getDepth())
258 return const_cast<ParagraphList&>(plist).end();
259 return depthHook(pit, plist,
260 Paragraph::depth_type(pit->getDepth() - 1));
264 bool isFirstInSequence(ParagraphList::iterator pit,
265 ParagraphList const & plist)
267 ParagraphList::iterator dhook = depthHook(pit, plist, pit->getDepth());
269 || dhook->layout() != pit->layout()
270 || dhook->getDepth() != pit->getDepth());
274 int getEndLabel(ParagraphList::iterator p, ParagraphList const & plist)
276 ParagraphList::iterator pit = p;
277 Paragraph::depth_type par_depth = p->getDepth();
278 while (pit != const_cast<ParagraphList&>(plist).end()) {
279 LyXLayout_ptr const & layout = pit->layout();
280 int const endlabeltype = layout->endlabeltype;
282 if (endlabeltype != END_LABEL_NO_LABEL) {
283 if (boost::next(p) == const_cast<ParagraphList&>(plist).end())
286 Paragraph::depth_type const next_depth = boost::next(p)->getDepth();
287 if (par_depth > next_depth ||
288 (par_depth == next_depth &&
289 layout != boost::next(p)->layout()))
295 pit = outerHook(pit, plist);
296 if (pit != const_cast<ParagraphList&>(plist).end())
297 par_depth = pit->getDepth();
299 return END_LABEL_NO_LABEL;
305 ParagraphList::iterator
306 TeXEnvironment(Buffer const & buf,
307 ParagraphList const & paragraphs,
308 ParagraphList::iterator pit,
309 ostream & os, TexRow & texrow,
310 LatexRunParams const & runparams);
312 ParagraphList::iterator
313 TeXOnePar(Buffer const & buf,
314 ParagraphList const & paragraphs,
315 ParagraphList::iterator pit,
316 ostream & os, TexRow & texrow,
317 LatexRunParams const & runparams,
318 string const & everypar = string());
321 ParagraphList::iterator
322 TeXDeeper(Buffer const & buf,
323 ParagraphList const & paragraphs,
324 ParagraphList::iterator pit,
325 ostream & os, TexRow & texrow,
326 LatexRunParams const & runparams)
328 lyxerr[Debug::LATEX] << "TeXDeeper... " << &*pit << endl;
329 ParagraphList::iterator par = pit;
331 while (par != const_cast<ParagraphList&>(paragraphs).end() &&
332 par->params().depth() == pit->params().depth()) {
333 if (par->layout()->isEnvironment()) {
334 par = TeXEnvironment(buf, paragraphs, par,
335 os, texrow, runparams);
337 par = TeXOnePar(buf, paragraphs, par,
338 os, texrow, runparams);
341 lyxerr[Debug::LATEX] << "TeXDeeper...done " << &*par << endl;
347 ParagraphList::iterator
348 TeXEnvironment(Buffer const & buf,
349 ParagraphList const & paragraphs,
350 ParagraphList::iterator pit,
351 ostream & os, TexRow & texrow,
352 LatexRunParams const & runparams)
354 lyxerr[Debug::LATEX] << "TeXEnvironment... " << &*pit << endl;
356 BufferParams const & bparams = buf.params();
358 LyXLayout_ptr const & style = pit->layout();
360 Language const * language = pit->getParLanguage(bparams);
361 Language const * doc_language = bparams.language;
362 Language const * previous_language =
363 (pit != const_cast<ParagraphList&>(paragraphs).begin())
364 ? boost::prior(pit)->getParLanguage(bparams)
366 if (language->babel() != previous_language->babel()) {
368 if (!lyxrc.language_command_end.empty() &&
369 previous_language->babel() != doc_language->babel()) {
370 os << subst(lyxrc.language_command_end, "$$lang",
371 previous_language->babel())
376 if (lyxrc.language_command_end.empty() ||
377 language->babel() != doc_language->babel()) {
378 os << subst(lyxrc.language_command_begin, "$$lang",
385 bool leftindent_open = false;
386 if (!pit->params().leftIndent().zero()) {
387 os << "\\begin{LyXParagraphLeftIndent}{" <<
388 pit->params().leftIndent().asLatexString() << "}\n";
390 leftindent_open = true;
393 if (style->isEnvironment()) {
394 if (style->latextype == LATEX_LIST_ENVIRONMENT) {
395 os << "\\begin{" << style->latexname() << "}{"
396 << pit->params().labelWidthString() << "}\n";
397 } else if (style->labeltype == LABEL_BIBLIO) {
399 os << "\\begin{" << style->latexname() << "}{"
400 << bibitemWidest(buf)
402 } else if (style->latextype == LATEX_ITEM_ENVIRONMENT) {
403 os << "\\begin{" << style->latexname() << '}'
404 << style->latexparam() << '\n';
406 os << "\\begin{" << style->latexname() << '}'
407 << style->latexparam() << '\n';
410 ParagraphList::iterator par = pit;
412 par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams);
414 if (par != const_cast<ParagraphList&>(paragraphs).end() && par->params().depth() > pit->params().depth()) {
415 if (par->layout()->isParagraph()) {
418 // How to handle this? (Lgb)
419 //&& !suffixIs(os, "\n\n")
421 // There should be at least one '\n' already
422 // but we need there to be two for Standard
423 // paragraphs that are depth-increment'ed to be
424 // output correctly. However, tables can
425 // also be paragraphs so don't adjust them.
428 // Will it ever harm to have one '\n' too
429 // many? i.e. that we sometimes will have
430 // three in a row. (Lgb)
434 par = TeXDeeper(buf, paragraphs, par, os, texrow,
437 } while (par != const_cast<ParagraphList&>(paragraphs).end()
438 && par->layout() == pit->layout()
439 && par->params().depth() == pit->params().depth()
440 && par->params().leftIndent() == pit->params().leftIndent());
442 if (style->isEnvironment()) {
443 os << "\\end{" << style->latexname() << "}\n";
447 if (leftindent_open) {
448 os << "\\end{LyXParagraphLeftIndent}\n";
452 lyxerr[Debug::LATEX] << "TeXEnvironment...done " << &*par << endl;
453 return par; // ale970302
457 InsetOptArg * optArgInset(Paragraph const & par)
460 InsetList::const_iterator it = par.insetlist.begin();
461 InsetList::const_iterator end = par.insetlist.end();
462 for (; it != end; ++it) {
463 InsetOld * ins = it->inset;
464 if (ins->lyxCode() == InsetOld::OPTARG_CODE) {
465 return static_cast<InsetOptArg *>(ins);
472 ParagraphList::iterator
473 TeXOnePar(Buffer const & buf,
474 ParagraphList const & paragraphs,
475 ParagraphList::iterator pit,
476 ostream & os, TexRow & texrow,
477 LatexRunParams const & runparams,
478 string const & everypar)
480 lyxerr[Debug::LATEX] << "TeXOnePar... " << &*pit << " '"
481 << everypar << "'" << endl;
482 BufferParams const & bparams = buf.params();
484 InsetOld const * in = pit->inInset();
485 bool further_blank_line = false;
488 // well we have to check if we are in an inset with unlimited
489 // length (all in one row) if that is true then we don't allow
490 // any special options in the paragraph and also we don't allow
491 // any environment other then "Standard" to be valid!
492 if (in == 0 || !in->forceDefaultParagraphs(in)) {
493 style = pit->layout();
495 if (pit->params().startOfAppendix()) {
496 os << "\\appendix\n";
500 if (!pit->params().spacing().isDefault()
501 && (pit == const_cast<ParagraphList&>(paragraphs).begin() || !boost::prior(pit)->hasSameLayout(*pit))) {
502 os << pit->params().spacing().writeEnvirBegin() << '\n';
506 if (style->isCommand()) {
511 if (pit->params().pagebreakTop()) {
513 further_blank_line = true;
515 if (pit->params().spaceTop().kind() != VSpace::NONE) {
516 os << pit->params().spaceTop().asLatexCommand(bparams);
517 further_blank_line = true;
520 if (pit->params().lineTop()) {
522 << pit->getFont(bparams, 0, outerFont(pit, paragraphs)).latexSize()
524 << "\\vspace{-1\\parskip}";
525 further_blank_line = true;
528 if (further_blank_line) {
533 style = bparams.getLyXTextClass().defaultLayout();
536 Language const * language = pit->getParLanguage(bparams);
537 Language const * doc_language = bparams.language;
538 Language const * previous_language =
539 (pit != const_cast<ParagraphList&>(paragraphs).begin())
540 ? boost::prior(pit)->getParLanguage(bparams)
543 if (language->babel() != previous_language->babel()
544 // check if we already put language command in TeXEnvironment()
545 && !(style->isEnvironment()
546 && (pit == const_cast<ParagraphList&>(paragraphs).begin() ||
547 (boost::prior(pit)->layout() != pit->layout() &&
548 boost::prior(pit)->getDepth() <= pit->getDepth())
549 || boost::prior(pit)->getDepth() < pit->getDepth())))
551 if (!lyxrc.language_command_end.empty() &&
552 previous_language->babel() != doc_language->babel())
554 os << subst(lyxrc.language_command_end, "$$lang",
555 previous_language->babel())
560 if (lyxrc.language_command_end.empty() ||
561 language->babel() != doc_language->babel())
563 os << subst(lyxrc.language_command_begin, "$$lang",
570 if (bparams.inputenc == "auto" &&
571 language->encoding() != previous_language->encoding()) {
572 os << "\\inputencoding{"
573 << language->encoding()->LatexName()
578 switch (style->latextype) {
580 os << '\\' << style->latexname();
582 // Separate handling of optional argument inset.
583 if (style->optionalargs == 1) {
584 InsetOptArg * it = optArgInset(*pit);
586 it->latexOptional(buf, os, runparams);
589 os << style->latexparam();
591 case LATEX_ITEM_ENVIRONMENT:
592 case LATEX_LIST_ENVIRONMENT:
595 case LATEX_BIB_ENVIRONMENT:
596 // ignore this, the inset will write itself
603 bool need_par = pit->simpleTeXOnePar(buf, bparams,
604 outerFont(pit, paragraphs),
605 os, texrow, runparams);
607 // Make sure that \\par is done with the font of the last
608 // character if this has another size as the default.
609 // This is necessary because LaTeX (and LyX on the screen)
610 // calculates the space between the baselines according
611 // to this font. (Matthias)
613 // Is this really needed ? (Dekel)
614 // We do not need to use to change the font for the last paragraph
616 LyXFont const outerfont(outerFont(pit, paragraphs));
620 ? pit->getLayoutFont(bparams, outerfont)
621 : pit->getFont(bparams, pit->size() - 1, outerfont));
623 bool is_command = style->isCommand();
625 if (style->resfont.size() != font.size()
626 && boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()
630 os << "\\" << font.latexSize() << " \\par}";
631 } else if (need_par) {
633 } else if (is_command)
636 switch (style->latextype) {
637 case LATEX_ITEM_ENVIRONMENT:
638 case LATEX_LIST_ENVIRONMENT:
639 if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()
640 && (pit->params().depth() < boost::next(pit)->params().depth())) {
645 case LATEX_ENVIRONMENT: {
646 // if its the last paragraph of the current environment
647 // skip it otherwise fall through
648 ParagraphList::iterator next = boost::next(pit);
650 if (next != const_cast<ParagraphList&>(paragraphs).end()
651 && (next->layout() != pit->layout()
652 || next->params().depth() != pit->params().depth()))
656 // fall through possible
658 // we don't need it for the last paragraph!!!
659 if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()) {
665 if (in == 0 || !in->forceDefaultParagraphs(in)) {
666 further_blank_line = false;
667 if (pit->params().lineBottom()) {
668 os << "\\lyxline{\\" << font.latexSize() << '}';
669 further_blank_line = true;
672 if (pit->params().spaceBottom().kind() != VSpace::NONE) {
673 os << pit->params().spaceBottom().asLatexCommand(bparams);
674 further_blank_line = true;
677 if (pit->params().pagebreakBottom()) {
679 further_blank_line = true;
682 if (further_blank_line) {
687 if (!pit->params().spacing().isDefault()
688 && (boost::next(pit) == const_cast<ParagraphList&>(paragraphs).end()|| !boost::next(pit)->hasSameLayout(*pit))) {
689 os << pit->params().spacing().writeEnvirEnd() << '\n';
694 // we don't need it for the last paragraph!!!
695 if (boost::next(pit) != const_cast<ParagraphList&>(paragraphs).end()) {
699 // Since \selectlanguage write the language to the aux file,
700 // we need to reset the language at the end of footnote or
703 if (language->babel() != doc_language->babel()) {
704 if (lyxrc.language_command_end.empty())
705 os << subst(lyxrc.language_command_begin,
707 doc_language->babel())
710 os << subst(lyxrc.language_command_end,
718 lyxerr[Debug::LATEX] << "TeXOnePar...done " << &*boost::next(pit) << endl;
726 // LaTeX all paragraphs from par to endpar, if endpar == 0 then to the end
728 void latexParagraphs(Buffer const & buf,
729 ParagraphList const & paragraphs,
732 LatexRunParams const & runparams,
733 string const & everypar)
735 bool was_title = false;
736 bool already_title = false;
737 LyXTextClass const & tclass = buf.params().getLyXTextClass();
738 ParagraphList::iterator par = const_cast<ParagraphList&>(paragraphs).begin();
739 ParagraphList::iterator endpar = const_cast<ParagraphList&>(paragraphs).end();
742 while (par != endpar) {
743 InsetOld * in = par->inInset();
744 // well we have to check if we are in an inset with unlimited
745 // length (all in one row) if that is true then we don't allow
746 // any special options in the paragraph and also we don't allow
747 // any environment other then "Standard" to be valid!
748 if (in == 0 || !in->forceDefaultParagraphs(in)) {
749 LyXLayout_ptr const & layout = par->layout();
751 if (layout->intitle) {
753 lyxerr <<"Error in latexParagraphs: You"
754 " should not mix title layouts"
755 " with normal ones." << endl;
756 } else if (!was_title) {
758 if (tclass.titletype() == TITLE_ENVIRONMENT) {
760 << tclass.titlename()
765 } else if (was_title && !already_title) {
766 if (tclass.titletype() == TITLE_ENVIRONMENT) {
767 os << "\\end{" << tclass.titlename()
771 os << "\\" << tclass.titlename()
775 already_title = true;
779 if (layout->is_environment) {
780 par = TeXOnePar(buf, paragraphs, par, os, texrow,
781 runparams, everypar);
782 } else if (layout->isEnvironment() ||
783 !par->params().leftIndent().zero())
785 par = TeXEnvironment(buf, paragraphs, par, os,
788 par = TeXOnePar(buf, paragraphs, par, os, texrow,
789 runparams, everypar);
792 par = TeXOnePar(buf, paragraphs, par, os, texrow,
793 runparams, everypar);
796 // It might be that we only have a title in this document
797 if (was_title && !already_title) {
798 if (tclass.titletype() == TITLE_ENVIRONMENT) {
799 os << "\\end{" << tclass.titlename()
803 os << "\\" << tclass.titlename()
813 int readParToken(Buffer & buf, Paragraph & par, LyXLex & lex, string const & token)
816 static Change change;
818 BufferParams const & bp = buf.params();
820 if (token[0] != '\\') {
821 string::const_iterator cit = token.begin();
822 for (; cit != token.end(); ++cit) {
823 par.insertChar(par.size(), (*cit), font, change);
825 } else if (token == "\\begin_layout") {
827 string layoutname = lex.getString();
829 font = LyXFont(LyXFont::ALL_INHERIT, bp.language);
832 LyXTextClass const & tclass = bp.getLyXTextClass();
834 if (layoutname.empty()) {
835 layoutname = tclass.defaultLayoutName();
838 bool hasLayout = tclass.hasLayout(layoutname);
841 lyxerr << "Layout '" << layoutname << "' does not"
842 << " exist in textclass '" << tclass.name()
844 lyxerr << "Trying to use default layout instead."
846 layoutname = tclass.defaultLayoutName();
849 par.layout(bp.getLyXTextClass()[layoutname]);
851 // Test whether the layout is obsolete.
852 LyXLayout_ptr const & layout = par.layout();
853 if (!layout->obsoleted_by().empty())
854 par.layout(bp.getLyXTextClass()[layout->obsoleted_by()]);
856 par.params().read(lex);
858 } else if (token == "\\end_layout") {
859 lyxerr << "Solitary \\end_layout in line " << lex.getLineNo() << "\n"
860 << "Missing \\begin_layout?.\n";
861 } else if (token == "\\end_inset") {
862 lyxerr << "Solitary \\end_inset in line " << lex.getLineNo() << "\n"
863 << "Missing \\begin_inset?.\n";
864 } else if (token == "\\begin_inset") {
865 InsetOld * inset = readInset(lex, buf);
866 par.insertInset(par.size(), inset, font, change);
867 } else if (token == "\\family") {
869 font.setLyXFamily(lex.getString());
870 } else if (token == "\\series") {
872 font.setLyXSeries(lex.getString());
873 } else if (token == "\\shape") {
875 font.setLyXShape(lex.getString());
876 } else if (token == "\\size") {
878 font.setLyXSize(lex.getString());
879 } else if (token == "\\lang") {
881 string const tok = lex.getString();
882 Language const * lang = languages.getLanguage(tok);
884 font.setLanguage(lang);
886 font.setLanguage(bp.language);
887 lex.printError("Unknown language `$$Token'");
889 } else if (token == "\\numeric") {
891 font.setNumber(font.setLyXMisc(lex.getString()));
892 } else if (token == "\\emph") {
894 font.setEmph(font.setLyXMisc(lex.getString()));
895 } else if (token == "\\bar") {
897 string const tok = lex.getString();
900 font.setUnderbar(LyXFont::ON);
901 else if (tok == "no")
902 font.setUnderbar(LyXFont::OFF);
903 else if (tok == "default")
904 font.setUnderbar(LyXFont::INHERIT);
906 lex.printError("Unknown bar font flag "
908 } else if (token == "\\noun") {
910 font.setNoun(font.setLyXMisc(lex.getString()));
911 } else if (token == "\\color") {
913 font.setLyXColor(lex.getString());
914 } else if (token == "\\InsetSpace" || token == "\\SpecialChar") {
916 // Insets don't make sense in a free-spacing context! ---Kayvan
917 if (par.isFreeSpacing()) {
918 if (token == "\\InsetSpace")
919 par.insertChar(par.size(), ' ', font, change);
920 else if (lex.isOK()) {
922 string const next_token = lex.getString();
923 if (next_token == "\\-")
924 par.insertChar(par.size(), '-', font, change);
926 lex.printError("Token `$$Token' "
928 "paragraph layout!");
932 InsetOld * inset = 0;
933 if (token == "\\SpecialChar" )
934 inset = new InsetSpecialChar;
936 inset = new InsetSpace;
937 inset->read(buf, lex);
938 par.insertInset(par.size(), inset, font, change);
940 } else if (token == "\\i") {
941 InsetOld * inset = new InsetLatexAccent;
942 inset->read(buf, lex);
943 par.insertInset(par.size(), inset, font, change);
944 } else if (token == "\\backslash") {
945 par.insertChar(par.size(), '\\', font, change);
946 } else if (token == "\\newline") {
947 InsetOld * inset = new InsetNewline;
948 inset->read(buf, lex);
949 par.insertInset(par.size(), inset, font, change);
950 } else if (token == "\\LyXTable") {
951 InsetOld * inset = new InsetTabular(buf);
952 inset->read(buf, lex);
953 par.insertInset(par.size(), inset, font, change);
954 } else if (token == "\\bibitem") {
955 InsetCommandParams p("bibitem", "dummy");
956 InsetBibitem * inset = new InsetBibitem(p);
957 inset->read(buf, lex);
958 par.insertInset(par.size(), inset, font, change);
959 } else if (token == "\\hfill") {
960 par.insertInset(par.size(), new InsetHFill, font, change);
961 } else if (token == "\\change_unchanged") {
962 // Hack ! Needed for empty paragraphs :/
963 // FIXME: is it still ??
966 change = Change(Change::UNCHANGED);
967 } else if (token == "\\change_inserted") {
969 istringstream is(STRCONV(lex.getString()));
973 change = Change(Change::INSERTED, bp.author_map[aid], ct);
974 } else if (token == "\\change_deleted") {
976 istringstream is(STRCONV(lex.getString()));
980 change = Change(Change::DELETED, bp.author_map[aid], ct);
983 string const s = bformat(_("Unknown token: %1$s %2$s\n"),
984 token, lex.getString());
986 buf.error(ErrorItem(_("Unknown token"), s,
987 par.id(), 0, par.size()));
996 int readParagraph(Buffer & buf, Paragraph & par, LyXLex & lex)
1001 string token = lex.getString();
1003 while (lex.isOK()) {
1005 unknown += readParToken(buf, par, lex, token);
1008 token = lex.getString();
1013 if (token == "\\end_layout") {
1014 //Ok, paragraph finished
1018 lyxerr[Debug::PARSER] << "Handling paragraph token: `"
1019 << token << '\'' << endl;
1020 if (token == "\\begin_layout" || token == "\\end_document"
1021 || token == "\\end_inset" || token == "\\begin_deeper"
1022 || token == "\\end_deeper") {
1023 lex.pushToken(token);
1024 lyxerr << "Paragraph ended in line "
1025 << lex.getLineNo() << "\n"
1026 << "Missing \\end_layout.\n";
1035 LyXFont const outerFont(ParagraphList::iterator pit,
1036 ParagraphList const & plist)
1038 Paragraph::depth_type par_depth = pit->getDepth();
1039 LyXFont tmpfont(LyXFont::ALL_INHERIT);
1041 // Resolve against environment font information
1042 while (pit != const_cast<ParagraphList&>(plist).end() &&
1043 par_depth && !tmpfont.resolved()) {
1044 pit = outerHook(pit, plist);
1045 if (pit != const_cast<ParagraphList&>(plist).end()) {
1046 tmpfont.realize(pit->layout()->font);
1047 par_depth = pit->getDepth();
1055 ParagraphList::iterator outerPar(Buffer const & buf, InsetOld const * inset)
1057 ParIterator pit = const_cast<Buffer &>(buf).par_iterator_begin();
1058 ParIterator end = const_cast<Buffer &>(buf).par_iterator_end();
1059 for ( ; pit != end; ++pit) {
1061 ParagraphList * plist;
1062 // the second '=' below is intentional
1063 for (int i = 0; (plist = inset->getParagraphs(i)); ++i)
1064 if (plist == &pit.plist())
1065 return pit.outerPar();
1067 InsetList::iterator ii = pit->insetlist.begin();
1068 InsetList::iterator iend = pit->insetlist.end();
1069 for ( ; ii != iend; ++ii)
1070 if (ii->inset == inset)
1071 return pit.outerPar();
1073 lyxerr << "outerPar: should not happen" << endl;
1075 return const_cast<Buffer &>(buf).paragraphs().end(); // shut up compiler
1079 Paragraph const & ownerPar(Buffer const & buf, InsetOld const * inset)
1081 ParConstIterator pit = buf.par_iterator_begin();
1082 ParConstIterator end = buf.par_iterator_end();
1083 for ( ; pit != end; ++pit) {
1084 ParagraphList * plist;
1085 // the second '=' below is intentional
1086 for (int i = 0; (plist = inset->getParagraphs(i)); ++i)
1087 if (plist == &pit.plist())
1090 InsetList::const_iterator ii = pit->insetlist.begin();
1091 InsetList::const_iterator iend = pit->insetlist.end();
1092 for ( ; ii != iend; ++ii)
1093 if (ii->inset == inset)
1096 lyxerr << "ownerPar: should not happen" << endl;
1098 return buf.paragraphs().front(); // shut up compiler