]> git.lyx.org Git - lyx.git/blobdiff - src/Text.cpp
Account for old versions of Pygments
[lyx.git] / src / Text.cpp
index f51646e55e681146027bc52d3d15b71ce530f0ae..483f945e039e7eb145b5d1660a42753e011f8405 100644 (file)
@@ -69,6 +69,7 @@
 #include "support/lyxalgo.h"
 #include "support/lyxtime.h"
 #include "support/textutils.h"
+#include "support/unique_ptr.h"
 
 #include <sstream>
 
@@ -109,12 +110,12 @@ static bool moveItem(Paragraph & fromPar, pos_type fromPos,
 
 
 void breakParagraphConservative(BufferParams const & bparams,
-       ParagraphList & pars, pit_type par_offset, pos_type pos)
+       ParagraphList & pars, pit_type pit, pos_type pos)
 {
        // create a new paragraph
-       Paragraph & tmp = *pars.insert(lyx::next(pars.begin(), par_offset + 1),
+       Paragraph & tmp = *pars.insert(lyx::next(pars.begin(), pit + 1),
                                       Paragraph());
-       Paragraph & par = pars[par_offset];
+       Paragraph & par = pars[pit];
 
        tmp.setInsetOwner(&par.inInset());
        tmp.makeSameLayout(par);
@@ -187,9 +188,8 @@ Text::Text(InsetText * owner, bool use_default_layout)
 
 
 Text::Text(InsetText * owner, Text const & text)
-       : owner_(owner)
+       : owner_(owner), pars_(text.pars_)
 {
-       pars_ = text.pars_;
        ParagraphList::iterator const end = pars_.end();
        ParagraphList::iterator it = pars_.begin();
        for (; it != end; ++it)
@@ -240,6 +240,21 @@ bool Text::isFirstInSequence(pit_type par_offset) const
 }
 
 
+pit_type Text::lastInSequence(pit_type pit) const
+{
+       depth_type const depth = pars_[pit].getDepth();
+       pit_type newpit = pit;
+
+       while (size_t(newpit + 1) < pars_.size() &&
+              (pars_[newpit + 1].getDepth() > depth ||
+               (pars_[newpit + 1].getDepth() == depth &&
+                pars_[newpit + 1].layout() == pars_[pit].layout())))
+               ++newpit;
+
+       return newpit;
+}
+
+
 int Text::getTocLevel(pit_type par_offset) const
 {
        Paragraph const & par = pars_[par_offset];
@@ -376,8 +391,8 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
                if (added_one) {
                        // Warn the user.
                        docstring const s = bformat(_("Layout `%1$s' was not found."), layoutname);
-                       errorList.push_back(
-                               ErrorItem(_("Layout Not Found"), s, par.id(), 0, par.size()));
+                       errorList.push_back(ErrorItem(_("Layout Not Found"), s,
+                                                     {par.id(), 0}, {par.id(), -1}));
                }
 
                par.setLayout(bp.documentClass()[layoutname]);
@@ -403,7 +418,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
                        lex.eatLine();
                        docstring line = lex.getDocString();
                        errorList.push_back(ErrorItem(_("Unknown Inset"), line,
-                                           par.id(), 0, par.size()));
+                                                     {par.id(), 0}, {par.id(), -1}));
                }
        } else if (token == "\\family") {
                lex.next();
@@ -449,6 +464,9 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        } else if (token == "\\strikeout") {
                lex.next();
                font.fontInfo().setStrikeout(setLyXMisc(lex.getString()));
+       } else if (token == "\\xout") {
+               lex.next();
+               font.fontInfo().setXout(setLyXMisc(lex.getString()));
        } else if (token == "\\uuline") {
                lex.next();
                font.fontInfo().setUuline(setLyXMisc(lex.getString()));
@@ -464,8 +482,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        } else if (token == "\\SpecialChar" ||
                   (token == "\\SpecialCharNoPassThru" &&
                    !par.layout().pass_thru && !inset().isPassThru())) {
-               auto_ptr<Inset> inset;
-               inset.reset(new InsetSpecialChar);
+               auto inset = make_unique<InsetSpecialChar>();
                inset->read(lex);
                inset->setBuffer(*buf);
                par.insertInset(par.size(), inset.release(), font, change);
@@ -474,8 +491,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
                docstring const s = ltrim(lex.getDocString(), "\\");
                par.insert(par.size(), s, font, change);
        } else if (token == "\\IPAChar") {
-               auto_ptr<Inset> inset;
-               inset.reset(new InsetIPAChar);
+               auto inset = make_unique<InsetIPAChar>();
                inset->read(lex);
                inset->setBuffer(*buf);
                par.insertInset(par.size(), inset.release(), font, change);
@@ -500,7 +516,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        } else if (token == "\\backslash") {
                par.appendChar('\\', font, change);
        } else if (token == "\\LyXTable") {
-               auto_ptr<Inset> inset(new InsetTabular(buf));
+               auto inset = make_unique<InsetTabular>(buf);
                inset->read(lex);
                par.insertInset(par.size(), inset.release(), font, change);
        } else if (token == "\\change_unchanged") {
@@ -522,8 +538,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
                                          "missing until the corresponding tracked changes "
                                          "are merged or this user edits the file again.\n"),
                                        aid),
