]> git.lyx.org Git - lyx.git/blobdiff - src/Text.cpp
Merge branch 'master' of git.lyx.org:lyx
[lyx.git] / src / Text.cpp
index 5e92dd09bb0d7a8fa18cbb80dab79d1d0f21bdc9..12ab04f043397925fbfdd47059172509702d7149 100644 (file)
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/lyxalgo.h"
+#include "support/lyxtime.h"
 #include "support/textutils.h"
+#include "support/unique_ptr.h"
 
-#include <limits>
 #include <sstream>
 
 
-// TODO: replace if in Text::readParToken() with compile time switch
-#if 0
-
-#include "support/metahash.h"
-
-typedef boost::mpl::string<'\\end','_lay','out'> end_layout;
-typedef boost::mpl::string<'\\end','in','set'>   end_inset;
-
-void foo()
-{
-       std::string token = "\\end_layout";
-
-       switch (boost::hash_value(token)) {
-               case lyx::support::hash_string<end_layout>::value:
-                       return;
-               case lyx::support::hash_string<end_inset>::value:
-                       return;
-               default: ;
-       };
-
-}
-#endif
-
-
 using namespace std;
 using namespace lyx::support;
 
@@ -133,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(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);
@@ -211,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)
@@ -361,7 +337,7 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
        string const & token, Font & font, Change & change, ErrorList & errorList)
 {
        Buffer * buf = const_cast<Buffer *>(&owner_->buffer());
-       BufferParams const & bp = buf->params();
+       BufferParams & bp = buf->params();
 
        if (token[0] != '\\') {
                docstring dstr = lex.getDocString();
@@ -488,8 +464,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);
@@ -498,8 +473,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);
@@ -524,7 +498,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") {
@@ -535,18 +509,25 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
                int aid;
                time_t ct;
                is >> aid >> ct;
-               BufferParams::AuthorMap const & am = bp.author_map;
+               BufferParams::AuthorMap const & am = bp.author_map_;
                if (am.find(aid) == am.end()) {
-                       errorList.push_back(ErrorItem(_("Change tracking error"),
-                                           bformat(_("Unknown author index for change: %1$d\n"), aid),
-                                           par.id(), 0, par.size()));
-                       change = Change(Change::UNCHANGED);
-               } else {
-                       if (token == "\\change_inserted")
-                               change = Change(Change::INSERTED, am.find(aid)->second, ct);
-                       else
-                               change = Change(Change::DELETED, am.find(aid)->second, ct);
+                       errorList.push_back(ErrorItem(
+                               _("Change tracking author index missing"),
+                               bformat(_("A change tracking author information for index "
+                                         "%1$d is missing. This can happen after a wrong "
+                                         "merge by a version control system. In this case, "
+                                         "either fix the merge, or have this information "
+                                         "missing until the corresponding tracked changes "
+                                         "are merged or this user edits the file again.\n"),
+                                       aid),
+                               par.id(), par.size(), par.size() + 1
+                               ));
+                       bp.addAuthor(Author(aid));
                }
