]> git.lyx.org Git - lyx.git/blobdiff - src/Paragraph.cpp
Update tex2lyx test files
[lyx.git] / src / Paragraph.cpp
index df8de4c39f09ced1bece8559b5f0405d4eb102b3..e80ddc1de3070113d72a892d5c9cb0f967e91d2f 100644 (file)
@@ -134,7 +134,7 @@ public:
                current_change_number_ = 0;
        }
 
-       void setRange(FontSpan const fp, SpellChecker::Result state)
+       void setRange(FontSpan const fp, SpellChecker::Result state)
        {
                Ranges result;
                RangesIterator et = ranges_.end();
@@ -330,6 +330,7 @@ public:
        ///
        void latexSpecialChar(
                                   otexstream & os,
+                                  BufferParams const & bparams,
                                   OutputParams const & runparams,
                                   Font const & running_font,
                                   Change const & running_change,
@@ -345,6 +346,12 @@ public:
                pos_type i,
                unsigned int & column);
        ///
+       bool latexSpecialT3(
+               char_type const c,
+               otexstream & os,
+               pos_type i,
+               unsigned int & column);
+       ///
        bool latexSpecialTypewriter(
                char_type const c,
                otexstream & os,
@@ -852,8 +859,14 @@ int Paragraph::Private::latexSurrogatePair(otexstream & os, char_type c,
        // FIXME: change tracking
        // Is this correct WRT change tracking?
        Encoding const & encoding = *(runparams.encoding);
-       docstring const latex1 = encoding.latexChar(next);
-       docstring const latex2 = encoding.latexChar(c);
+       docstring latex1 = encoding.latexChar(next).first;
+       if (runparams.inIPA) {
+               string const tipashortcut = Encodings::TIPAShortcut(next);
+               if (!tipashortcut.empty()) {
+                       latex1 = from_ascii(tipashortcut);
+               }
+       }
+       docstring const latex2 = encoding.latexChar(c).first;
        if (docstring(1, next) == latex1) {
                // the encoding supports the combination
                os << latex2 << latex1;
@@ -969,7 +982,7 @@ int Paragraph::Private::writeScriptChars(otexstream & os,
                // Stop here if there is a font attribute or encoding change.
                if (found && cit != end && prev_font != cit->font())
                        break;
-               docstring const latex = encoding.latexChar(next);
+               docstring const latex = encoding.latexChar(next).first;
                docstring::size_type const b1 =
                                        latex.find_first_of(from_ascii("{"));
                docstring::size_type const b2 =
@@ -1070,6 +1083,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams,
        odocstream::pos_type const len = os.os().tellp();
 
        if (inset->forceLTR()
+           && !runparams.use_polyglossia
            && running_font.isRightToLeft()
            // ERT is an exception, it should be output with no
            // decorations at all
@@ -1149,6 +1163,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams,
 
 
 void Paragraph::Private::latexSpecialChar(otexstream & os,
+                                         BufferParams const & bparams,
                                          OutputParams const & runparams,
                                          Font const & running_font,
                                          Change const & running_change,
@@ -1157,29 +1172,36 @@ void Paragraph::Private::latexSpecialChar(otexstream & os,
                                          pos_type end_pos,
                                          unsigned int & column)
 {
-       char_type const c = text_[i];
+       // With polyglossia, brackets and stuff need not be reversed
+       // in RTL scripts (see bug #8251)
+       char_type const c = (runparams.use_polyglossia) ?
+               owner_->getUChar(bparams, i) : text_[i];
 
        if (style.pass_thru || runparams.pass_thru) {
                if (c != '\0') {
                        Encoding const * const enc = runparams.encoding;
-                       if (enc && enc->latexChar(c, true).empty())
+                       if (enc && !enc->encodable(c))
                                throw EncodingException(c);
                        os.put(c);
                }
                return;
        }
 
+       // TIPA uses its own T3 encoding
+       if (runparams.inIPA && latexSpecialT3(c, os, i, column))
+               return;
        // If T1 font encoding is used, use the special
        // characters it provides.
        // NOTE: some languages reset the font encoding
        // internally
-       if (!running_font.language()->internalFontEncoding()
+       if (!runparams.inIPA && !running_font.language()->internalFontEncoding()
            && lyxrc.fontenc == "T1" && latexSpecialT1(c, os, i, column))
                return;
 
        // \tt font needs special treatment
-       if (running_font.fontInfo().family() == TYPEWRITER_FAMILY
-               && latexSpecialTypewriter(c, os, i, column))
+       if (!runparams.inIPA
+            && running_font.fontInfo().family() == TYPEWRITER_FAMILY
+            && latexSpecialTypewriter(c, os, i, column))
                return;
 
        // Otherwise, we use what LaTeX provides us.
@@ -1253,8 +1275,9 @@ void Paragraph::Private::latexSpecialChar(otexstream & os,
                        return;
 
                Encoding const & encoding = *(runparams.encoding);
+               char_type next = '\0';
                if (i + 1 < int(text_.size())) {
-                       char_type next = text_[i + 1];
+                       next = text_[i + 1];
                        if (Encodings::isCombiningChar(next)) {
                                column += latexSurrogatePair(os, c, next, runparams) - 1;
                                ++i;
@@ -1262,20 +1285,50 @@ void Paragraph::Private::latexSpecialChar(otexstream & os,
                        }
                }
                string script;
-               docstring const latex = encoding.latexChar(c);
+               pair<docstring, bool> latex = encoding.latexChar(c);
+               docstring nextlatex;
+               bool nexttipas = false;
+               string nexttipashortcut;
+               if (next != '\0' && next != META_INSET) {
+                       nextlatex = encoding.latexChar(next).first;
+                       if (runparams.inIPA) {
+                               nexttipashortcut = Encodings::TIPAShortcut(next);
+                               nexttipas = !nexttipashortcut.empty();
+                       }
+               }
+               bool tipas = false;
+               if (runparams.inIPA) {
+                       string const tipashortcut = Encodings::TIPAShortcut(c);
+                       if (!tipashortcut.empty()) {
+                               latex.first = from_ascii(tipashortcut);
+                               latex.second = false;
+                               tipas = true;
+                       }
+               }
                if (Encodings::isKnownScriptChar(c, script)
-                   && prefixIs(latex, from_ascii("\\" + script)))
-                       column += writeScriptChars(os, latex,
+                   && prefixIs(latex.first, from_ascii("\\" + script)))
+                       column += writeScriptChars(os, latex.first,
                                        running_change, encoding, i) - 1;
-               else if (latex.length() > 1 && latex[latex.length() - 1] != '}') {
+               else if (latex.second
+                        && ((!prefixIs(nextlatex, '\\')
+                              && !prefixIs(nextlatex, '{')
+                              && !prefixIs(nextlatex, '}'))
+                            || (nexttipas
+                                && !prefixIs(from_ascii(nexttipashortcut), '\\')))
+                        && !tipas) {
                        // Prevent eating of a following
                        // space or command corruption by
                        // following characters
-                       column += latex.length() + 1;
-                       os << latex << "{}";
+                       if (next == ' ' || next == '\0') {
+                               column += latex.first.length() + 1;
+                               os << latex.first << "{}";
+                       } else {
+                               column += latex.first.length();
+                               os << latex.first << " ";
+                       }
                } else {
-                       column += latex.length() - 1;
-                       os << latex;
+                       column += latex.first.length() - 1;
+                       os << latex.first;
                }
                break;
        }
@@ -1310,6 +1363,26 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os,
 }
 
 
+bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os,
+       pos_type /*i*/, unsigned int & column)
+{
+       switch (c) {
+       case '*':
+       case '[':
+       case ']':
+       case '\"':
+               os.put(c);
+               return true;
+       case '|':
+               os << "\\textvertline{}";
+               column += 14;
+               return true;
+       default:
+               return false;
+       }
+}
+
+
 bool Paragraph::Private::latexSpecialTypewriter(char_type const c, otexstream & os,
        pos_type i, unsigned int & column)
 {
@@ -1397,7 +1470,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
 
        if (features.runparams().flavor == OutputParams::HTML
            && layout_->htmltitle()) {
-               features.setHTMLTitle(owner_->asString(AS_STR_INSETS));
+               features.setHTMLTitle(owner_->asString(AS_STR_INSETS | AS_STR_SKIPDELETE));
        }
 
        // check the params.
@@ -1838,16 +1911,23 @@ FontSize Paragraph::highestFontInRange
 char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
 {
        char_type c = d->text_[pos];
-       if (!lyxrc.rtl_support)
+       if (!lyxrc.rtl_support || !getFontSettings(bparams, pos).isRightToLeft())
                return c;
 
+       // FIXME: The arabic special casing is due to the difference of arabic
+       // round brackets input introduced in r18599. Check if this should be
+       // unified with Hebrew or at least if all bracket types should be
+       // handled the same (file format change in either case).
+       string const & lang = getFontSettings(bparams, pos).language()->lang();
+       bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi"
+               || lang == "farsi";
        char_type uc = c;
        switch (c) {
        case '(':
-               uc = ')';
+               uc = arabic ? c : ')';
                break;
        case ')':
-               uc = '(';
+               uc = arabic ? c : '(';
                break;
        case '[':
                uc = ']';
@@ -1868,9 +1948,8 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
                uc = '<';
                break;
        }
-       if (uc != c && getFontSettings(bparams, pos).isRightToLeft())
-               return uc;
-       return c;
+
+       return uc;
 }
 
 
@@ -2508,7 +2587,7 @@ void Paragraph::latex(BufferParams const & bparams,
                } else {
                        if (i >= start_pos && (end_pos == -1 || i < end_pos)) {
                                try {
-                                       d->latexSpecialChar(os, rp, running_font, runningChange,
+                                       d->latexSpecialChar(os, bparams, rp, running_font, runningChange,
                                                            style, i, end_pos, column);
                                } catch (EncodingException & e) {
                                if (runparams.dryrun) {
@@ -2784,7 +2863,7 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
                                retval += inset->xhtml(xs, np);
                        }
                } else {
-                       char_type c = d->text_[i];
+                       char_type c = getUChar(buf.params(), i);
 
                        if (style.pass_thru)
                                xs << c;
@@ -3171,70 +3250,61 @@ char_type Paragraph::transformChar(char_type c, pos_type pos) const
 }
 
 
-int Paragraph::checkBiblio(Buffer const & buffer)
+bool Paragraph::brokenBiblio() const
 {
-       // FIXME From JS:
-       // This is getting more and more a mess. ...We really should clean
-       // up this bibitem issue for 1.6.
+       // there is a problem if there is no bibitem at position 0 or
+       // if there is another bibitem in the paragraph.
+       return d->layout_->labeltype == LABEL_BIBLIO
+               && (d->insetlist_.find(BIBITEM_CODE) != 0
+                   || d->insetlist_.find(BIBITEM_CODE, 1) > 0);
+}
+
+
+int Paragraph::fixBiblio(Buffer const & buffer)
+{
+       // FIXME: What about the case where paragraph is not BIBLIO
+       // but there is an InsetBibitem?
+       // FIXME: when there was already an inset at 0, the return value is 1,
+       // which does not tell whether another inset has been remove; the
+       // cursor cannot be correctly updated.
 
-       // Add bibitem insets if necessary
        if (d->layout_->labeltype != LABEL_BIBLIO)
                return 0;
 
-       bool hasbibitem = !d->insetlist_.empty()
-               // Insist on it being in pos 0
-               && d->text_[0] == META_INSET
-               && d->insetlist_.begin()->inset->lyxCode() == BIBITEM_CODE;
-
-       bool track_changes = buffer.params().trackChanges;
-
-       docstring oldkey;
-       docstring oldlabel;
-
-       // remove a bibitem in pos != 0
-       // restore it later in pos 0 if necessary
-       // (e.g. if a user inserts contents _before_ the item)
-       // we're assuming there's only one of these, which there
-       // should be.
-       int erasedInsetPosition = -1;
-       InsetList::iterator it = d->insetlist_.begin();
-       InsetList::iterator end = d->insetlist_.end();
-       for (; it != end; ++it)
-               if (it->inset->lyxCode() == BIBITEM_CODE
-                     && it->pos > 0) {
-                       InsetCommand * olditem = it->inset->asInsetCommand();
-                       oldkey = olditem->getParam("key");
-                       oldlabel = olditem->getParam("label");
-                       erasedInsetPosition = it->pos;
-                       eraseChar(erasedInsetPosition, track_changes);
-                       break;
-       }
+       bool const track_changes = buffer.params().trackChanges;
+       int bibitem_pos = d->insetlist_.find(BIBITEM_CODE);
+       bool const hasbibitem0 = bibitem_pos == 0;
 
-       // There was an InsetBibitem at the beginning, and we didn't
-       // have to erase one.
-       if (hasbibitem && erasedInsetPosition < 0)
+       if (hasbibitem0) {
+               bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1);
+               // There was an InsetBibitem at pos 0, and no other one => OK
+               if (bibitem_pos == -1)
                        return 0;
+               // there is a bibitem at the 0 position, but since
+               // there is a second one, we copy the second on the
+               // first. We're assuming there are at most two of
+               // these, which there should be.
+               // FIXME: why does it make sense to do that rather
+               // than keep the first? (JMarc)
+               Inset * inset = d->insetlist_.release(bibitem_pos);
+               eraseChar(bibitem_pos, track_changes);
+               d->insetlist_.begin()->inset = inset;
+               return -bibitem_pos;
+       }
+
+       // We need to create an inset at the beginning
+       Inset * inset = 0;
+       if (bibitem_pos > 0) {
+               // there was one somewhere in the paragraph, let's move it
+               inset = d->insetlist_.release(bibitem_pos);
+               eraseChar(bibitem_pos, track_changes);
+       } else
+               // make a fresh one
+               inset = new InsetBibitem(const_cast<Buffer *>(&buffer),
+                                        InsetCommandParams(BIBITEM_CODE));
 
-       // There was an InsetBibitem at the beginning and we did have to
-       // erase one. So we give its properties to the beginning inset.
-       if (hasbibitem) {
-               InsetCommand * inset = d->insetlist_.begin()->inset->asInsetCommand();
-               if (!oldkey.empty())
-                       inset->setParam("key", oldkey);
-               inset->setParam("label", oldlabel);
-               return -erasedInsetPosition;
-       }
-
-       // There was no inset at the beginning, so we need to create one with
-       // the key and label of the one we erased.
-       InsetBibitem * inset =
-               new InsetBibitem(const_cast<Buffer *>(&buffer), InsetCommandParams(BIBITEM_CODE));
-       // restore values of previously deleted item in this par.
-       if (!oldkey.empty())
-               inset->setParam("key", oldkey);
-       inset->setParam("label", oldlabel);
-       insertInset(0, inset,
-                   Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
+       insertInset(0, inset, Change(track_changes ? Change::INSERTED 
+                                                  : Change::UNCHANGED));
 
        return 1;
 }
@@ -3489,16 +3559,13 @@ void Paragraph::locateWord(pos_type & from, pos_type & to,
 
 void Paragraph::collectWords()
 {
-       // This is the value that needs to be exposed in the preferences
-       // to resolve bug #6760.
-       static int minlength = 6;
        pos_type n = size();
        for (pos_type pos = 0; pos < n; ++pos) {
                if (isWordSeparator(pos))
                        continue;
                pos_type from = pos;
                locateWord(from, pos, WHOLE_WORD);
-               if (pos - from >= minlength) {
+               if ((pos - from) >= (int)lyxrc.completion_minlength) {
                        docstring word = asString(from, pos, AS_STR_NONE);
                        FontList::const_iterator cit = d->fontlist_.fontIterator(pos);
                        if (cit == d->fontlist_.end())