-                               par.id(), par.size(), par.size() + 1
-                               ));
+                               {par.id(), par.size()}, {par.id(), par.size() + 1}));
                        bp.addAuthor(Author(aid));
                }
                if (token == "\\change_inserted")
@@ -533,9 +548,10 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        } else {
                lex.eatLine();
                errorList.push_back(ErrorItem(_("Unknown token"),
-                       bformat(_("Unknown token: %1$s %2$s\n"), from_utf8(token),
-                       lex.getDocString()),
-                       par.id(), 0, par.size()));
+                                             bformat(_("Unknown token: %1$s %2$s\n"),
+                                                     from_utf8(token),
+                                                     lex.getDocString()),
+                                             {par.id(), 0}, {par.id(), -1}));
        }
 }
 
@@ -588,7 +604,7 @@ class TextCompletionList : public CompletionList
 {
 public:
        ///
-       TextCompletionList(Cursor const & cur, WordList const * list)
+       TextCompletionList(Cursor const & cur, WordList const & list)
                : buffer_(cur.buffer()), list_(list)
        {}
        ///
@@ -599,19 +615,19 @@ public:
        ///
        virtual size_t size() const
        {
-               return list_->size();
+               return list_.size();
        }
        ///
        virtual docstring const & data(size_t idx) const
        {
-               return list_->word(idx);
+               return list_.word(idx);
        }
 
 private:
        ///
        Buffer const * buffer_;
        ///
-       WordList const * list_;
+       WordList const & list_;
 };
 
 
