]> git.lyx.org Git - lyx.git/blobdiff - src/Text.cpp
Use << for raising 2 to power instead of ^
[lyx.git] / src / Text.cpp
index 1321a534f3b9abc5db1b9e743ee0d3df576f1cfd..4a447577f22c9e91d0139a739525d3a276f1538c 100644 (file)
@@ -190,10 +190,8 @@ Text::Text(InsetText * owner, bool use_default_layout)
 Text::Text(InsetText * owner, Text const & text)
        : owner_(owner), pars_(text.pars_)
 {
-       ParagraphList::iterator const end = pars_.end();
-       ParagraphList::iterator it = pars_.begin();
-       for (; it != end; ++it)
-               it->setInsetOwner(owner);
+       for (auto & p : pars_)
+               p.setInsetOwner(owner);
 }
 
 
@@ -288,6 +286,35 @@ Font const Text::outerFont(pit_type par_offset) const
 }
 
 
+int Text::getEndLabel(pit_type p) const
+{
+       pit_type pit = p;
+       depth_type par_depth = pars_[p].getDepth();
+       while (pit != pit_type(pars_.size())) {
+               Layout const & layout = pars_[pit].layout();
+               int const endlabeltype = layout.endlabeltype;
+
+               if (endlabeltype != END_LABEL_NO_LABEL) {
+                       if (p + 1 == pit_type(pars_.size()))
+                               return endlabeltype;
+
+                       depth_type const next_depth =
+                               pars_[p + 1].getDepth();
+                       if (par_depth > next_depth ||
+                           (par_depth == next_depth && layout != pars_[p + 1].layout()))
+                               return endlabeltype;
+                       break;
+               }
+               if (par_depth == 0)
+                       break;
+               pit = outerHook(pit);
+               if (pit != pit_type(pars_.size()))
+                       par_depth = pars_[pit].getDepth();
+       }
+       return END_LABEL_NO_LABEL;
+}
+
+
 static void acceptOrRejectChanges(ParagraphList & pars,
        BufferParams const & bparams, Text::ChangeOp op)
 {
@@ -445,6 +472,9 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        } else if (token == "\\numeric") {
                lex.next();
                font.fontInfo().setNumber(setLyXMisc(lex.getString()));
+       } else if (token == "\\nospellcheck") {
+               lex.next();
+               font.fontInfo().setNoSpellcheck(setLyXMisc(lex.getString()));
        } else if (token == "\\emph") {
                lex.next();
                font.fontInfo().setEmph(setLyXMisc(lex.getString()));
@@ -836,12 +866,18 @@ void Text::insertStringAsLines(Cursor & cur, docstring const & str,
        pit_type pit = cur.pit();
        pos_type pos = cur.pos();
 
+       // The special chars we handle
+       map<wchar_t, InsetSpecialChar::Kind> specialchars;
+       specialchars[0x200c] = InsetSpecialChar::LIGATURE_BREAK;
+       specialchars[0x200b] = InsetSpecialChar::ALLOWBREAK;
+       specialchars[0x2026] = InsetSpecialChar::LDOTS;
+       specialchars[0x2011] = InsetSpecialChar::NOBREAKDASH;
+
        // insert the string, don't insert doublespace
        bool space_inserted = true;
-       for (docstring::const_iterator cit = str.begin();
-           cit != str.end(); ++cit) {
+       for (auto const & ch : str) {
                Paragraph & par = pars_[pit];
-               if (*cit == '\n') {
+               if (ch == '\n') {
                        if (inset().allowMultiPar() && (!par.empty() || par.allowEmpty())) {
                                lyx::breakParagraph(*this, pit, pos,
                                        par.layout().isEnvironment());
@@ -852,28 +888,35 @@ void Text::insertStringAsLines(Cursor & cur, docstring const & str,
                                continue;
                        }
                // do not insert consecutive spaces if !free_spacing
-               } else if ((*cit == ' ' || *cit == '\t') &&
+               } else if ((ch == ' ' || ch == '\t') &&
                           space_inserted && !par.isFreeSpacing()) {
                        continue;
-               } else if (*cit == '\t') {
+               } else if (ch == '\t') {
                        if (!par.isFreeSpacing()) {
                                // tabs are like spaces here
                                par.insertChar(pos, ' ', font, bparams.track_changes);
                                ++pos;
                                space_inserted = true;
                        } else {
-                               par.insertChar(pos, *cit, font, bparams.track_changes);
+                               par.insertChar(pos, ch, font, bparams.track_changes);
                                ++pos;
                                space_inserted = true;
                        }
-               } else if (!isPrintable(*cit)) {
-                       // Ignore unprintables
+               } else if (specialchars.find(ch) != specialchars.end()) {
+                       par.insertInset(pos, new InsetSpecialChar(specialchars.find(ch)->second),
+                                       font, bparams.track_changes ?
+                                               Change(Change::INSERTED)
+                                             : Change(Change::UNCHANGED));
+                       ++pos;
+                       space_inserted = false;
+               } else if (!isPrintable(ch)) {
+                       // Ignore (other) unprintables
                        continue;
                } else {
                        // just insert the character
-                       par.insertChar(pos, *cit, font, bparams.track_changes);
+                       par.insertChar(pos, ch, font, bparams.track_changes);
                        ++pos;
-                       space_inserted = (*cit == ' ');
+                       space_inserted = (ch == ' ');
                }
        }
        setCursor(cur, pit, pos);
@@ -922,8 +965,8 @@ bool canInsertChar(Cursor const & cur, char_type c)
                                        "beginning of a paragraph. Please read the Tutorial."));
                        return false;
                }
-               // LASSERT: Is it safe to continue here?
-               LASSERT(cur.pos() > 0, /**/);
+               // If something is wrong, ignore this character.
+               LASSERT(cur.pos() > 0, return false);
                if ((par.isLineSeparator(cur.pos() - 1) || par.isNewline(cur.pos() - 1))
                                && !par.isDeleted(cur.pos() - 1)) {
                        cur.message(_(
@@ -968,14 +1011,19 @@ void Text::insertChar(Cursor & cur, char_type c)
        if (lyxrc.auto_number) {
                static docstring const number_operators = from_ascii("+-/*");
                static docstring const number_unary_operators = from_ascii("+-");
-               static docstring const number_separators = from_ascii(".,:");
 
+               // European Number Separators: comma, dot etc.
+               // European Number Terminators: percent, permille, degree, euro etc.
                if (cur.current_font.fontInfo().number() == FONT_ON) {
                        if (!isDigitASCII(c) && !contains(number_operators, c) &&
-                           !(contains(number_separators, c) &&
+                           !(isEuropeanNumberSeparator(c) &&
                              cur.pos() != 0 &&
                              cur.pos() != cur.lastpos() &&
                              tm.displayFont(pit, cur.pos()).fontInfo().number() == FONT_ON &&
+                             tm.displayFont(pit, cur.pos() - 1).fontInfo().number() == FONT_ON) &&
+                           !(isEuropeanNumberTerminator(c) &&
+                             cur.pos() != 0 &&
+                             tm.displayFont(pit, cur.pos()).fontInfo().number() == FONT_ON &&
                              tm.displayFont(pit, cur.pos() - 1).fontInfo().number() == FONT_ON)
                           )
                                number(cur); // Set current_font.number to OFF
@@ -993,7 +1041,7 @@ void Text::insertChar(Cursor & cur, char_type c)
                                  ) {
                                        setCharFont(pit, cur.pos() - 1, cur.current_font,
                                                tm.font_);
-                               } else if (contains(number_separators, ch)
+                               } else if (isEuropeanNumberSeparator(ch)
                                     && cur.pos() >= 2
                                     && tm.displayFont(pit, cur.pos() - 2).fontInfo().number() == FONT_ON) {
                                        setCharFont(pit, cur.pos() - 1, cur.current_font,
@@ -1333,7 +1381,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
        pos_type endPos = cur.selectionEnd().pos();
 
        // keep selection info, because endPos becomes invalid after the first loop
-       bool endsBeforeEndOfPar = (endPos < pars_[endPit].size());
+       bool const endsBeforeEndOfPar = (endPos < pars_[endPit].size());
 
        // first, accept/reject changes within each individual paragraph (do not consider end-of-par)
        for (pit_type pit = begPit; pit <= endPit; ++pit) {
@@ -1352,8 +1400,8 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
                if (pit == endPit && endPos == 0)
                        break; // last iteration anyway
 
-               pos_type left  = (pit == begPit ? begPos : 0);
-               pos_type right = (pit == endPit ? endPos : parSize);
+               pos_type const left  = (pit == begPit ? begPos : 0);
+               pos_type const right = (pit == endPit ? endPos : parSize);
 
                if (left == right)
                        // there is no change here
@@ -1476,7 +1524,7 @@ void Text::deleteWordForward(Cursor & cur, bool const force)
                cursorForwardOneWord(cur);
                cur.setSelection();
                if (force || !cur.confirmDeletion()) {
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                        cur.checkBufferStructure();
                }
        }
@@ -1494,7 +1542,7 @@ void Text::deleteWordBackward(Cursor & cur, bool const force)
                cursorBackwardOneWord(cur);
                cur.setSelection();
                if (force || !cur.confirmDeletion()) {
-                       cutSelection(cur, true, false);
+                       cutSelection(cur, false);
                        cur.checkBufferStructure();
                }
        }
@@ -1662,6 +1710,7 @@ bool Text::backspacePos0(Cursor & cur)
                plist.erase(lyx::next(plist.begin(), prevcur.pit()));
                needsUpdate = true;
        }
+       // FIXME: Do we really not want to allow this???
        // Pasting is not allowed, if the paragraphs have different
        // layouts. I think it is a real bug of all other
        // word processors to allow it. It confuses the user.
@@ -1695,7 +1744,8 @@ bool Text::backspace(Cursor & cur)
                Cursor prev_cur = cur;
                --prev_cur.pit();
 
-               if (!prev_cur.paragraph().isMergedOnEndOfParDeletion(cur.buffer()->params().track_changes)) {
+               if (cur.paragraph().size() > 0
+                   && !prev_cur.paragraph().isMergedOnEndOfParDeletion(cur.buffer()->params().track_changes)) {
                        cur.recordUndo(prev_cur.pit(), prev_cur.pit());
                        prev_cur.paragraph().setChange(prev_cur.lastpos(), Change(Change::DELETED));
                        setCursorIntern(cur, prev_cur.pit(), prev_cur.lastpos());
@@ -1729,7 +1779,7 @@ bool Text::backspace(Cursor & cur)
        needsUpdate |= handleBibitems(cur);
 
        // A singlePar update is not enough in this case.
-//             cur.screenUpdateFlags(Update::Force);
+       // cur.screenUpdateFlags(Update::Force);
        cur.top().setPitPos(cur.pit(), cur.pos());
 
        return needsUpdate;
@@ -1774,13 +1824,27 @@ bool Text::dissolveInset(Cursor & cur)
                // but we'll try the cheaper solution here.
                cur.buffer()->clearReferenceCache();
 
+               if (!lyxrc.ct_markup_copied)
+                       // Do not revive deleted text
+                       lyx::acceptChanges(plist, b.params());
+
                // ERT paragraphs have the Language latex_language.
                // This is invalid outside of ERT, so we need to
                // change it to the buffer language.
-               ParagraphList::iterator it = plist.begin();
-               ParagraphList::iterator it_end = plist.end();
-               for (; it != it_end; ++it)
-                       it->changeLanguage(b.params(), latex_language, b.language());
+               for (auto & p : plist)
+                       p.changeLanguage(b.params(), latex_language, b.language());
+
+               /* If the inset is the only thing in paragraph and the layout
+                * is not plain, then the layout of the first paragraph of
+                * inset should be remembered.
+                * FIXME: this does not work as expected when change tracking
+                *   is on However, we do not really know what to do in this
+                *   case.
+                */
+               DocumentClass const & tclass = cur.buffer()->params().documentClass();
+               if (inset_it.lastpos() == 1
+                   && plist[0].layout().name() != tclass.plainLayoutName())
+                       cur.paragraph().makeSameLayout(plist[0]);
 
                pasteParagraphList(cur, plist, b.params().documentClassPtr(),
                                   b.errorList("Paste"));
@@ -1974,12 +2038,44 @@ docstring Text::currentState(CursorData const & cur, bool devel_mode) const
 
 docstring Text::getPossibleLabel(DocIterator const & cur) const
 {
-       pit_type pit = cur.pit();
+       pit_type textpit = cur.pit();
+       Layout const * layout = &(pars_[textpit].layout());
+
+       // Will contain the label prefix.
+       docstring name;
+
+       // For captions, we just take the caption type
+       Inset * caption_inset = cur.innerInsetOfType(CAPTION_CODE);
+       if (caption_inset) {
+               string const & ftype = static_cast<InsetCaption *>(caption_inset)->floattype();
+               FloatList const & fl = cur.buffer()->params().documentClass().floats();
+               if (fl.typeExist(ftype)) {
+                       Floating const & flt = fl.getType(ftype);
+                       name = from_utf8(flt.refPrefix());
+               }
+               if (name.empty())
+                       name = from_utf8(ftype.substr(0,3));
+       } else {
+               // For section, subsection, etc...
+               if (layout->latextype == LATEX_PARAGRAPH && textpit != 0) {
+                       Layout const * layout2 = &(pars_[textpit - 1].layout());
+                       if (layout2->latextype != LATEX_PARAGRAPH) {
+                               --textpit;
+                               layout = layout2;
+                       }
+               }
+               if (layout->latextype != LATEX_PARAGRAPH)
+                       name = layout->refprefix;
 
-       Layout const * layout = &(pars_[pit].layout());
+               // If none of the above worked, see if the inset knows.
+               if (name.empty()) {
+                       InsetLayout const & il = cur.inset().getLayout();
+                       name = il.refprefix();
+               }
+       }
 
        docstring text;
-       docstring par_text = pars_[pit].asString();
+       docstring par_text = pars_[textpit].asString(AS_STR_SKIPDELETE);
 
        // The return string of math matrices might contain linebreaks
        par_text = subst(par_text, '\n', '-');
@@ -2000,46 +2096,13 @@ docstring Text::getPossibleLabel(DocIterator const & cur) const
        if (text.size() > max_label_length)
                text.resize(max_label_length);
 
-       // Will contain the label prefix.
-       docstring name;
-
-       // For section, subsection, etc...
-       if (layout->latextype == LATEX_PARAGRAPH && pit != 0) {
-               Layout const * layout2 = &(pars_[pit - 1].layout());
-               if (layout2->latextype != LATEX_PARAGRAPH) {
-                       --pit;
-                       layout = layout2;
-               }
-       }
-       if (layout->latextype != LATEX_PARAGRAPH)
-               name = layout->refprefix;
-
-       // For captions, we just take the caption type
-       Inset * caption_inset = cur.innerInsetOfType(CAPTION_CODE);
-       if (caption_inset) {
-               string const & ftype = static_cast<InsetCaption *>(caption_inset)->floattype();
-               FloatList const & fl = cur.buffer()->params().documentClass().floats();
-               if (fl.typeExist(ftype)) {
-                       Floating const & flt = fl.getType(ftype);
-                       name = from_utf8(flt.refPrefix());
-               }
-               if (name.empty())
-                       name = from_utf8(ftype.substr(0,3));
-       }
-
-       // If none of the above worked, see if the inset knows.
-       if (name.empty()) {
-               InsetLayout const & il = cur.inset().getLayout();
-               name = il.refprefix();
-       }
-
        if (!name.empty())
                text = name + ':' + text;
 
        // We need a unique label
        docstring label = text;
        int i = 1;
-       while (cur.buffer()->insetLabel(label)) {
+       while (cur.buffer()->activeLabel(label)) {
                        label = text + '-' + convert<docstring>(i);
                        ++i;
                }
@@ -2191,7 +2254,8 @@ docstring Text::previousWord(CursorSlice const & sl) const
 bool Text::completionSupported(Cursor const & cur) const
 {
        Paragraph const & par = cur.paragraph();
-       return cur.pos() > 0
+       return !cur.selection()
+               && cur.pos() > 0
                && (cur.pos() >= par.size() || par.isWordSeparator(cur.pos()))
                && !par.isWordSeparator(cur.pos() - 1);
 }