X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fparagraph_pimpl.C;h=ab4b20af932117b7d012be41b1167f083e104c92;hb=98c966c64594611e469313314abd1e59524adb4a;hp=2d9891074c1b89ee35da93dad55227aca6eb515a;hpb=76ef051b1cb1fb51c3ffd8ccc9105be4471e74d4;p=lyx.git diff --git a/src/paragraph_pimpl.C b/src/paragraph_pimpl.C index 2d9891074c..ab4b20af93 100644 --- a/src/paragraph_pimpl.C +++ b/src/paragraph_pimpl.C @@ -1,10 +1,10 @@ /* This file is part of - * ====================================================== - * + * ====================================================== + * * LyX, The Document Processor - * + * * Copyright 1995 Matthias Ettrich - * Copyright 1995-2001 The LyX Team. + * Copyright 1995-2001 The LyX Team. * * ====================================================== */ @@ -16,19 +16,41 @@ #include "paragraph_pimpl.h" #include "texrow.h" +#include "language.h" #include "bufferparams.h" #include "encoding.h" #include "lyxrc.h" #include "debug.h" +#include "lyxtextclasslist.h" + +#include "support/LAssert.h" + +using lyx::pos_type; +using std::endl; +using std::ostream; +using std::upper_bound; +using std::lower_bound; extern int tex_code_break_column; +// Initialize static member. +ShareContainer Paragraph::Pimpl::FontTable::container; // Initialization of the counter for the paragraph id's, unsigned int Paragraph::Pimpl::paragraph_id = 0; -// Initialize static member. -ShareContainer Paragraph::Pimpl::FontTable::container; +namespace { + +string special_phrases[][2] = { + { "LyX", "\\LyX{}" }, + { "TeX", "\\TeX{}" }, + { "LaTeX2e", "\\LaTeXe{}" }, + { "LaTeX", "\\LaTeX{}" }, + }; + +size_t phrases_nr = sizeof(special_phrases)/sizeof(special_phrases[0]); + +} // namespace anon Paragraph::Pimpl::Pimpl(Paragraph * owner) @@ -39,12 +61,16 @@ Paragraph::Pimpl::Pimpl(Paragraph * owner) } -Paragraph::Pimpl::Pimpl(Paragraph::Pimpl const & p, Paragraph * owner) - : owner_(owner) +Paragraph::Pimpl::Pimpl(Pimpl const & p, Paragraph * owner, bool same_ids) + : params(p.params), owner_(owner) { inset_owner = p.inset_owner; text = p.text; fontlist = p.fontlist; + if (same_ids) + id_ = p.id_; + else + id_ = paragraph_id++; } @@ -61,8 +87,7 @@ void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par) } -Paragraph::value_type -Paragraph::Pimpl::getChar(Paragraph::size_type pos) const +Paragraph::value_type Paragraph::Pimpl::getChar(pos_type pos) const { lyx::Assert(pos <= size()); // This is stronger, and I belive that this is the assertion @@ -71,20 +96,18 @@ Paragraph::Pimpl::getChar(Paragraph::size_type pos) const // Then this has no meaning. (Lgb) if (!size() || pos == size()) return '\0'; - + return text[pos]; } -void Paragraph::Pimpl::setChar(Paragraph::size_type pos, - Paragraph::value_type c) +void Paragraph::Pimpl::setChar(pos_type pos, value_type c) { text[pos] = c; } -void Paragraph::Pimpl::insertChar(Paragraph::size_type pos, - Paragraph::value_type c, +void Paragraph::Pimpl::insertChar(pos_type pos, value_type c, LyXFont const & font) { lyx::Assert(pos <= size()); @@ -94,79 +117,83 @@ void Paragraph::Pimpl::insertChar(Paragraph::size_type pos, // Update the font table. FontTable search_font(pos, LyXFont()); for (FontList::iterator it = lower_bound(fontlist.begin(), - fontlist.end(), - search_font, matchFT()); + fontlist.end(), + search_font, matchFT()); it != fontlist.end(); ++it) - (*it).pos((*it).pos() + 1); - + { + it->pos(it->pos() + 1); + } + // Update the inset table. InsetTable search_inset(pos, 0); for (InsetList::iterator it = lower_bound(owner_->insetlist.begin(), - owner_->insetlist.end(), - search_inset, matchIT()); + owner_->insetlist.end(), + search_inset, matchIT()); it != owner_->insetlist.end(); ++it) - ++(*it).pos; - + { + ++it->pos; + } owner_->setFont(pos, font); } -void Paragraph::Pimpl::insertInset(Paragraph::size_type pos, +void Paragraph::Pimpl::insertInset(pos_type pos, Inset * inset, LyXFont const & font) { lyx::Assert(inset); lyx::Assert(pos <= size()); - + insertChar(pos, META_INSET, font); lyx::Assert(text[pos] == META_INSET); - + // Add a new entry in the inset table. InsetTable search_inset(pos, 0); InsetList::iterator it = lower_bound(owner_->insetlist.begin(), - owner_->insetlist.end(), - search_inset, matchIT()); - if (it != owner_->insetlist.end() && (*it).pos == pos) { + owner_->insetlist.end(), + search_inset, matchIT()); + if (it != owner_->insetlist.end() && it->pos == pos) { lyxerr << "ERROR (Paragraph::InsertInset): " "there is an inset in position: " << pos << endl; } else { owner_->insetlist.insert(it, InsetTable(pos, inset)); + inset->parOwner(owner_); } - + if (inset_owner) inset->setOwner(inset_owner); } -void Paragraph::Pimpl::erase(Paragraph::size_type pos) +void Paragraph::Pimpl::erase(pos_type pos) { lyx::Assert(pos < size()); - // if it is an inset, delete the inset entry + // if it is an inset, delete the inset entry if (text[pos] == Paragraph::META_INSET) { // find the entry InsetTable search_inset(pos, 0); InsetList::iterator it = lower_bound(owner_->insetlist.begin(), - owner_->insetlist.end(), - search_inset, matchIT()); - if (it != owner_->insetlist.end() && (*it).pos == pos) { - delete (*it).inset; + owner_->insetlist.end(), + search_inset, matchIT()); + if (it != owner_->insetlist.end() && it->pos == pos) { + delete it->inset; owner_->insetlist.erase(it); } } - + text.erase(text.begin() + pos); - + // Erase entries in the tables. FontTable search_font(pos, LyXFont()); - + FontList::iterator it = lower_bound(fontlist.begin(), fontlist.end(), search_font, matchFT()); - if (it != fontlist.end() && (*it).pos() == pos && - (pos == 0 || - (it != fontlist.begin() - && (*(it - 1)).pos() == pos - 1))) { + if (it != fontlist.end() && it->pos() == pos && + (pos == 0 || + (it != fontlist.begin() + && boost::prior(it)->pos() == pos - 1))) { // If it is a multi-character font // entry, we just make it smaller // (see update below), otherwise we @@ -180,48 +207,44 @@ void Paragraph::Pimpl::erase(Paragraph::size_type pos) it = fontlist.begin() + i - 1; } } - + // Update all other entries. FontList::iterator fend = fontlist.end(); for (; it != fend; ++it) - (*it).pos((*it).pos() - 1); - + it->pos(it->pos() - 1); + // Update the inset table. InsetTable search_inset(pos, 0); InsetList::iterator lend = owner_->insetlist.end(); for (InsetList::iterator it = upper_bound(owner_->insetlist.begin(), - lend, - search_inset, matchIT()); + lend, + search_inset, matchIT()); it != lend; ++it) - --(*it).pos; + --it->pos; } void Paragraph::Pimpl::simpleTeXBlanks(ostream & os, TexRow & texrow, - Paragraph::size_type const i, - int & column, LyXFont const & font, - LyXLayout const & style) + pos_type const i, + int & column, LyXFont const & font, + LyXLayout const & style) { + if (style.pass_thru) return; if (column > tex_code_break_column - && i - && owner_->getChar(i - 1) != ' ' - && (i < owner_->size() - 1) -#ifndef NO_LATEX - // In LaTeX mode, we don't want to - // break lines since some commands - // do not like this - && ! (font.latex() == LyXFont::ON) -#endif + && i + && getChar(i - 1) != ' ' + && (i < size() - 1) // same in FreeSpacing mode && !style.free_spacing - // In typewriter mode, we want to avoid + && !owner_->isFreeSpacing() + // In typewriter mode, we want to avoid // ! . ? : at the end of a line && !(font.family() == LyXFont::TYPEWRITER_FAMILY - && (owner_->getChar(i-1) == '.' - || owner_->getChar(i-1) == '?' - || owner_->getChar(i-1) == ':' - || owner_->getChar(i-1) == '!'))) { + && (getChar(i - 1) == '.' + || getChar(i - 1) == '?' + || getChar(i - 1) == ':' + || getChar(i - 1) == '!'))) { if (tex_code_break_column == 0) { // in batchmode we need LaTeX to still // see it as a space not as an extra '\n' @@ -232,34 +255,49 @@ void Paragraph::Pimpl::simpleTeXBlanks(ostream & os, TexRow & texrow, texrow.newline(); texrow.start(owner_, i + 1); column = 0; - } else -#ifndef NO_LATEX - if (font.latex() == LyXFont::OFF) { -#endif - if (style.free_spacing) { - os << '~'; - } else { - os << ' '; - } -#ifndef NO_LATEX + } else if (style.free_spacing) { + os << '~'; + } else { + os << ' '; } -#endif +} + + +bool Paragraph::Pimpl::isTextAt(BufferParams const & bp, + string const & str, pos_type pos) +{ + LyXFont const & font = owner_->getFont(bp, pos); + + for (string::size_type i = 0; i < str.length(); ++i) { + if (pos + static_cast(i) >= size()) + return false; + if (str[i] != getChar(pos + i)) + return false; + if (owner_->getFont(bp, pos + i) != font) + return false; + } + return true; } void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf, BufferParams const & bparams, - ostream & os, TexRow & texrow, + ostream & os, + TexRow & texrow, bool moving_arg, LyXFont & font, LyXFont & running_font, LyXFont & basefont, bool & open_font, LyXLayout const & style, - Paragraph::size_type & i, + pos_type & i, int & column, - Paragraph::value_type const c) + value_type const c) { + if (style.pass_thru) { + if (c != '\0') os << c; + return; + } // Two major modes: LaTeX or plain // Handle here those cases common to both modes // and then split to handle the two modes separately. @@ -270,28 +308,29 @@ void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf, bool close = false; int const len = os.tellp(); //ostream::pos_type const len = os.tellp(); - if ((inset->LyxCode() == Inset::GRAPHICS_CODE - || inset->LyxCode() == Inset::MATH_CODE - || inset->LyxCode() == Inset::URL_CODE) + if ((inset->lyxCode() == Inset::GRAPHICS_CODE + || inset->lyxCode() == Inset::MATH_CODE + || inset->lyxCode() == Inset::URL_CODE) && running_font.isRightToLeft()) { os << "\\L{"; close = true; } - int tmp = inset->Latex(buf, os, moving_arg, + int tmp = inset->latex(buf, os, moving_arg, style.free_spacing); if (close) os << "}"; if (tmp) { + for (int j = 0; j < tmp; ++j) { + texrow.newline(); + } + texrow.start(owner_, i + 1); column = 0; } else { column += int(os.tellp()) - len; } - for (; tmp--;) { - texrow.newline(); - } } } break; @@ -303,213 +342,172 @@ void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf, basefont); open_font = false; } - basefont = owner_->getFont(bparams, -1); + basefont = owner_->getLayoutFont(bparams); running_font = basefont; break; - case Paragraph::META_HFILL: + case Paragraph::META_HFILL: os << "\\hfill{}"; column += 7; break; default: // And now for the special cases within each mode -#ifndef NO_LATEX - // Are we in LaTeX mode? - if (font.latex() == LyXFont::ON) { - // at present we only have one option - // but I'll leave it as a switch statement - // so its simpler to extend. (ARRae) - switch (c) { - default: - // make sure that we will not print - // error generating chars to the tex - // file. This test would not be needed - // if it were done in the buffer - // itself. - if (c != '\0') { - os << c; + + switch (c) { + case '\\': + os << "\\textbackslash{}"; + column += 15; + break; + + case '°': case '±': case '²': case '³': + case '×': case '÷': case '¹': case 'ª': + case 'º': case '¬': case 'µ': + if ((bparams.inputenc == "latin1" || + bparams.inputenc == "latin9") || + (bparams.inputenc == "auto" && + (font.language()->encoding()->LatexName() + == "latin1" || + font.language()->encoding()->LatexName() + == "latin9"))) { + os << "\\ensuremath{" + << c + << '}'; + column += 13; + } else { + os << c; + } + break; + + case '|': case '<': case '>': + // In T1 encoding, these characters exist + if (lyxrc.fontenc == "T1") { + os << c; + //... but we should avoid ligatures + if ((c == '>' || c == '<') + && i <= size() - 2 + && getChar(i + 1) == c) { + //os << "\\textcompwordmark{}"; + // Jean-Marc, have a look at + // this. I think this works + // equally well: + os << "\\,{}"; + // Lgb + column += 19; } break; } - } else { -#endif - // Plain mode (i.e. not LaTeX) + // Typewriter font also has them + if (font.family() == LyXFont::TYPEWRITER_FAMILY) { + os << c; + break; + } + // Otherwise, we use what LaTeX + // provides us. switch (c) { - case '\\': - os << "\\textbackslash{}"; - column += 15; + case '<': + os << "\\textless{}"; + column += 10; break; - - case '°': case '±': case '²': case '³': - case '×': case '÷': case '¹': case 'ª': - case 'º': case '¬': case 'µ': - if (bparams.inputenc == "latin1" || - (bparams.inputenc == "auto" && - font.language()->encoding()->LatexName() - == "latin1")) { - os << "\\ensuremath{" - << c - << '}'; - column += 13; - } else { - os << c; - } + case '>': + os << "\\textgreater{}"; + column += 13; break; - - case '|': case '<': case '>': - // In T1 encoding, these characters exist - if (lyxrc.fontenc == "T1") { - os << c; - //... but we should avoid ligatures - if ((c == '>' || c == '<') - && i <= owner_->size() - 2 - && owner_->getChar(i + 1) == c) { - //os << "\\textcompwordmark{}"; - // Jean-Marc, have a look at - // this. I think this works - // equally well: - os << "\\,{}"; - // Lgb - column += 19; - } - break; - } - // Typewriter font also has them - if (font.family() == LyXFont::TYPEWRITER_FAMILY) { - os << c; - break; - } - // Otherwise, we use what LaTeX - // provides us. - switch (c) { - case '<': - os << "\\textless{}"; - column += 10; - break; - case '>': - os << "\\textgreater{}"; - column += 13; - break; - case '|': - os << "\\textbar{}"; - column += 9; - break; - } + case '|': + os << "\\textbar{}"; + column += 9; break; + } + break; - case '-': // "--" in Typewriter mode -> "-{}-" - if (i <= owner_->size() - 2 - && owner_->getChar(i + 1) == '-' - && font.family() == LyXFont::TYPEWRITER_FAMILY) { - os << "-{}"; - column += 2; - } else { - os << '-'; - } - break; + case '-': // "--" in Typewriter mode -> "-{}-" + if (i <= size() - 2 + && getChar(i + 1) == '-' + && font.family() == LyXFont::TYPEWRITER_FAMILY) { + os << "-{}"; + column += 2; + } else { + os << '-'; + } + break; - case '\"': - os << "\\char`\\\"{}"; - column += 9; - break; + case '\"': + os << "\\char`\\\"{}"; + column += 9; + break; - case '£': - if (bparams.inputenc == "default") { - os << "\\pounds{}"; - column += 8; - } else { + case '£': + if (bparams.inputenc == "default") { + os << "\\pounds{}"; + column += 8; + } else { + os << c; + } + break; + + case '$': case '&': + case '%': case '#': case '{': + case '}': case '_': + os << '\\' << c; + column += 1; + break; + + case '~': + os << "\\textasciitilde{}"; + column += 16; + break; + + case '^': + os << "\\textasciicircum{}"; + column += 17; + break; + + case '*': case '[': case ']': + // avoid being mistaken for optional arguments + os << '{' << c << '}'; + column += 2; + break; + + case ' ': + // Blanks are printed before font switching. + // Sure? I am not! (try nice-latex) + // I am sure it's correct. LyX might be smarter + // in the future, but for now, nothing wrong is + // written. (Asger) + break; + + default: + + // I assume this is hack treating typewriter as verbatim + if (font.family() == LyXFont::TYPEWRITER_FAMILY) { + if (c != '\0') { os << c; } break; + } - case '$': case '&': - case '%': case '#': case '{': - case '}': case '_': - os << '\\' << c; - column += 1; - break; - - case '~': - os << "\\textasciitilde{}"; - column += 16; - break; - - case '^': - os << "\\textasciicircum{}"; - column += 17; - break; + // LyX, LaTeX etc. - case '*': case '[': case ']': - // avoid being mistaken for optional arguments - os << '{' << c << '}'; - column += 2; - break; + // FIXME: if we have "LaTeX" with a font change in the middle (before + // the 'T', then the "TeX" part is still special cased. Really we + // should only operate this on "words" for some definition of word - case ' ': - // Blanks are printed before font switching. - // Sure? I am not! (try nice-latex) - // I am sure it's correct. LyX might be smarter - // in the future, but for now, nothing wrong is - // written. (Asger) - break; + size_t pnr = 0; - default: - /* idea for labels --- begin*/ - // Check for "LyX" - if (c == 'L' - && i <= owner_->size() - 3 - && font.family() != LyXFont::TYPEWRITER_FAMILY - && owner_->getChar(i + 1) == 'y' - && owner_->getChar(i + 2) == 'X') { - os << "\\LyX{}"; - i += 2; - column += 5; - } - // Check for "TeX" - else if (c == 'T' - && i <= owner_->size() - 3 - && font.family() != LyXFont::TYPEWRITER_FAMILY - && owner_->getChar(i + 1) == 'e' - && owner_->getChar(i + 2) == 'X') { - os << "\\TeX{}"; - i += 2; - column += 5; - } - // Check for "LaTeX2e" - else if (c == 'L' - && i <= owner_->size() - 7 - && font.family() != LyXFont::TYPEWRITER_FAMILY - && owner_->getChar(i + 1) == 'a' - && owner_->getChar(i + 2) == 'T' - && owner_->getChar(i + 3) == 'e' - && owner_->getChar(i + 4) == 'X' - && owner_->getChar(i + 5) == '2' - && owner_->getChar(i + 6) == 'e') { - os << "\\LaTeXe{}"; - i += 6; - column += 8; - } - // Check for "LaTeX" - else if (c == 'L' - && i <= owner_->size() - 5 - && font.family() != LyXFont::TYPEWRITER_FAMILY - && owner_->getChar(i + 1) == 'a' - && owner_->getChar(i + 2) == 'T' - && owner_->getChar(i + 3) == 'e' - && owner_->getChar(i + 4) == 'X') { - os << "\\LaTeX{}"; - i += 4; - column += 7; - /* idea for labels --- end*/ - } else if (c != '\0') { - os << c; + for (; pnr < phrases_nr; ++pnr) { + if (isTextAt(bparams, special_phrases[pnr][0], i)) { + os << special_phrases[pnr][1]; + i += special_phrases[pnr][0].length() - 1; + column += special_phrases[pnr][1].length() - 1; + break; } - break; } -#ifndef NO_LATEX + + if (pnr == phrases_nr && c != '\0') { + os << c; + } + break; } -#endif } } @@ -523,8 +521,7 @@ Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf, Paragraph * par = owner_; while (par && par->params().depth() == owner_->params().depth()) { - if (textclasslist.Style(bparams.textclass, - par->layout).isEnvironment()) { + if (textclasslist[bparams.textclass][par->layout()].isEnvironment()) { par = par->TeXEnvironment(buf, bparams, os, texrow); } else { @@ -538,3 +535,45 @@ Paragraph * Paragraph::Pimpl::TeXDeeper(Buffer const * buf, } +Paragraph * Paragraph::Pimpl::getParFromID(int id) const +{ + InsetList::const_iterator cit = owner_->insetlist.begin(); + InsetList::const_iterator lend = owner_->insetlist.end(); + Paragraph * result; + for (; cit != lend; ++cit) { + if ((result = cit->inset->getParFromID(id))) + return result; + } + return 0; +} + + +LyXFont const Paragraph::Pimpl::realizeFont(LyXFont const & font, + BufferParams const & bparams) const +{ + LyXFont tmpfont(font); + + // check for environment font information + char par_depth = owner_->getDepth(); + Paragraph const * par = owner_; + LyXTextClass const & tclass = textclasslist[bparams.textclass]; + + while (par && par->getDepth() && !tmpfont.resolved()) { + par = par->outerHook(); + if (par) { + tmpfont.realize(tclass[par->layout()].font +#ifdef INHERIT_LANGUAGE + , bparams.language +#endif + ); + par_depth = par->getDepth(); + } + } + + tmpfont.realize(tclass.defaultfont() +#ifdef INHERIT_LANGUAGE + , bparams.language +#endif + ); + return tmpfont; +}