+               if (token == "\\change_inserted")
+                       change = Change(Change::INSERTED, am.find(aid)->second, ct);
+               else
+                       change = Change(Change::DELETED, am.find(aid)->second, ct);
        } else {
                lex.eatLine();
                errorList.push_back(ErrorItem(_("Unknown token"),
@@ -662,7 +643,7 @@ static void breakParagraph(Text & text, pit_type par_offset, pos_type pos,
        ParagraphList & pars = text.paragraphs();
        // create a new paragraph, and insert into the list
        ParagraphList::iterator tmp =
-               pars.insert(next(pars.begin(), par_offset + 1),
+               pars.insert(lyx::next(pars.begin(), par_offset + 1),
                            Paragraph());
 
        Paragraph & par = pars[par_offset];
@@ -924,11 +905,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 &&
@@ -949,7 +930,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,
@@ -1044,7 +1025,7 @@ void Text::insertChar(Cursor & cur, char_type c)
 
        pos_type pos = cur.pos();
        if (!cur.paragraph().isPassThru() && owner_->lyxCode() != IPA_CODE &&
-           cur.current_font.fontInfo().family() != TYPEWRITER_FAMILY &&
+           cur.real_current_font.fontInfo().family() != TYPEWRITER_FAMILY &&
            c == '-' && pos > 0) {
                if (par.getChar(pos - 1) == '-') {
                        // convert "--" to endash
@@ -1104,7 +1085,7 @@ bool Text::cursorForwardOneWord(Cursor & cur)
        Paragraph const & par = cur.paragraph();
 
        // Paragraph boundary is a word boundary
-       if (pos == lastpos) {
+       if (pos == lastpos || (pos + 1 == lastpos && par.isEnvSeparator(pos))) {
                if (pit != cur.lastpit())
                        return setCursor(cur, pit + 1, 0);
                else
@@ -1114,7 +1095,7 @@ bool Text::cursorForwardOneWord(Cursor & cur)
        if (lyxrc.mac_like_cursor_movement) {
                // Skip through trailing punctuation and spaces.
                while (pos != lastpos && (par.isChar(pos) || par.isSpace(pos)))
-                        ++pos;
+                       ++pos;
 
                // Skip over either a non-char inset or a full word
                if (pos != lastpos && par.isWordSeparator(pos))
@@ -1137,6 +1118,10 @@ bool Text::cursorForwardOneWord(Cursor & cur)
                             ++pos;
        }
 
+       // Don't skip a separator inset at the end of a paragraph
+       if (pos == lastpos && pos && par.isEnvSeparator(pos - 1))
+               --pos;
+
        return setCursor(cur, pit, pos);
 }
 
@@ -1150,8 +1135,14 @@ bool Text::cursorBackwardOneWord(Cursor & cur)
        Paragraph & par = cur.paragraph();
 
        // Paragraph boundary is a word boundary
-       if (pos == 0 && pit != 0)
-               return setCursor(cur, pit - 1, getPar(pit - 1).size());
+       if (pos == 0 && pit != 0) {
+               Paragraph & prevpar = getPar(pit - 1);
+               pos = prevpar.size();
+               // Don't stop after an environment separator
+               if (pos && prevpar.isEnvSeparator(pos - 1))
+                       --pos;
+               return setCursor(cur, pit - 1, pos);
+       }
 
        if (lyxrc.mac_like_cursor_movement) {
                // Skip through punctuation and spaces.
@@ -1187,7 +1178,6 @@ bool Text::cursorVisLeftOneWord(Cursor & cur)
        LBUFERR(this == cur.text());
 
        pos_type left_pos, right_pos;
-       bool left_is_letter, right_is_letter;
 
        Cursor temp_cur = cur;
 
@@ -1196,9 +1186,9 @@ bool Text::cursorVisLeftOneWord(Cursor & cur)
 
                // collect some information about current cursor position
                temp_cur.getSurroundingPos(left_pos, right_pos);
-               left_is_letter =
+               bool left_is_letter =
                        (left_pos > -1 ? !temp_cur.paragraph().isWordSeparator(left_pos) : false);
-               right_is_letter =
+               bool right_is_letter =
                        (right_pos > -1 ? !temp_cur.paragraph().isWordSeparator(right_pos) : false);
 
                // if we're not at a letter/non-letter boundary, continue moving
@@ -1224,7 +1214,6 @@ bool Text::cursorVisRightOneWord(Cursor & cur)
        LBUFERR(this == cur.text());
 
        pos_type left_pos, right_pos;
-       bool left_is_letter, right_is_letter;
 
        Cursor temp_cur = cur;
 
@@ -1233,9 +1222,9 @@ bool Text::cursorVisRightOneWord(Cursor & cur)
 
                // collect some information about current cursor position
                temp_cur.getSurroundingPos(left_pos, right_pos);
-               left_is_letter =
+               bool left_is_letter =
                        (left_pos > -1 ? !temp_cur.paragraph().isWordSeparator(left_pos) : false);
-               right_is_letter =
+               bool right_is_letter =
                        (right_pos > -1 ? !temp_cur.paragraph().isWordSeparator(right_pos) : false);
 
                // if we're not at a letter/non-letter boundary, continue moving
@@ -1262,7 +1251,7 @@ void Text::selectWord(Cursor & cur, word_location loc)
 {
        LBUFERR(this == cur.text());
        CursorSlice from = cur.top();
-       CursorSlice to = cur.top();
+       CursorSlice to;
        getWord(from, to, loc);
        if (cur.top() != from)
                setCursor(cur, from.pit(), from.pos());
@@ -1464,7 +1453,7 @@ void Text::deleteWordForward(Cursor & cur)
                cursorForward(cur);
        else {
                cur.resetAnchor();
-               cur.setSelection(true);
+               cur.selection(true);
                cursorForwardOneWord(cur);
                cur.setSelection();
                cutSelection(cur, true, false);
@@ -1480,7 +1469,7 @@ void Text::deleteWordBackward(Cursor & cur)
                cursorBackward(cur);
        else {
                cur.resetAnchor();
-               cur.setSelection(true);
+               cur.selection(true);
                cursorBackwardOneWord(cur);
                cur.setSelection();
                cutSelection(cur, true, false);
@@ -1490,20 +1479,19 @@ void Text::deleteWordBackward(Cursor & cur)
 
 
 // Kill to end of line.
-void Text::changeCase(Cursor & cur, TextCase action)
+void Text::changeCase(Cursor & cur, TextCase action, bool partial)
 {
        LBUFERR(this == cur.text());
        CursorSlice from;
        CursorSlice to;
 
-       bool gotsel = false;
-       if (cur.selection()) {
+       bool const gotsel = cur.selection();
+       if (gotsel) {
                from = cur.selBegin();
                to = cur.selEnd();
-               gotsel = true;
        } else {
                from = cur.top();
-               getWord(from, to, PARTIAL_WORD);
+               getWord(from, to, partial ? PARTIAL_WORD : WHOLE_WORD);
                cursorForwardOneWord(cur);
        }
 
@@ -1611,7 +1599,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();
        }
 
@@ -1640,14 +1628,14 @@ bool Text::backspacePos0(Cursor & cur)
        if (cur.lastpos() == 0
            || (cur.lastpos() == 1 && par.isSeparator(0))) {
                cur.recordUndo(prevcur.pit());
-               plist.erase(next(plist.begin(), cur.pit()));
+               plist.erase(lyx::next(plist.begin(), cur.pit()));
                needsUpdate = true;
        }
        // is previous par empty?
        else if (prevcur.lastpos() == 0
                 || (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
                cur.recordUndo(prevcur.pit());
-               plist.erase(next(plist.begin(), prevcur.pit()));
+               plist.erase(lyx::next(plist.begin(), prevcur.pit()));
                needsUpdate = true;
        }
        // Pasting is not allowed, if the paragraphs have different
@@ -1718,7 +1706,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;
 }
@@ -1887,13 +1875,11 @@ docstring Text::currentState(Cursor const & cur) const
        Change change = par.lookupChange(cur.pos());
 
        if (change.changed()) {
-               Author const & a = buf.params().authors().get(change.author);
-               os << _("Change: ") << a.name();
-               if (!a.email().empty())
-                       os << " (" << a.email() << ")";
-               // FIXME ctime is english, we should translate that
-               os << _(" at ") << ctime(&change.changetime);
-               os << " : ";
+               docstring const author =
+                       buf.params().authors().get(change.author).nameAndEmail();
+               docstring const date = formatted_datetime(change.changetime);
+               os << bformat(_("Changed by %1$s[[author]] on %2$s[[date]]. "),
+                             author, date);
        }
 
        // I think we should only show changes from the default
@@ -2047,16 +2033,25 @@ docstring Text::asString(pit_type beg, pit_type end, int options) const
 }
 
 
-void Text::forOutliner(docstring & os, size_t maxlen, bool shorten) const
+void Text::shortenForOutliner(docstring & str, size_t const maxlen)
 {
-       if (maxlen == 0)
-               maxlen = std::numeric_limits<std::size_t>::max();
-       else
-               LASSERT(maxlen >= 8, maxlen = TOC_ENTRY_LENGTH);
-       for (size_t i = 0; i != pars_.size() && os.length() < maxlen; ++i)
-               pars_[i].forOutliner(os, maxlen);
-       if (shorten && os.length() >= maxlen)
-               os = os.substr(0, maxlen - 3) + from_ascii("...");
+       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' ';   
+}
+
+
+void Text::forOutliner(docstring & os, size_t const maxlen,
+                                          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);
+       if (shorten)
+               shortenForOutliner(os, maxlen);
 }