]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
Amend 6c3447c8: FindAdv: sometimes a space is added on some math symbols
[lyx.git] / src / lyxfind.cpp
index 0ba2acec9010a4d194352901cc12b9143416b047..a42fc4e1dcf2ee08c9054f7ba591c3a1d3fd578b 100644 (file)
 //#define ResultsDebug
 #define USE_QT_FOR_SEARCH
 #if defined(USE_QT_FOR_SEARCH)
-       #include <QtCore>       // sets QT_VERSION
-       #if (QT_VERSION >= 0x050000)
-               #include <QRegularExpression>
-               #define QTSEARCH 1
-       #else
-               #define QTSEARCH 0
-       #endif
+       #include <QRegularExpression>
+       #define QTSEARCH 1
 #else
        #define QTSEARCH 0
 #endif
@@ -294,9 +289,11 @@ bool findOne(BufferView * bv, docstring const & searchstr,
             bool find_del, bool check_wrap, bool const auto_wrap,
             bool instant, bool onlysel)
 {
+       bool const had_selection = bv->cursor().selection();
+
        // Clean up previous selections with empty searchstr on instant
        if (searchstr.empty() && instant) {
-               if (bv->cursor().selection()) {
+               if (had_selection) {
                        bv->setCursor(bv->cursor().selectionBegin());
                        bv->clearSelection();
                }
@@ -306,9 +303,10 @@ bool findOne(BufferView * bv, docstring const & searchstr,
        if (!searchAllowed(searchstr))
                return false;
 
-       DocIterator const endcur = forward ? bv->cursor().selectionEnd() : bv->cursor().selectionBegin();
+       DocIterator const startcur = bv->cursor().selectionBegin();
+       DocIterator const endcur = bv->cursor().selectionEnd();
 
-       if (onlysel && bv->cursor().selection()) {
+       if (onlysel && had_selection) {
                docstring const matchstring = bv->cursor().selectionAsString(false);
                docstring const lcmatchsting = support::lowercase(matchstring);
                if (matchstring == searchstr || (!case_sens && lcmatchsting == lowercase(searchstr))) {
@@ -334,11 +332,11 @@ bool findOne(BufferView * bv, docstring const & searchstr,
 
        int match_len = forward
                ? findForward(cur, endcur, match, find_del, onlysel)
-               : findBackwards(cur, endcur, match, find_del, onlysel);
+               : findBackwards(cur, startcur, match, find_del, onlysel);
 
        if (match_len > 0)
                bv->putSelectionAt(cur, match_len, !forward);
-       else if (onlysel) {
+       else if (onlysel && had_selection) {
                docstring q = _("The search string was not found within the selection.\n"
                                "Continue search outside?");
                int search_answer = frontend::Alert::prompt(_("Search outside selection?"),
@@ -352,7 +350,6 @@ bool findOne(BufferView * bv, docstring const & searchstr,
                return false;
        }
        else if (check_wrap) {
-               DocIterator cur_orig(bv->cursor());
                bool wrap = auto_wrap;
                if (!auto_wrap) {
                        docstring q;
@@ -385,7 +382,13 @@ bool findOne(BufferView * bv, docstring const & searchstr,
                                    find_del, false, false, false, false))
                                return true;
                }
-               bv->cursor().setCursor(cur_orig);
+               bv->setCursor(startcur);
+
+               // restore original selection
+               if (had_selection) {
+                       bv->cursor().resetAnchor();
+                       bv->setSelection(startcur, endcur);
+               }
                return false;
        }
 
@@ -461,7 +464,7 @@ int replaceAll(BufferView * bv,
        if (had_selection) {
                endcur.fixIfBroken();
                bv->cursor().resetAnchor();
-               bv->setCursorSelectionTo(endcur);
+               bv->setSelection(startcur, endcur);
        }
 
        return num;
@@ -836,13 +839,47 @@ string string2regex(string in)
                        // normal blanks
                        blanks++;
                }
-               else if ((tempx[i] == '\302' && tempx[i+1] == '\240')
-                       || (tempx[i] == '\342' && tempx[i+1] == '\200')) {
-                       // protected space
-                       // thin space
+               else if (tempx[i] == '\302' && tempx[i+1] == '\240') {
+                       // Normal Space
                        blanks++;
                        i++;
                }
+               else if (tempx[i] == '\342') {
+                       if (tempx[i+1] == '\200') {
+                               if ((tempx[i+2] == '\257')
+                                  || (tempx[i+2] == '\203')
+                                  || (tempx[i+2] == '\202')) {
+                                       // Non-breaking Thin (1/6 em)
+                                       // Quad(1 em), (Double quad counts as 2 blanks)
+                                       // Half Quad
+                                       blanks++;
+                                       i += 2;
+                               }
+                               else if (tempx[i+2] == '\213') {
+                                       // Ignoring parts of Medium and Thick
+                                       i += 2;
+                                       continue;
+                               }
+                               else if ((tempx[i+2] == '\204') || (tempx[i+2] == '\205')) {
+                                       // Thick
+                                       // Medium
+                                       blanks++;
+                                       i += 2;
+                               }
+                       }
+                       else if (tempx[i+1] == '\201') {
+                               if (tempx[i+2] == '\240') {
+                                       // Ignoring parts of half quad
+                                       i += 2;
+                                       continue;
+                               }
+                       }
+                       else if ((tempx[i+1] == '\220') && (tempx[i+2] == '\243')) {
+                               // Visible space
+                               blanks++;
+                               i += 2;
+                       }
+               }
                else {
                        if (blanks > 0) {
                                temp += getRegexSpaceCount(blanks);
@@ -918,6 +955,9 @@ string correctRegex(string t, bool withformat)
                        }
                        else if (sub.str(4) == "mathcircumflex")
                                replace = "^";
+                       else if ((sub.str(4) == "negthinspace") || (sub.str(4) == "negmedspace") || (sub.str(4) == "negthickspace")) {
+                               replace = accents[sub.str(4)+"{}"];
+                       }
                        else if (backslashed) {
                                backslashed = false;
                                if (withformat) {
@@ -1128,10 +1168,10 @@ private:
        // par_as_string after removal of lead_as_string
        string par_as_string_nolead;
        // unmatched open braces in the search string/regexp
-       int open_braces;
+       int open_braces = 0;
        // number of (.*?) subexpressions added at end of search regexp for closing
        // environments, math mode, styles, etc...
-       int close_wildcards;
+       int close_wildcards = 0;
 public:
        // Are we searching with regular expressions ?
        bool use_regexp = false;
@@ -1236,6 +1276,16 @@ static string latexNamesToUtf8(docstring strIn, bool withformat)
        return add;
 }
 
+static bool isPartOfMath(Paragraph const & par)
+{
+       if (par.size() < 1)
+               return false;
+       const Inset * isInset = par.getInset(par.size()-1);
+       if (isInset == nullptr)
+               return false;
+       return isInset->inMathed();
+}
+
 static docstring stringifySearchBuffer(Buffer & buffer, FindAndReplaceOptions const & opt)
 {
        docstring str;
@@ -1258,6 +1308,8 @@ static docstring stringifySearchBuffer(Buffer & buffer, FindAndReplaceOptions co
                        runparams.find_add_feature(OutputParams::SearchNonOutput);
                }
                string t("");
+               // Only check if the very last entry is inside math to remove trailing space
+               bool isMathInset = false;
                for (pos_type pit = pos_type(0); pit < (pos_type)buffer.paragraphs().size(); ++pit) {
                        Paragraph const & par = buffer.paragraphs().at(pit);
                        string add = latexNamesToUtf8(par.asString(pos_type(0), par.size(),
@@ -1266,10 +1318,16 @@ static docstring stringifySearchBuffer(Buffer & buffer, FindAndReplaceOptions co
                        LYXERR(Debug::FINDVERBOSE, "Adding to search string: '"
                                << add << "'");
                        t += add;
+                       isMathInset = isPartOfMath(par);
                }
                // Even in ignore-format we have to remove "\text{}, \lyxmathsym{}" parts
                while (regex_replace(t, t, "\\\\(text|lyxmathsym|ensuremath)\\{([^\\}]*)\\}", "$2"));
-               str = from_utf8(t);
+               // remove trailing space, it may have  been added by plaintext() in InsetMathHull.cpp
+               size_t t_size = t.size();
+               if (opt.ignoreformat && (t_size > 1) && (t[t_size-1] == ' ') && isMathInset)
+                       str =  from_utf8(t.substr(0, t_size-1));
+               else
+                       str = from_utf8(t);
        }
        return str;
 }
@@ -1967,11 +2025,11 @@ static void buildAccentsMap()
        accents["guillemotleft"] = "«";
        accents["hairspace"]     = getutf8(0xf0000);    // select from free unicode plane 15
        accents["thinspace"]     = getutf8(0xf0002);    // and used _only_ by findadv
-       accents["negthinspace"]  = getutf8(0xf0003);    // to omit backslashed latex macros
+       accents["negthinspace{}"]= getutf8(0xf0003);    // to omit backslashed latex macros
        accents["medspace"]      = getutf8(0xf0004);    // See https://en.wikipedia.org/wiki/Private_Use_Areas
-       accents["negmedspace"]   = getutf8(0xf0005);
+       accents["negmedspace{}"] = getutf8(0xf0005);
        accents["thickspace"]    = getutf8(0xf0006);
-       accents["negthickspace"] = getutf8(0xf0007);
+       accents["negthickspace{}"]= getutf8(0xf0007);
        accents["lyx"]           = getutf8(0xf0010);    // Used logos
        accents["LyX"]           = getutf8(0xf0010);
        accents["tex"]           = getutf8(0xf0011);
@@ -2061,7 +2119,7 @@ void Intervall::removeAccents()
        if (accents.empty())
                buildAccentsMap();
        static regex const accre("\\\\("
-                                "([\\S]|[A-Za-z]+)\\{[^\\\\\\{\\}]+\\}"
+                                "([\\S]|[A-Za-z]+)\\{[^\\\\\\{\\}]*\\}"
                                 "|([\\S]|[A-Za-z]+)\\{\\\\[ij](math)?\\}"
                                 "|("
                                 "(backslash ([lL]y[xX]|[tT]e[xX]|[lL]a[tT]e[xX]e?|lyxarrow))"
@@ -3670,8 +3728,6 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt)
        }
        // When using regexp, braces are hacked already by escape_for_regex()
        par_as_string = convertLF2Space(ds, opt.ignoreformat);
-       open_braces = 0;
-       close_wildcards = 0;
 
        size_t lead_size = 0;
        // correct the language settings
@@ -4055,9 +4111,16 @@ string MatchStringAdv::convertLF2Space(docstring const &s, bool ignore_format) c
        return(t.str());
 }
 
+static string showPos(DocIterator const & cur)
+{
+       stringstream a;
+       a << "[idx(" << cur.idx() << "),pit(" << cur.pit() << "),pos(" << cur.pos() << "),depth(" << cur.depth() << ")]";
+       return(a.str());
+}
+
 docstring stringifyFromCursor(DocIterator const & cur, int len)
 {
-       LYXERR(Debug::FINDVERBOSE, "Stringifying with len=" << len << " from cursor at pos: " << cur);
+       LYXERR(Debug::FINDVERBOSE, "Stringifying with len=" << len << " from cursor at " << showPos(cur));
        if (cur.inTexted()) {
                Paragraph const & par = cur.paragraph();
                // TODO what about searching beyond/across paragraph breaks ?
@@ -4079,8 +4142,8 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
                if (ignoreFormats.getNonContent()) {
                        runparams.find_add_feature(OutputParams::SearchNonOutput);
                }
-               LYXERR(Debug::FINDVERBOSE, "Stringifying with cur: "
-                      << cur << ", from pos: " << cur.pos() << ", end: " << end);
+               LYXERR(Debug::FINDVERBOSE, "Stringifying with cur = "
+                      << showPos(cur) << ", to end: " << end);
                docstring res = from_utf8(latexNamesToUtf8(par.asString(cur.pos(), end,
                                                                        option,
                                                                        &runparams), false));
@@ -4093,14 +4156,14 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
                                (( len == -1 || cs.pos() + len > int(md.size()))
                                 ? md.end()
                                 : md.begin() + cs.pos() + len );
-               MathData md2;
+               MathData md2(cur.buffer());
                for (MathData::const_iterator it = md.begin() + cs.pos(); it != it_end; ++it)
                        md2.push_back(*it);
                docstring res = from_utf8(latexNamesToUtf8(asString(md2), false));
                LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Stringified math from pos(" << cur.pos() << ") len(" << len << "): " << res);
                return res;
        }
-       LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Don't know how to stringify from here: " << cur);
+       LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Don't know how to stringify from here: " << showPos(cur));
        return docstring();
 }
 
@@ -4111,7 +4174,7 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
 docstring latexifyFromCursor(DocIterator const & cur, int len)
 {
        /*
-       LYXERR(Debug::FINDVERBOSE, "Latexifying with len=" << len << " from cursor at pos: " << cur);
+       LYXERR(Debug::FINDVERBOSE, "Latexifying with len=" << len << " from cursor at " << showPos(cur));
        LYXERR(Debug::FINDVERBOSE, "  with cur.lastpost=" << cur.lastpos() << ", cur.lastrow="
               << cur.lastrow() << ", cur.lastcol=" << cur.lastcol());
        */
@@ -4159,7 +4222,7 @@ docstring latexifyFromCursor(DocIterator const & cur, int len)
                                ((len == -1 || cs.pos() + len > int(md.size()))
                                 ? md.end()
                                 : md.begin() + cs.pos() + len);
-               MathData md2;
+               MathData md2(cur.buffer());
                for (MathData::const_iterator it = md.begin() + cs.pos();
                     it != it_end; ++it)
                        md2.push_back(*it);
@@ -4178,7 +4241,7 @@ docstring latexifyFromCursor(DocIterator const & cur, int len)
                }
                LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Latexified math from pos(" << cur.pos() << ") len(" << len << "): " << ods.str());
        } else {
-               LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Don't know how to stringify from here: " << cur);
+               LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Don't know how to stringify from here: " << showPos(cur));
        }
        return ods.str();
 }
@@ -4382,7 +4445,7 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
        cur = orig_cur;
        while (!theApp()->longOperationCancelled() && cur) {
                //(void) findAdvForwardInnermost(cur);
-               LYXERR(Debug::FINDVERBOSE, "findForwardAdv() cur: " << cur);
+               LYXERR(Debug::FINDVERBOSE, "findForwardAdv() cur: " << showPos(cur));
                MatchResult mres = match(cur, -1, MatchStringAdv::MatchAnyPlace);
                string msg = "Starting";
                if (repeat > 0)
@@ -4401,7 +4464,7 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
                                // This should exit nested insets, if any, or otherwise undefine the currsor.
                                cur.pos() = cur.lastpos();
                        }
-                       LYXERR(Debug::FINDVERBOSE, "Advancing pos: cur=" << cur);
+                       LYXERR(Debug::FINDVERBOSE, "Advancing pos: cur=" << showPos(cur));
                        cur.forwardPos();
                }
                else {  // match_len > 0
@@ -4499,7 +4562,7 @@ MatchResult findMostBackwards(DocIterator & cur, MatchStringAdv const & match, M
        MatchResult mr = findAdvFinalize(tmp_cur, match, expected);
        Inset & inset = cur.inset();
        for (; cur != cur_begin; cur.backwardPos()) {
-               LYXERR(Debug::FINDVERBOSE, "findMostBackwards(): cur=" << cur);
+               LYXERR(Debug::FINDVERBOSE, "findMostBackwards(): cur=" << showPos(cur));
                DocIterator new_cur = cur;
                new_cur.backwardPos();
                if (new_cur == cur || &new_cur.inset() != &inset
@@ -4510,7 +4573,7 @@ MatchResult findMostBackwards(DocIterator & cur, MatchStringAdv const & match, M
                        break;
                mr = new_mr;
        }
-       LYXERR(Debug::FINDVERBOSE, "findMostBackwards(): exiting with cur=" << cur);
+       LYXERR(Debug::FINDVERBOSE, "findMostBackwards(): exiting with cur=" << showPos(cur));
        return mr;
 }
 
@@ -4536,12 +4599,12 @@ int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match)
                                cur.pos() = cur.lastpos();
                        else
                                cur.pos() = cur_orig.pos();
-                       LYXERR(Debug::FINDVERBOSE, "findBackAdv2: cur: " << cur);
+                       LYXERR(Debug::FINDVERBOSE, "findBackAdv2: cur: " << showPos(cur));
                        DocIterator cur_prev_iter;
                        do {
                                found_match = match(cur, -1, MatchStringAdv::MatchFromStart);
                                LYXERR(Debug::FINDVERBOSE, "findBackAdv3: found_match="
-                                      << (found_match.match_len > 0) << ", cur: " << cur);
+                                      << (found_match.match_len > 0) << ", cur: " << showPos(cur));
                                if (found_match.match_len > 0) {
                                        MatchResult found_mr = findMostBackwards(cur, match, found_match);
                                        if (found_mr.pos_len > 0) {
@@ -4622,7 +4685,7 @@ static bool firstUppercase(Cursor const & cur)
        char_type ch1, ch2;
        pos_type pos = cur.selectionBegin().pos();
        if (pos >= cur.lastpos() - 1) {
-               LYXERR(Debug::FINDVERBOSE, "No upper-case at cur: " << cur);
+               LYXERR(Debug::FINDVERBOSE, "No upper-case at cur: " << showPos(cur));
                return false;
        }
        ch1 = cur.paragraph().getChar(pos);
@@ -4730,12 +4793,12 @@ static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, Ma
                                        repl_buffer.language(),
                                        cur.getFont().language());
                LYXERR(Debug::FINDVERBOSE, "Replacing by pasteParagraphList()ing repl_buffer");
-               LYXERR(Debug::FINDVERBOSE, "Before pasteParagraphList() cur=" << cur << endl);
+               LYXERR(Debug::FINDVERBOSE, "Before pasteParagraphList() cur=" << showPos(cur) << endl);
                cap::pasteParagraphList(cur, repl_buffer.paragraphs(),
                                        repl_buffer.params().documentClassPtr(),
                                        repl_buffer.params().authors(),
                                        bv->buffer().errorList("Paste"));
-               LYXERR(Debug::FINDVERBOSE, "After pasteParagraphList() cur=" << cur << endl);
+               LYXERR(Debug::FINDVERBOSE, "After pasteParagraphList() cur=" << showPos(cur) << endl);
                sel_len = repl_buffer.paragraphs().begin()->size();
        } else if (cur.inMathed()) {
                odocstringstream ods;
@@ -4752,18 +4815,18 @@ static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, Ma
                (void)regex_replace(to_utf8(repl_latex), s, "\\$(.*)\\$", "$1");
                (void)regex_replace(s, s, "\\\\\\[(.*)\\\\\\]", "$1");
                repl_latex = from_utf8(s);
-               LYXERR(Debug::FINDVERBOSE, "Replacing by insert()ing latex: '" << repl_latex << "' cur=" << cur << " with depth=" << cur.depth());
+               LYXERR(Debug::FINDVERBOSE, "Replacing by insert()ing latex: '" << repl_latex << "' cur=" << showPos(cur) );
                MathData ar(cur.buffer());
                asArray(repl_latex, ar, Parse::NORMAL);
                cur.insert(ar);
                sel_len = ar.size();
-               LYXERR(Debug::FINDVERBOSE, "After insert() cur=" << cur << " with depth: " << cur.depth() << " and len: " << sel_len);
+               LYXERR(Debug::FINDVERBOSE, "After insert() cur=" << showPos(cur) << " and len: " << sel_len);
        }
        if (cur.pos() >= sel_len)
                cur.pos() -= sel_len;
        else
                cur.pos() = 0;
-       LYXERR(Debug::FINDVERBOSE, "After pos adj cur=" << cur << " with depth: " << cur.depth() << " and len: " << sel_len);
+       LYXERR(Debug::FINDVERBOSE, "After pos adj cur=" << showPos(cur) << " and len: " << sel_len);
        bv->putSelectionAt(DocIterator(cur), sel_len, !opt.forward);
        bv->processUpdateFlags(Update::Force);
        return 1;
@@ -4823,7 +4886,7 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions & opt)
                                                MathData md = cs.cell();
                                                int len = -1;
                                                MathData::const_iterator it_end = md.end();
-                                               MathData md2;
+                                               MathData md2(cur.buffer());
                                                // Start the check with one character before actual cursor position
                                                for (MathData::const_iterator it = md.begin() + cs.pos() - 1;
                                                    it != it_end; ++it)
@@ -4883,7 +4946,7 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions & opt)
                // Should never happen, maybe LASSERT() here?
                pos_len = cur.lastpos() - cur.pos();
        }
-       LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Putting selection at cur=" << cur << " with len: " << pos_len);
+       LYXERR(Debug::FINDVERBOSE|Debug::FIND, "Putting selection at cur=" << showPos(cur) << " with len: " << pos_len);
        bv->putSelectionAt(cur, pos_len, !opt.forward);
 
        return true;