@@ -740,12 +756,17 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic)
        Layout const & layout = cpar.layout();
 
        if (cur.lastpos() == 0 && !cpar.allowEmpty()) {
-               if (changeDepthAllowed(cur, DEC_DEPTH))
+               if (changeDepthAllowed(cur, DEC_DEPTH)) {
                        changeDepth(cur, DEC_DEPTH);
-               else {
+                       pit_type const prev = depthHook(cpit, cpar.getDepth());
+                       docstring const & lay = pars_[prev].layout().name();
+                       if (lay != layout.name())
+                               setLayout(cur, lay);
+               } else {
                        docstring const & lay = cur.paragraph().usePlainLayout()
                            ? tclass.plainLayoutName() : tclass.defaultLayoutName();
-                       setLayout(cur, lay);
+                       if (lay != layout.name())
+                               setLayout(cur, lay);
                }
                return;
        }
@@ -907,11 +928,11 @@ 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_seperators = from_ascii(".,:");
+               static docstring const number_separators = from_ascii(".,:");
 
                if (cur.current_font.fontInfo().number() == FONT_ON) {
                        if (!isDigitASCII(c) && !contains(number_operators, c) &&
-                           !(contains(number_seperators, c) &&
+                           !(contains(number_separators, c) &&
                              cur.pos() != 0 &&
                              cur.pos() != cur.lastpos() &&
                              tm.displayFont(pit, cur.pos()).fontInfo().number() == FONT_ON &&
@@ -932,7 +953,7 @@ void Text::insertChar(Cursor & cur, char_type c)
                                  ) {
                                        setCharFont(pit, cur.pos() - 1, cur.current_font,
                                                tm.font_);
-                               } else if (contains(number_seperators, c)
+                               } else if (contains(number_separators, c)
                                     && cur.pos() >= 2
                                     && tm.displayFont(pit, cur.pos() - 2).fontInfo().number() == FONT_ON) {
                                        setCharFont(pit, cur.pos() - 1, cur.current_font,
@@ -1039,11 +1060,6 @@ void Text::insertChar(Cursor & cur, char_type c)
                        par.eraseChar(pos - 1, cur.buffer()->params().track_changes);
                        c = 0x2014;
                        pos--;
-               } else if (par.getChar(pos - 1) == 0x2014) {
-                       // convert "----" to "-"
-                       par.eraseChar(pos - 1, cur.buffer()->params().track_changes);
-                       c = '-';
-                       pos--;
                }
        }
 
@@ -1448,34 +1464,38 @@ void Text::rejectChanges()
 }
 
 
-void Text::deleteWordForward(Cursor & cur)
+void Text::deleteWordForward(Cursor & cur, bool const force)
 {
        LBUFERR(this == cur.text());
        if (cur.lastpos() == 0)
                cursorForward(cur);
        else {
                cur.resetAnchor();
-               cur.setSelection(true);
+               cur.selection(true);
                cursorForwardOneWord(cur);
                cur.setSelection();
-               cutSelection(cur, true, false);
-               cur.checkBufferStructure();
+               if (force || !cur.confirmDeletion()) {
+                       cutSelection(cur, true, false);
+                       cur.checkBufferStructure();
+               }
        }
 }
 
 
-void Text::deleteWordBackward(Cursor & cur)
+void Text::deleteWordBackward(Cursor & cur, bool const force)
 {
        LBUFERR(this == cur.text());
        if (cur.lastpos() == 0)
                cursorBackward(cur);
        else {
                cur.resetAnchor();
-               cur.setSelection(true);
+               cur.selection(true);
                cursorBackwardOneWord(cur);
                cur.setSelection();
-               cutSelection(cur, true, false);
-               cur.checkBufferStructure();
+               if (force || !cur.confirmDeletion()) {
+                       cutSelection(cur, true, false);
+                       cur.checkBufferStructure();
+               }
        }
 }
 
@@ -1587,6 +1607,7 @@ bool Text::erase(Cursor & cur)
                        return dissolveInset(cur);
 
                if (!par.isMergedOnEndOfParDeletion(cur.buffer()->params().track_changes)) {
+                       cur.recordUndo(DELETE_UNDO);
                        par.setChange(cur.pos(), Change(Change::DELETED));
                        cur.forwardPos();
                        needsUpdate = true;
@@ -1601,7 +1622,7 @@ bool Text::erase(Cursor & cur)
        if (needsUpdate) {
                // Make sure the cursor is correct. Is this really needed?
                // No, not really... at least not here!
-               cur.text()->setCursor(cur.top(), cur.pit(), cur.pos());
+               cur.top().setPitPos(cur.pit(), cur.pos());
                cur.checkBufferStructure();
        }
 
@@ -1708,7 +1729,7 @@ bool Text::backspace(Cursor & cur)
 
        // A singlePar update is not enough in this case.
 //             cur.screenUpdateFlags(Update::Force);
-       setCursor(cur.top(), cur.pit(), cur.pos());
+       cur.top().setPitPos(cur.pit(), cur.pos());
 
        return needsUpdate;
 }
@@ -1724,20 +1745,24 @@ bool Text::dissolveInset(Cursor & cur)
        cur.recordUndoInset();
        cur.setMark(false);
        cur.selHandle(false);
-       // save position
+       // save position inside inset
        pos_type spos = cur.pos();
        pit_type spit = cur.pit();
        ParagraphList plist;
        if (cur.lastpit() != 0 || cur.lastpos() != 0)
                plist = paragraphs();
        cur.popBackward();
-       // store cursor offset
+       // update cursor offset
        if (spit == 0)
                spos += cur.pos();
        spit += cur.pit();
-       Buffer & b = *cur.buffer();
-       cur.paragraph().eraseChar(cur.pos(), b.params().track_changes);
+       // remember position outside inset to delete inset later
+       // we do not do it now to avoid memory reuse issues (see #10667).
+       DocIterator inset_it = cur;
+       // jump over inset
+       ++cur.pos();
 
+       Buffer & b = *cur.buffer();
        if (!plist.empty()) {
                // see bug 7319
                // we clear the cache so that we won't get conflicts with labels
@@ -1758,17 +1783,20 @@ bool Text::dissolveInset(Cursor & cur)
 
                pasteParagraphList(cur, plist, b.params().documentClassPtr(),
                                   b.errorList("Paste"));
-               // restore position
-               cur.pit() = min(cur.lastpit(), spit);
-               cur.pos() = min(cur.lastpos(), spos);
        }
 
-       cur.forceBufferUpdate();
+       // delete the inset now
+       inset_it.paragraph().eraseChar(inset_it.pos(), b.params().track_changes);
 
+       // restore position
+       cur.pit() = min(cur.lastpit(), spit);
+       cur.pos() = min(cur.lastpos(), spos);
        // Ensure the current language is set correctly (bug 6292)
        cur.text()->setCursor(cur, cur.pit(), cur.pos());
        cur.clearSelection();
        cur.resetAnchor();
+       cur.forceBufferUpdate();
+
        return true;
 }
 
@@ -2038,20 +2066,36 @@ docstring Text::asString(pit_type beg, pit_type end, int options) const
 void Text::shortenForOutliner(docstring & str, size_t const maxlen)
 {
        support::truncateWithEllipsis(str, maxlen);
-       docstring::iterator it = str.begin();
-       docstring::iterator end = str.end();
-       for (; it != end; ++it)
-               if ((*it) == L'\n' || (*it) == L'\t')
-                       (*it) = L' ';   
+       for (char_type & c : str)
+               if (c == L'\n' || c == L'\t')
+                       c = L' ';
+}
+
+
+void Text::forOutliner(docstring & os, size_t const maxlen,
+                       bool const shorten) const
+{
+       pit_type end = pars_.size() - 1;
+       if (0 <= end && !pars_[0].labelString().empty())
+               os += pars_[0].labelString() + ' ';
+       forOutliner(os, maxlen, 0, end, shorten);
 }
 
 
 void Text::forOutliner(docstring & os, size_t const maxlen,
-                                          bool const shorten) const
+                       pit_type pit_start, pit_type pit_end,
+                       bool const shorten) const
 {
        size_t tmplen = shorten ? maxlen + 1 : maxlen;
-       for (size_t i = 0; i != pars_.size() && os.length() < tmplen; ++i)
-               pars_[i].forOutliner(os, tmplen, false);
+       pit_type end = min(size_t(pit_end), pars_.size() - 1);
+       bool first = true;
+       for (pit_type i = pit_start; i <= end && os.length() < tmplen; ++i) {
+               if (!first)
+                       os += ' ';
+               // This function lets the first label be treated separately
+               pars_[i].forOutliner(os, tmplen, false, !first);
+               first = false;
+       }
        if (shorten)
                shortenForOutliner(os, maxlen);
 }
@@ -2152,7 +2196,7 @@ bool Text::completionSupported(Cursor const & cur) const
 
 CompletionList const * Text::createCompletionList(Cursor const & cur) const
 {
-       WordList const * list = theWordList(cur.getFont().language()->lang());
+       WordList const & list = theWordList(cur.getFont().language()->lang());
        return new TextCompletionList(cur, list);
 }