X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxfind.cpp;h=86cf64d44a55320f73c3d609c563d954e5031de1;hb=bca1b63d89e27b31b089ab48c63368640084b3a6;hp=ab20921d0e73cc93c6a4ca798f9630f8eccb825f;hpb=96f9c8fb19a75e35e274e9621ad0207e2d0662ca;p=lyx.git diff --git a/src/lyxfind.cpp b/src/lyxfind.cpp index ab20921d0e..86cf64d44a 100644 --- a/src/lyxfind.cpp +++ b/src/lyxfind.cpp @@ -31,6 +31,7 @@ #include "Paragraph.h" #include "Text.h" #include "Encoding.h" +#include "Language.h" #include "frontends/Application.h" #include "frontends/alert.h" @@ -49,7 +50,7 @@ #include "support/lstrings.h" #include "support/textutils.h" -#include +#include #include //#define ResultsDebug @@ -71,8 +72,9 @@ using namespace lyx::support; namespace lyx { -typedef map AccentsMap; -static AccentsMap accents = map(); +typedef unordered_map AccentsMap; +typedef unordered_map::const_iterator AccentsIterator; +static AccentsMap accents = unordered_map(); // Helper class for deciding what should be ignored class IgnoreFormats { @@ -100,7 +102,11 @@ class IgnoreFormats { /// bool getLanguage() const { return ignoreLanguage_; } /// - void setIgnoreFormat(string const & type, bool value); + bool getDeleted() const { return ignoreDeleted_; } + /// + void setIgnoreDeleted(bool value); + /// + void setIgnoreFormat(string const & type, bool value, bool fromUser = true); private: /// @@ -123,16 +129,23 @@ private: bool ignoreColor_ = false; /// bool ignoreLanguage_ = false; + bool userSelectedIgnoreLanguage_ = false; + /// + bool ignoreDeleted_ = true; }; - -void IgnoreFormats::setIgnoreFormat(string const & type, bool value) +void IgnoreFormats::setIgnoreFormat(string const & type, bool value, bool fromUser) { if (type == "color") { ignoreColor_ = value; } else if (type == "language") { - ignoreLanguage_ = value; + if (fromUser) { + userSelectedIgnoreLanguage_ = value; + ignoreLanguage_ = value; + } + else + ignoreLanguage_ = (value || userSelectedIgnoreLanguage_); } else if (type == "sectioning") { ignoreSectioning_ = value; @@ -161,24 +174,27 @@ void IgnoreFormats::setIgnoreFormat(string const & type, bool value) else if (type == "strike") { ignoreStrikeOut_ = value; } + else if (type == "deleted") { + ignoreDeleted_ = value; + } } // The global variable that can be changed from outside IgnoreFormats ignoreFormats; -void setIgnoreFormat(string const & type, bool value) +void setIgnoreFormat(string const & type, bool value, bool fromUser) { - ignoreFormats.setIgnoreFormat(type, value); + ignoreFormats.setIgnoreFormat(type, value, fromUser); } namespace { -bool parse_bool(docstring & howto) +bool parse_bool(docstring & howto, bool const defvalue = false) { if (howto.empty()) - return false; + return defvalue; docstring var; howto = split(howto, var, ' '); return var == "1"; @@ -209,24 +225,33 @@ private: }; -int findForward(DocIterator & cur, MatchString const & match, - bool find_del = true) +int findForward(DocIterator & cur, DocIterator const endcur, + MatchString const & match, + bool find_del = true, bool onlysel = false) { - for (; cur; cur.forwardChar()) + for (; cur; cur.forwardChar()) { + if (onlysel && endcur.pit() == cur.pit() + && endcur.idx() == cur.idx() && endcur.pos() < cur.pos()) + break; if (cur.inTexted()) { int len = match(cur.paragraph(), cur.pos(), find_del); if (len > 0) return len; } + } return 0; } -int findBackwards(DocIterator & cur, MatchString const & match, - bool find_del = true) +int findBackwards(DocIterator & cur, DocIterator const endcur, + MatchString const & match, + bool find_del = true, bool onlysel = false) { while (cur) { cur.backwardChar(); + if (onlysel && endcur.pit() == cur.pit() + && endcur.idx() == cur.idx() && endcur.pos() > cur.pos()) + break; if (cur.inTexted()) { int len = match(cur.paragraph(), cur.pos(), find_del); if (len > 0) @@ -246,38 +271,87 @@ bool searchAllowed(docstring const & str) return true; } +} // namespace + bool findOne(BufferView * bv, docstring const & searchstr, bool case_sens, bool whole, bool forward, - bool find_del = true, bool check_wrap = false) + bool find_del, bool check_wrap, bool const auto_wrap, + bool instant, bool onlysel) { + // Clean up previous selections with empty searchstr on instant + if (searchstr.empty() && instant) { + if (bv->cursor().selection()) { + bv->setCursor(bv->cursor().selectionBegin()); + bv->clearSelection(); + } + return true; + } + if (!searchAllowed(searchstr)) return false; + DocIterator const endcur = forward ? bv->cursor().selectionEnd() : bv->cursor().selectionBegin(); + + if (onlysel && bv->cursor().selection()) { + docstring const matchstring = bv->cursor().selectionAsString(false); + docstring const lcmatchsting = support::lowercase(matchstring); + if (matchstring == searchstr || (!case_sens && lcmatchsting == lowercase(searchstr))) { + docstring q = _("The search string matches the selection, and search is limited to selection.\n" + "Continue search outside?"); + int search_answer = frontend::Alert::prompt(_("Search outside selection?"), + q, 0, 1, _("&Yes"), _("&No")); + if (search_answer == 0) { + bv->clearSelection(); + if (findOne(bv, searchstr, case_sens, whole, forward, + find_del, check_wrap, auto_wrap, false, false)) + return true; + } + return false; + } + } + DocIterator cur = forward - ? bv->cursor().selectionEnd() - : bv->cursor().selectionBegin(); + ? ((instant || onlysel) ? bv->cursor().selectionBegin() : bv->cursor().selectionEnd()) + : ((instant || onlysel) ? bv->cursor().selectionEnd() : bv->cursor().selectionBegin()); MatchString const match(searchstr, case_sens, whole); int match_len = forward - ? findForward(cur, match, find_del) - : findBackwards(cur, match, find_del); + ? findForward(cur, endcur, match, find_del, onlysel) + : findBackwards(cur, endcur, match, find_del, onlysel); if (match_len > 0) bv->putSelectionAt(cur, match_len, !forward); + else if (onlysel) { + docstring q = _("The search string was not found within the selection.\n" + "Continue search outside?"); + int search_answer = frontend::Alert::prompt(_("Search outside selection?"), + q, 0, 1, _("&Yes"), _("&No")); + if (search_answer == 0) { + bv->clearSelection(); + if (findOne(bv, searchstr, case_sens, whole, forward, + find_del, check_wrap, auto_wrap, false, false)) + return true; + } + return false; + } else if (check_wrap) { DocIterator cur_orig(bv->cursor()); - docstring q; - if (forward) - q = _("End of file reached while searching forward.\n" - "Continue searching from the beginning?"); - else - q = _("Beginning of file reached while searching backward.\n" - "Continue searching from the end?"); - int wrap_answer = frontend::Alert::prompt(_("Wrap search?"), - q, 0, 1, _("&Yes"), _("&No")); - if (wrap_answer == 0) { + bool wrap = auto_wrap; + if (!auto_wrap) { + docstring q; + if (forward) + q = _("End of file reached while searching forward.\n" + "Continue searching from the beginning?"); + else + q = _("Beginning of file reached while searching backward.\n" + "Continue searching from the end?"); + int wrap_answer = frontend::Alert::prompt(_("Wrap search?"), + q, 0, 1, _("&Yes"), _("&No")); + wrap = wrap_answer == 0; + } + if (wrap) { if (forward) { bv->cursor().clear(); bv->cursor().push_back(CursorSlice(bv->buffer().inset())); @@ -285,8 +359,15 @@ bool findOne(BufferView * bv, docstring const & searchstr, bv->cursor().setCursor(doc_iterator_end(&bv->buffer())); bv->cursor().backwardPos(); } + if (auto_wrap) { + docstring const msg = forward + ? _("Search reached end of document, continuing from beginning.") + : _("Search reached beginning of document, continuing from end."); + bv->message(msg); + } bv->clearSelection(); - if (findOne(bv, searchstr, case_sens, whole, forward, find_del, false)) + if (findOne(bv, searchstr, case_sens, whole, forward, + find_del, false, false, false, false)) return true; } bv->cursor().setCursor(cur_orig); @@ -297,16 +378,20 @@ bool findOne(BufferView * bv, docstring const & searchstr, } +namespace { + int replaceAll(BufferView * bv, docstring const & searchstr, docstring const & replacestr, - bool case_sens, bool whole) + bool case_sens, bool whole, bool onlysel) { Buffer & buf = bv->buffer(); if (!searchAllowed(searchstr) || buf.isReadonly()) return 0; - DocIterator cur_orig(bv->cursor()); + DocIterator startcur = bv->cursor().selectionBegin(); + DocIterator endcur = bv->cursor().selectionEnd(); + bool const had_selection = bv->cursor().selection(); MatchString const match(searchstr, case_sens, whole); int num = 0; @@ -316,29 +401,53 @@ int replaceAll(BufferView * bv, Cursor cur(*bv); cur.setCursor(doc_iterator_begin(&buf)); - int match_len = findForward(cur, match, false); + int match_len = findForward(cur, endcur, match, false, onlysel); while (match_len > 0) { // Backup current cursor position and font. pos_type const pos = cur.pos(); Font const font = cur.paragraph().getFontSettings(buf.params(), pos); cur.recordUndo(); - int striked = ssize - + int ct_deleted_text = ssize - cur.paragraph().eraseChars(pos, pos + match_len, buf.params().track_changes); cur.paragraph().insert(pos, replacestr, font, Change(buf.params().track_changes ? Change::INSERTED : Change::UNCHANGED)); - for (int i = 0; i < rsize + striked; ++i) - cur.forwardChar(); + for (int i = 0; i < rsize + ct_deleted_text + && cur.pos() < cur.lastpos(); ++i) + cur.forwardPos(); + if (onlysel && cur.pit() == endcur.pit() && cur.idx() == endcur.idx()) { + // Adjust end of selection for replace-all in selection + if (rsize > ssize) { + int const offset = rsize - ssize; + for (int i = 0; i < offset + ct_deleted_text + && endcur.pos() < endcur.lastpos(); ++i) + endcur.forwardPos(); + } else { + int const offset = ssize - rsize; + for (int i = 0; i < offset && endcur.pos() > 0; ++i) + endcur.backwardPos(); + for (int i = 0; i < ct_deleted_text + && endcur.pos() < endcur.lastpos(); ++i) + endcur.forwardPos(); + } + } ++num; - match_len = findForward(cur, match, false); + match_len = findForward(cur, endcur, match, false, onlysel); } bv->putSelectionAt(doc_iterator_begin(&buf), 0, false); - cur_orig.fixIfBroken(); - bv->setCursor(cur_orig); + startcur.fixIfBroken(); + bv->setCursor(startcur); + + // Reset selection, accounting for changes in selection + if (had_selection) { + endcur.fixIfBroken(); + bv->cursor().resetAnchor(); + bv->setCursorSelectionTo(endcur); + } return num; } @@ -361,13 +470,15 @@ int replaceAll(BufferView * bv, // whether anything at all was done. pair replaceOne(BufferView * bv, docstring searchstr, docstring const & replacestr, bool case_sens, - bool whole, bool forward, bool findnext) + bool whole, bool forward, bool findnext, bool wrap, + bool onlysel) { Cursor & cur = bv->cursor(); - if (!cur.selection()) { + if (!cur.selection() || onlysel) { // no selection, non-empty search string: find it if (!searchstr.empty()) { - bool const found = findOne(bv, searchstr, case_sens, whole, forward, true, findnext); + bool const found = findOne(bv, searchstr, case_sens, whole, + forward, true, findnext, wrap, false, onlysel); return make_pair(found, 0); } // empty search string @@ -396,7 +507,8 @@ pair replaceOne(BufferView * bv, docstring searchstr, // no selection or current selection is not search word: // just find the search word if (!have_selection || !match) { - bool const found = findOne(bv, searchstr, case_sens, whole, forward, true, findnext); + bool const found = findOne(bv, searchstr, case_sens, whole, forward, + true, findnext, wrap, false, onlysel); return make_pair(found, 0); } @@ -412,7 +524,8 @@ pair replaceOne(BufferView * bv, docstring searchstr, cur.pos() = cur.lastpos()); } if (findnext) - findOne(bv, searchstr, case_sens, whole, forward, false, findnext); + findOne(bv, searchstr, case_sens, whole, + forward, false, findnext, wrap, false, onlysel); return make_pair(true, 1); } @@ -421,13 +534,18 @@ pair replaceOne(BufferView * bv, docstring searchstr, docstring const find2string(docstring const & search, - bool casesensitive, bool matchword, bool forward) + bool casesensitive, bool matchword, + bool forward, bool wrap, bool instant, + bool onlysel) { odocstringstream ss; ss << search << '\n' << int(casesensitive) << ' ' << int(matchword) << ' ' - << int(forward); + << int(forward) << ' ' + << int(wrap) << ' ' + << int(instant) << ' ' + << int(onlysel); return ss.str(); } @@ -435,7 +553,8 @@ docstring const find2string(docstring const & search, docstring const replace2string(docstring const & replace, docstring const & search, bool casesensitive, bool matchword, - bool all, bool forward, bool findnext) + bool all, bool forward, bool findnext, + bool wrap, bool onlysel) { odocstringstream ss; ss << replace << '\n' @@ -444,29 +563,56 @@ docstring const replace2string(docstring const & replace, << int(matchword) << ' ' << int(all) << ' ' << int(forward) << ' ' - << int(findnext); + << int(findnext) << ' ' + << int(wrap) << ' ' + << int(onlysel); return ss.str(); } -bool lyxfind(BufferView * bv, FuncRequest const & ev) +docstring const string2find(docstring const & argument, + bool &casesensitive, + bool &matchword, + bool &forward, + bool &wrap, + bool &instant, + bool &onlysel) { - if (!bv || ev.action() != LFUN_WORD_FIND) - return false; - - //lyxerr << "find called, cmd: " << ev << endl; - // data is of the form // " - // " + // " docstring search; - docstring howto = split(ev.argument(), search, '\n'); + docstring howto = split(argument, search, '\n'); - bool casesensitive = parse_bool(howto); - bool matchword = parse_bool(howto); - bool forward = parse_bool(howto); + casesensitive = parse_bool(howto); + matchword = parse_bool(howto); + forward = parse_bool(howto, true); + wrap = parse_bool(howto); + instant = parse_bool(howto); + onlysel = parse_bool(howto); + + return search; +} - return findOne(bv, search, casesensitive, matchword, forward, false, true); + +bool lyxfind(BufferView * bv, FuncRequest const & ev) +{ + if (!bv || ev.action() != LFUN_WORD_FIND) + return false; + + //lyxerr << "find called, cmd: " << ev << endl; + bool casesensitive; + bool matchword; + bool forward; + bool wrap; + bool instant; + bool onlysel; + + docstring search = string2find(ev.argument(), casesensitive, + matchword, forward, wrap, instant, onlysel); + + return findOne(bv, search, casesensitive, matchword, forward, + false, true, wrap, instant, onlysel); } @@ -478,7 +624,7 @@ bool lyxreplace(BufferView * bv, FuncRequest const & ev) // data is of the form // " // - // " + // " docstring search; docstring rplc; docstring howto = split(ev.argument(), rplc, '\n'); @@ -487,18 +633,26 @@ bool lyxreplace(BufferView * bv, FuncRequest const & ev) bool casesensitive = parse_bool(howto); bool matchword = parse_bool(howto); bool all = parse_bool(howto); - bool forward = parse_bool(howto); - bool findnext = howto.empty() ? true : parse_bool(howto); + bool forward = parse_bool(howto, true); + bool findnext = parse_bool(howto, true); + bool wrap = parse_bool(howto); + bool onlysel = parse_bool(howto); + + if (!bv->cursor().selection()) + // only selection only makes sense with selection + onlysel = false; bool update = false; int replace_count = 0; if (all) { - replace_count = replaceAll(bv, search, rplc, casesensitive, matchword); + replace_count = replaceAll(bv, search, rplc, casesensitive, + matchword, onlysel); update = replace_count > 0; } else { pair rv = - replaceOne(bv, search, rplc, casesensitive, matchword, forward, findnext); + replaceOne(bv, search, rplc, casesensitive, matchword, + forward, findnext, wrap, onlysel); update = rv.first; replace_count = rv.second; } @@ -506,15 +660,19 @@ bool lyxreplace(BufferView * bv, FuncRequest const & ev) Buffer const & buf = bv->buffer(); if (!update) { // emit message signal. - buf.message(_("String not found.")); + if (onlysel) + buf.message(_("String not found in selection.")); + else + buf.message(_("String not found.")); } else { if (replace_count == 0) { buf.message(_("String found.")); } else if (replace_count == 1) { buf.message(_("String has been replaced.")); } else { - docstring const str = - bformat(_("%1$d strings have been replaced."), replace_count); + docstring const str = onlysel + ? bformat(_("%1$d strings have been replaced in the selection."), replace_count) + : bformat(_("%1$d strings have been replaced."), replace_count); buf.message(str); } } @@ -640,101 +798,6 @@ namespace { typedef vector > Escapes; -/// A map of symbols and their escaped equivalent needed within a regex. -/// @note Beware of order -/* -Escapes const & get_regexp_escapes() -{ - typedef std::pair P; - - static Escapes escape_map; - if (escape_map.empty()) { - escape_map.push_back(P("$", "_x_$")); - escape_map.push_back(P("{", "_x_{")); - escape_map.push_back(P("}", "_x_}")); - escape_map.push_back(P("[", "_x_[")); - escape_map.push_back(P("]", "_x_]")); - escape_map.push_back(P("(", "_x_(")); - escape_map.push_back(P(")", "_x_)")); - escape_map.push_back(P("+", "_x_+")); - escape_map.push_back(P("*", "_x_*")); - escape_map.push_back(P(".", "_x_.")); - escape_map.push_back(P("\\", "(?:\\\\|\\\\backslash)")); - escape_map.push_back(P("~", "(?:\\\\textasciitilde|\\\\sim)")); - escape_map.push_back(P("^", "(?:\\^|\\\\textasciicircum\\{\\}|\\\\textasciicircum|\\\\mathcircumflex)")); - escape_map.push_back(P("_x_", "\\")); - } - return escape_map; -} -*/ - -/// A map of lyx escaped strings and their unescaped equivalent. -/* -Escapes const & get_lyx_unescapes() -{ - typedef std::pair P; - - static Escapes escape_map; - if (escape_map.empty()) { - escape_map.push_back(P("\\%", "%")); - escape_map.push_back(P("\\{", "{")); - escape_map.push_back(P("\\}", "}")); - escape_map.push_back(P("\\mathcircumflex ", "^")); - escape_map.push_back(P("\\mathcircumflex", "^")); - escape_map.push_back(P("\\backslash ", "\\")); - escape_map.push_back(P("\\backslash", "\\")); - escape_map.push_back(P("\\sim ", "~")); - escape_map.push_back(P("\\sim", "~")); - } - return escape_map; -} -*/ - -/// A map of escapes turning a regexp matching text to one matching latex. -/* -Escapes const & get_regexp_latex_escapes() -{ - typedef std::pair P; - - static Escapes escape_map; - if (escape_map.empty()) { - escape_map.push_back(P("\\\\", "(?:\\\\\\\\|\\\\backslash|\\\\textbackslash\\{\\}|\\\\textbackslash)")); - escape_map.push_back(P("(first << " as " << it->second); - unsigned int pos = 0; - while (pos < s.length() && (pos = s.find(it->first, pos)) < s.length()) { - s.replace(pos, it->first.length(), it->second); - LYXERR(Debug::FIND, "After escape: " << s); - pos += it->second.length(); -// LYXERR(Debug::FIND, "pos: " << pos); - } - } - LYXERR(Debug::FIND, "Escaped : '" << s << "'"); - return s; -} -*/ - - string string2regex(string in) { static std::regex specialChars { R"([-[\]{}()*+?.,\^$|#\s\$\\])" }; @@ -780,12 +843,10 @@ string correctRegex(string t, bool withformat) if (sub.str(4) == "backslash") { replace = "\\"; if (withformat) { - // tranforms '\backslash \{' into '\{' + // transforms '\backslash \{' into '\{' // and '\{' into '{' - sregex_iterator it2 = it; - ++it2; - smatch sub2 = *it2; - if ((sub2.str(3) == "{") || (sub2.str(3) == "}")) { + string next = t.substr(sub.position(2) + sub.str(2).length(), 2); + if ((next == "\\{") || (next == "\\}")) { replace = ""; backslashed = true; } @@ -859,62 +920,6 @@ bool regex_replace(string const & s, string & t, string const & searchstr, return rv; } -#if 0 -/** Checks if supplied string segment is well-formed from the standpoint of matching open-closed braces. - ** - ** Verify that closed braces exactly match open braces. This avoids that, for example, - ** \frac{.*}{x} matches \frac{x+\frac{y}{x}}{z} with .* being 'x+\frac{y'. - ** - ** @param unmatched - ** Number of open braces that must remain open at the end for the verification to succeed. - **/ -#if QTSEARCH -bool braces_match(QString const & beg, - int unmatched = 0) -#else -bool braces_match(string const & beg, - int unmatched = 0) -#endif -{ - int open_pars = 0; -#if QTSEARCH - LYXERR(Debug::FIND, "Checking " << unmatched << " unmatched braces in '" << beg.toStdString() << "'"); -#else - LYXERR(Debug::FIND, "Checking " << unmatched << " unmatched braces in '" << beg << "'"); -#endif - int lastidx = beg.size(); - for (int i=0; i < lastidx; ++i) { - // Skip escaped braces in the count -#if QTSEARCH - QChar c = beg.at(i); -#else - char c = beg.at(i); -#endif - if (c == '\\') { - ++i; - if (i >= lastidx) - break; - } else if (c == '{') { - ++open_pars; - } else if (c == '}') { - if (open_pars == 0) { - LYXERR(Debug::FIND, "Found unmatched closed brace"); - return false; - } else - --open_pars; - } - } - if (open_pars != unmatched) { - LYXERR(Debug::FIND, "Found " << open_pars - << " instead of " << unmatched - << " unmatched open braces at the end of count"); - return false; - } - LYXERR(Debug::FIND, "Braces match as expected"); - return true; -} -#endif - class MatchResult { public: enum range { @@ -930,21 +935,19 @@ public: int pos_len; int searched_size; vector result = vector (); - MatchResult(int len = 0): match_len(len),match_prefix(0),match2end(0), pos(0),leadsize(0),pos_len(-1),searched_size(0) {}; + MatchResult(int len = 0): match_len(len),match_prefix(0),match2end(0), pos(0),leadsize(0),pos_len(-1),searched_size(0) {} }; static MatchResult::range interpretMatch(MatchResult &oldres, MatchResult &newres) { - int range = oldres.match_len; - if (range > 0) range--; - if (newres.match2end < oldres.match2end - oldres.match_len) + if (newres.match2end < oldres.match2end) return MatchResult::newIsTooFar; if (newres.match_len < oldres.match_len) return MatchResult::newIsTooFar; - if ((newres.match_len == oldres.match_len) && - (newres.match2end < oldres.match2end + range) && - (newres.match2end > oldres.match2end - range)) { - return MatchResult::newIsBetter; + + if (newres.match_len == oldres.match_len) { + if (newres.match2end == oldres.match2end) + return MatchResult::newIsBetter; } return MatchResult::newIsInvalid; } @@ -1052,7 +1055,10 @@ static docstring buffer_to_latex(Buffer & buffer) runparams.linelen = 10000; //lyxrc.plaintext_linelen; // No side effect of file copying and image conversion runparams.dryrun = true; - runparams.for_search = true; + if (ignoreFormats.getDeleted()) + runparams.for_searchAdv = OutputParams::SearchWithoutDeleted; + else + runparams.for_searchAdv = OutputParams::SearchWithDeleted; pit_type const endpit = buffer.paragraphs().size(); for (pit_type pit = 0; pit != endpit; ++pit) { TeXOnePar(buffer, buffer.text(), pit, os, runparams); @@ -1074,21 +1080,28 @@ static docstring stringifySearchBuffer(Buffer & buffer, FindAndReplaceOptions co runparams.flavor = Flavor::XeTeX; runparams.linelen = 10000; //lyxrc.plaintext_linelen; runparams.dryrun = true; - runparams.for_search = true; + int option = AS_STR_INSETS |AS_STR_PLAINTEXT; + if (ignoreFormats.getDeleted()) { + option |= AS_STR_SKIPDELETE; + runparams.for_searchAdv = OutputParams::SearchWithoutDeleted; + } + else { + runparams.for_searchAdv = OutputParams::SearchWithDeleted; + } for (pos_type pit = pos_type(0); pit < (pos_type)buffer.paragraphs().size(); ++pit) { Paragraph const & par = buffer.paragraphs().at(pit); LYXERR(Debug::FIND, "Adding to search string: '" << par.asString(pos_type(0), par.size(), - AS_STR_INSETS | AS_STR_SKIPDELETE | AS_STR_PLAINTEXT, + option, &runparams) << "'"); str += par.asString(pos_type(0), par.size(), - AS_STR_INSETS | AS_STR_SKIPDELETE | AS_STR_PLAINTEXT, + option, &runparams); } // Even in ignore-format we have to remove "\text{}, \lyxmathsym{}" parts string t = to_utf8(str); - while (regex_replace(t, t, "\\\\(text|lyxmathsym)\\{([^\\}]*)\\}", "$2")); + while (regex_replace(t, t, "\\\\(text|lyxmathsym|ensuremath)\\{([^\\}]*)\\}", "$2")); str = from_utf8(t); } return str; @@ -1235,7 +1248,7 @@ class KeyInfo { class Border { public: - Border(int l=0, int u=0) : low(l), upper(u) {}; + Border(int l=0, int u=0) : low(l), upper(u) {} int low; int upper; }; @@ -1480,6 +1493,223 @@ static string getutf8(unsigned uchar) return(ret); } +static void addAccents(string latex_in, string unicode_out) +{ + latex_in = latex_in.substr(1); + AccentsIterator it_ac = accents.find(latex_in); + if (it_ac == accents.end()) { + accents[latex_in] = unicode_out; + } + else { + LYXERR0("Key " << latex_in << " already set"); + } +} + +void static fillMissingUnicodesymbols() +{ + addAccents("\\textyen", getutf8(0x00a5)); + addAccents("\\yen", getutf8(0x00a5)); + addAccents("\\textsection", getutf8(0x00a7)); + addAccents("\\mathsection", getutf8(0x00a7)); + addAccents("\\textlnot", getutf8(0x00ac)); + addAccents("\\neg", getutf8(0x00ac)); + addAccents("\\textpm", getutf8(0x00b1)); + addAccents("\\pm", getutf8(0x00b1)); + addAccents("\\textparagraph", getutf8(0x00b6)); + addAccents("\\mathparagraph", getutf8(0x00b6)); + addAccents("\\textperiodcentered", getutf8(0x00b7)); + addAccents("\\texttimes", getutf8(0x00d7)); + addAccents("\\times", getutf8(0x00d7)); + addAccents("\\dh", getutf8(0x00f0)); + addAccents("\\eth", getutf8(0x00f0)); + addAccents("\\textdiv", getutf8(0x00f7)); + addAccents("\\div", getutf8(0x00f7)); + addAccents("\\o", getutf8(0x00f8)); + addAccents("\\j", getutf8(0x0237)); + addAccents("\\textalpha", getutf8(0x03b1)); + addAccents("\\alpha", getutf8(0x03b1)); + addAccents("\\textbeta", getutf8(0x03b2)); + addAccents("\\beta", getutf8(0x03b2)); + addAccents("\\textgamma", getutf8(0x03b3)); + addAccents("\\gamma", getutf8(0x03b3)); + addAccents("\\textdelta", getutf8(0x03b4)); + addAccents("\\delta", getutf8(0x03b4)); + addAccents("\\textepsilon", getutf8(0x03b5)); + addAccents("\\varepsilon", getutf8(0x03b5)); + addAccents("\\textzeta", getutf8(0x03b6)); + addAccents("\\zeta", getutf8(0x03b6)); + addAccents("\\texteta", getutf8(0x03b7)); + addAccents("\\eta", getutf8(0x03b7)); + addAccents("\\texttheta", getutf8(0x03b8)); + addAccents("\\theta", getutf8(0x03b8)); + addAccents("\\textiota", getutf8(0x03b9)); + addAccents("\\iota", getutf8(0x03b9)); + addAccents("\\textkappa", getutf8(0x03ba)); + addAccents("\\kappa", getutf8(0x03ba)); + addAccents("\\textlambda", getutf8(0x03bb)); + addAccents("\\lambda", getutf8(0x03bb)); + addAccents("\\textmu", getutf8(0x03bc)); + addAccents("\\mu", getutf8(0x03bc)); + addAccents("\\textnu", getutf8(0x03bd)); + addAccents("\\nu", getutf8(0x03bd)); + addAccents("\\textxi", getutf8(0x03be)); + addAccents("\\xi", getutf8(0x03be)); + addAccents("\\textpi", getutf8(0x03c0)); + addAccents("\\pi", getutf8(0x03c0)); + addAccents("\\textrho", getutf8(0x03c1)); + addAccents("\\rho", getutf8(0x03c1)); + addAccents("\\textfinalsigma", getutf8(0x03c2)); + addAccents("\\varsigma", getutf8(0x03c2)); + addAccents("\\textsigma", getutf8(0x03c3)); + addAccents("\\sigma", getutf8(0x03c3)); + addAccents("\\texttau", getutf8(0x03c4)); + addAccents("\\tau", getutf8(0x03c4)); + addAccents("\\textupsilon", getutf8(0x03c5)); + addAccents("\\upsilon", getutf8(0x03c5)); + addAccents("\\textphi", getutf8(0x03c6)); + addAccents("\\varphi", getutf8(0x03c6)); + addAccents("\\textchi", getutf8(0x03c7)); + addAccents("\\chi", getutf8(0x03c7)); + addAccents("\\textpsi", getutf8(0x03c8)); + addAccents("\\psi", getutf8(0x03c8)); + addAccents("\\textomega", getutf8(0x03c9)); + addAccents("\\omega", getutf8(0x03c9)); + addAccents("\\textdigamma", getutf8(0x03dd)); + addAccents("\\digamma", getutf8(0x03dd)); + addAccents("\\hebalef", getutf8(0x05d0)); + addAccents("\\aleph", getutf8(0x05d0)); + addAccents("\\hebbet", getutf8(0x05d1)); + addAccents("\\beth", getutf8(0x05d1)); + addAccents("\\hebgimel", getutf8(0x05d2)); + addAccents("\\gimel", getutf8(0x05d2)); + addAccents("\\hebdalet", getutf8(0x05d3)); + addAccents("\\daleth", getutf8(0x05d3)); + // Thai characters + addAccents("\\thaiKoKai", getutf8(0x0e01)); + addAccents("\\thaiKhoKhai", getutf8(0x0e02)); + addAccents("\\thaiKhoKhuat", getutf8(0x0e03)); + addAccents("\\thaiKhoKhwai", getutf8(0x0e04)); + addAccents("\\thaiKhoKhon", getutf8(0x0e05)); + addAccents("\\thaiKhoRakhang", getutf8(0x0e06)); + addAccents("\\thaiNgoNgu", getutf8(0x0e07)); + addAccents("\\thaiChoChan", getutf8(0x0e08)); + addAccents("\\thaiChoChing", getutf8(0x0e09)); + addAccents("\\thaiChoChang", getutf8(0x0e0a)); + addAccents("\\thaiSoSo", getutf8(0x0e0b)); + addAccents("\\thaiChoChoe", getutf8(0x0e0c)); + addAccents("\\thaiYoYing", getutf8(0x0e0d)); + addAccents("\\thaiDoChada", getutf8(0x0e0e)); + addAccents("\\thaiToPatak", getutf8(0x0e0f)); + addAccents("\\thaiThoThan", getutf8(0x0e10)); + addAccents("\\thaiThoNangmontho", getutf8(0x0e11)); + addAccents("\\thaiThoPhuthao", getutf8(0x0e12)); + addAccents("\\thaiNoNen", getutf8(0x0e13)); + addAccents("\\thaiDoDek", getutf8(0x0e14)); + addAccents("\\thaiToTao", getutf8(0x0e15)); + addAccents("\\thaiThoThung", getutf8(0x0e16)); + addAccents("\\thaiThoThahan", getutf8(0x0e17)); + addAccents("\\thaiThoThong", getutf8(0x0e18)); + addAccents("\\thaiNoNu", getutf8(0x0e19)); + addAccents("\\thaiBoBaimai", getutf8(0x0e1a)); + addAccents("\\thaiPoPla", getutf8(0x0e1b)); + addAccents("\\thaiPhoPhung", getutf8(0x0e1c)); + addAccents("\\thaiFoFa", getutf8(0x0e1d)); + addAccents("\\thaiPhoPhan", getutf8(0x0e1e)); + addAccents("\\thaiFoFan", getutf8(0x0e1f)); + addAccents("\\thaiPhoSamphao", getutf8(0x0e20)); + addAccents("\\thaiMoMa", getutf8(0x0e21)); + addAccents("\\thaiYoYak", getutf8(0x0e22)); + addAccents("\\thaiRoRua", getutf8(0x0e23)); + addAccents("\\thaiRu", getutf8(0x0e24)); + addAccents("\\thaiLoLing", getutf8(0x0e25)); + addAccents("\\thaiLu", getutf8(0x0e26)); + addAccents("\\thaiWoWaen", getutf8(0x0e27)); + addAccents("\\thaiSoSala", getutf8(0x0e28)); + addAccents("\\thaiSoRusi", getutf8(0x0e29)); + addAccents("\\thaiSoSua", getutf8(0x0e2a)); + addAccents("\\thaiHoHip", getutf8(0x0e2b)); + addAccents("\\thaiLoChula", getutf8(0x0e2c)); + addAccents("\\thaiOAng", getutf8(0x0e2d)); + addAccents("\\thaiHoNokhuk", getutf8(0x0e2e)); + addAccents("\\thaiPaiyannoi", getutf8(0x0e2f)); + addAccents("\\thaiSaraA", getutf8(0x0e30)); + addAccents("\\thaiMaiHanakat", getutf8(0x0e31)); + addAccents("\\thaiSaraAa", getutf8(0x0e32)); + addAccents("\\thaiSaraAm", getutf8(0x0e33)); + addAccents("\\thaiSaraI", getutf8(0x0e34)); + addAccents("\\thaiSaraIi", getutf8(0x0e35)); + addAccents("\\thaiSaraUe", getutf8(0x0e36)); + addAccents("\\thaiSaraUee", getutf8(0x0e37)); + addAccents("\\thaiSaraU", getutf8(0x0e38)); + addAccents("\\thaiSaraUu", getutf8(0x0e39)); + addAccents("\\thaiPhinthu", getutf8(0x0e3a)); + addAccents("\\thaiSaraE", getutf8(0x0e40)); + addAccents("\\thaiSaraAe", getutf8(0x0e41)); + addAccents("\\thaiSaraO", getutf8(0x0e42)); + addAccents("\\thaiSaraAiMaimuan", getutf8(0x0e43)); + addAccents("\\thaiSaraAiMaimalai", getutf8(0x0e44)); + addAccents("\\thaiLakkhangyao", getutf8(0x0e45)); + addAccents("\\thaiMaiyamok", getutf8(0x0e46)); + addAccents("\\thaiMaitaikhu", getutf8(0x0e47)); + addAccents("\\thaiMaiEk", getutf8(0x0e48)); + addAccents("\\thaiMaiTho", getutf8(0x0e49)); + addAccents("\\thaiMaiTri", getutf8(0x0e4a)); + addAccents("\\thaiMaiChattawa", getutf8(0x0e4b)); + addAccents("\\thaiThanthakhat", getutf8(0x0e4c)); + addAccents("\\thaiNikhahit", getutf8(0x0e4d)); + addAccents("\\thaiYamakkan", getutf8(0x0e4e)); + addAccents("\\thaiFongman", getutf8(0x0e4f)); + addAccents("\\thaizero", getutf8(0x0e50)); + addAccents("\\thaione", getutf8(0x0e51)); + addAccents("\\thaitwo", getutf8(0x0e52)); + addAccents("\\thaithree", getutf8(0x0e53)); + addAccents("\\thaifour", getutf8(0x0e54)); + addAccents("\\thaifive", getutf8(0x0e55)); + addAccents("\\thaisix", getutf8(0x0e56)); + addAccents("\\thaiseven", getutf8(0x0e57)); + addAccents("\\thaieight", getutf8(0x0e58)); + addAccents("\\thainine", getutf8(0x0e59)); + addAccents("\\thaiAngkhankhu", getutf8(0x0e5a)); + addAccents("\\thaiKhomut", getutf8(0x0e5b)); + + addAccents("\\dag", getutf8(0x2020)); + addAccents("\\dagger", getutf8(0x2020)); + addAccents("\\ddag", getutf8(0x2021)); + addAccents("\\ddagger", getutf8(0x2021)); + addAccents("\\textbullet", getutf8(0x2022)); + addAccents("\\bullet", getutf8(0x2022)); + addAccents("\\dots", getutf8(0x2026)); + addAccents("\\ldots", getutf8(0x2026)); + addAccents("\\textasciiacute", getutf8(0x2032)); + addAccents("\\prime", getutf8(0x2032)); + addAccents("\\textasciigrave", getutf8(0x2035)); + addAccents("\\backprime", getutf8(0x2035)); + addAccents("\\textasteriskcentered", getutf8(0x204e)); + addAccents("\\ast", getutf8(0x204e)); + addAccents("\\textmho", getutf8(0x2127)); + addAccents("\\mho", getutf8(0x2127)); + addAccents("\\textleftarrow", getutf8(0x2190)); + addAccents("\\leftarrow", getutf8(0x2190)); + addAccents("\\textuparrow", getutf8(0x2191)); + addAccents("\\uparrow", getutf8(0x2191)); + addAccents("\\textrightarrow", getutf8(0x2192)); + addAccents("\\rightarrow", getutf8(0x2192)); + addAccents("\\textdownarrow", getutf8(0x2193)); + addAccents("\\downarrow", getutf8(0x2193)); + addAccents("\\textglobrise", getutf8(0x2197)); + addAccents("\\nearrow", getutf8(0x2197)); + addAccents("\\textglobfall", getutf8(0x2198)); + addAccents("\\searrow", getutf8(0x2198)); + addAccents("\\textsurd", getutf8(0x221a)); + addAccents("\\surd", getutf8(0x221a)); + addAccents("\\textbigcircle", getutf8(0x25ef)); + addAccents("\\bigcirc", getutf8(0x25ef)); + addAccents("\\textlangle", getutf8(0x27e8)); + addAccents("\\langle", getutf8(0x27e8)); + addAccents("\\textrangle", getutf8(0x27e9)); + addAccents("\\rangle", getutf8(0x27e9)); +} + static void buildAccentsMap() { accents["imath"] = "ı"; @@ -1571,6 +1801,8 @@ static void buildAccentsMap() "ȂȃȆȇȊȋȎȏȒȓȖȗ"); // inverted breve buildaccent("slashed", "oO", "øØ"); // slashed + fillMissingUnicodesymbols(); // Add some still not handled entries contained in 'unicodesynbols' + // LYXERR0("Number of accents " << accents.size()); } /* @@ -1588,8 +1820,9 @@ void Intervall::removeAccents() for (sregex_iterator itacc(par.begin(), par.end(), accre), end; itacc != end; ++itacc) { sub = *itacc; string key = sub.str(1); - if (accents.find(key) != accents.end()) { - string val = accents[key]; + AccentsIterator it_ac = accents.find(key); + if (it_ac != accents.end()) { + string val = it_ac->second; size_t pos = sub.position(size_t(0)); for (size_t i = 0; i < val.size(); i++) { par[pos+i] = val[i]; @@ -1664,9 +1897,10 @@ int Intervall::nextNotIgnored(int start) const return start; } -typedef map KeysMap; +typedef unordered_map KeysMap; +typedef unordered_map::const_iterator KeysIterator; typedef vector< KeyInfo> Entries; -static KeysMap keys = map(); +static KeysMap keys = unordered_map(); class LatexInfo { private: @@ -1686,7 +1920,7 @@ class LatexInfo { buildKeys(isPatternString); entries_ = vector(); buildEntries(isPatternString); - }; + } int getFirstKey() { entidx_ = 0; if (entries_.empty()) { @@ -1707,7 +1941,7 @@ class LatexInfo { return -1; } return 0; - }; + } int getNextKey() { entidx_++; if (int(entries_.size()) > entidx_) { @@ -1716,7 +1950,7 @@ class LatexInfo { else { return -1; } - }; + } bool setNextKey(int idx) { if ((idx == entidx_) && (entidx_ >= 0)) { entidx_--; @@ -1724,7 +1958,7 @@ class LatexInfo { } else return false; - }; + } int find(int start, KeyInfo::KeyType keytype) const { if (start < 0) return -1; @@ -1735,20 +1969,20 @@ class LatexInfo { tmpIdx++; } return -1; - }; + } int process(ostringstream & os, KeyInfo const & actual); int dispatch(ostringstream & os, int previousStart, KeyInfo & actual); - // string show(int lastpos) { return interval.show(lastpos);}; - int nextNotIgnored(int start) { return interval_.nextNotIgnored(start);}; + // string show(int lastpos) { return interval.show(lastpos);} + int nextNotIgnored(int start) { return interval_.nextNotIgnored(start);} KeyInfo &getKeyInfo(int keyinfo) { static KeyInfo invalidInfo = KeyInfo(); if ((keyinfo < 0) || ( keyinfo >= int(entries_.size()))) return invalidInfo; else return entries_[keyinfo]; - }; - void setForDefaultLang(KeyInfo const & defLang) {interval_.setForDefaultLang(defLang);}; - void addIntervall(int low, int up) { interval_.addIntervall(low, up); }; + } + void setForDefaultLang(KeyInfo const & defLang) {interval_.setForDefaultLang(defLang);} + void addIntervall(int low, int up) { interval_.addIntervall(low, up); } }; @@ -1781,7 +2015,9 @@ class MathInfo { public: string wait; size_t mathEnd; + size_t mathpostfixsize; size_t mathStart; + size_t mathprefixsize; size_t mathSize; }; size_t actualIdx_; @@ -1790,15 +2026,17 @@ class MathInfo { MathInfo() { actualIdx_ = 0; } - void insert(string const & wait, size_t start, size_t end) { + void insert(string const & wait, size_t start, size_t prefixsize, size_t end, size_t postfixsize) { MathEntry m = MathEntry(); m.wait = wait; m.mathStart = start; - m.mathEnd = end; - m.mathSize = end - start; + m.mathprefixsize = prefixsize; + m.mathEnd = end + postfixsize; + m.mathpostfixsize = postfixsize; + m.mathSize = m.mathEnd - m.mathStart; entries_.push_back(m); } - bool empty() const { return entries_.empty(); }; + bool empty() const { return entries_.empty(); } size_t getEndPos() const { if (entries_.empty() || (actualIdx_ >= entries_.size())) { return 0; @@ -1811,6 +2049,18 @@ class MathInfo { } return entries_[actualIdx_].mathStart; } + size_t getPrefixSize() const { + if (entries_.empty() || (actualIdx_ >= entries_.size())) { + return 0; + } + return entries_[actualIdx_].mathprefixsize; + } + size_t getPostfixSize() const { + if (entries_.empty() || (actualIdx_ >= entries_.size())) { + return 0; + } + return entries_[actualIdx_].mathpostfixsize; + } size_t getFirstPos() { actualIdx_ = 0; return getStartPos(); @@ -1821,12 +2071,12 @@ class MathInfo { } return entries_[actualIdx_].mathSize; } - void incrEntry() { actualIdx_++; }; + void incrEntry() { actualIdx_++; } }; void LatexInfo::buildEntries(bool isPatternString) { - static regex const rmath("(\\\\)*(\\$|\\\\\\[|\\\\\\]|\\\\(begin|end)\\{((eqnarray|equation|flalign|gather|multline|align|alignat)\\*?)\\})"); + static regex const rmath("(\\\\)*(\\$|\\\\\\[|\\\\\\]|\\\\(begin|end)\\{((eqnarray|equation|flalign|gather|multline|align|x?x?alignat)\\*?\\})(\\{[0-9]+\\})?)"); static regex const rkeys("(\\\\)*(\\$|\\\\\\[|\\\\\\]|\\\\((([a-zA-Z]+\\*?)(\\{([a-z]+\\*?)\\}|=[0-9]+[a-z]+)?)))"); static bool disableLanguageOverride = false; smatch sub, submath; @@ -1841,8 +2091,10 @@ void LatexInfo::buildEntries(bool isPatternString) KeyInfo found; bool math_end_waiting = false; size_t math_pos = 10000; + size_t math_prefix_size = 1; string math_end; static vector usedText = vector(); + static bool removeMathHull = false; interval_.removeAccents(); @@ -1856,17 +2108,17 @@ void LatexInfo::buildEntries(bool isPatternString) size_t pos = submath.position(size_t(2)); if ((math_end == "$") && (submath.str(2) == "$")) { - mi.insert("$", math_pos, pos + 1); + mi.insert("$", math_pos, 1, pos, 1); math_end_waiting = false; } else if ((math_end == "\\]") && (submath.str(2) == "\\]")) { - mi.insert("\\]", math_pos, pos + 2); + mi.insert("\\]", math_pos, 2, pos, 2); math_end_waiting = false; } else if ((submath.str(3).compare("end") == 0) && - (submath.str(4).compare(math_end) == 0)) { - mi.insert(math_end, math_pos, pos + submath.str(2).length()); + (submath.str(5).compare(math_end) == 0)) { + mi.insert(math_end, math_pos, math_prefix_size, pos, submath.str(2).length()); math_end_waiting = false; } else @@ -1875,8 +2127,9 @@ void LatexInfo::buildEntries(bool isPatternString) else { if (submath.str(3).compare("begin") == 0) { math_end_waiting = true; - math_end = submath.str(4); + math_end = submath.str(5); math_pos = submath.position(size_t(2)); + math_prefix_size = submath.str(2).length(); } else if (submath.str(2).compare("\\[") == 0) { math_end_waiting = true; @@ -1902,9 +2155,12 @@ void LatexInfo::buildEntries(bool isPatternString) // Disable language keys["foreignlanguage"].disabled = true; disableLanguageOverride = true; + removeMathHull = false; } - else + else { + removeMathHull = true; // used later if not isPatternString disableLanguageOverride = false; + } } else { if (disableLanguageOverride) { @@ -1926,9 +2182,10 @@ void LatexInfo::buildEntries(bool isPatternString) key = sub.str(2); } } - if (keys.find(key) != keys.end()) { - if (keys[key].keytype == KeyInfo::headRemove) { - KeyInfo found1 = keys[key]; + KeysIterator it_key = keys.find(key); + if (it_key != keys.end()) { + if (it_key->second.keytype == KeyInfo::headRemove) { + KeyInfo found1 = it_key->second; found1.disabled = true; found1.head = "\\" + key + "{"; found1._tokenstart = sub.position(size_t(2)); @@ -1962,7 +2219,7 @@ void LatexInfo::buildEntries(bool isPatternString) mi.incrEntry(); math_pos = mi.getStartPos(); } - if (keys.find(key) == keys.end()) { + if (it_key == keys.end()) { found = KeyInfo(KeyInfo::isStandard, 0, true); LYXERR(Debug::INFO, "Undefined key " << key << " ==> will be used as text"); found = KeyInfo(KeyInfo::isText, 0, false); @@ -1995,6 +2252,17 @@ void LatexInfo::buildEntries(bool isPatternString) found._dataStart = found._dataEnd; found.parenthesiscount = 0; found.head = interval_.par.substr(found._tokenstart, found._tokensize); + if (removeMathHull) { + interval_.addIntervall(found._tokenstart, found._tokenstart + mi.getPrefixSize()); + interval_.addIntervall(found._dataEnd - mi.getPostfixSize(), found._dataEnd); + } + else { + // Treate all math constructs as simple math + interval_.par[found._tokenstart] = '$'; + interval_.par[found._dataEnd - mi.getPostfixSize()] = '$'; + interval_.addIntervall(found._tokenstart + 1, found._tokenstart + mi.getPrefixSize()); + interval_.addIntervall(found._dataEnd - mi.getPostfixSize() + 1, found._dataEnd); + } evaluatingMath = true; } else { @@ -2234,7 +2502,7 @@ void LatexInfo::buildKeys(bool isPatternString) if (keysBuilt && !isPatternString) return; // Keys to ignore in any case - makeKey("text|textcyrillic|lyxmathsym", KeyInfo(KeyInfo::headRemove, 1, true), true); + makeKey("text|textcyrillic|lyxmathsym|ensuremath", KeyInfo(KeyInfo::headRemove, 1, true), true); // Known standard keys with 1 parameter. // Split is done, if not at start of region makeKey("textsf|textss|texttt", KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getFamily()), isPatternString); @@ -2822,7 +3090,10 @@ int LatexInfo::process(ostringstream & os, KeyInfo const & actual ) } if (dstart < output_end) interval_.output(os, output_end); - interval_.addIntervall(actual._tokenstart, end); + if (nextKeyIdx < 0) + interval_.addIntervall(0, end); + else + interval_.addIntervall(actual._tokenstart, end); return nextKeyIdx; } @@ -2906,7 +3177,7 @@ string splitOnKnownMacros(string par, bool isPatternString) * Resulting modified string is set to "", if * the searched tex does not contain all the features in the search pattern */ -static string correctlanguagesetting(string par, bool isPatternString, bool withformat) +static string correctlanguagesetting(string par, bool isPatternString, bool withformat, lyx::Buffer *pbuf = nullptr) { static Features regex_f; static int missed = 0; @@ -2926,8 +3197,24 @@ static string correctlanguagesetting(string par, bool isPatternString, bool with // Split the latex input into pieces which // can be digested by our search engine LYXERR(Debug::FIND, "input: \"" << par << "\""); + if (isPatternString && (pbuf != nullptr)) { // Check if we should disable/enable test for language + // We check for polyglossia, because in runparams.flavor we use Flavor::XeTeX + string doclang = pbuf->params().language->polyglossia(); + static regex langre("\\\\(foreignlanguage)\\{([^\\}]+)\\}"); + smatch sub; + bool toIgnoreLang = true; + for (sregex_iterator it(par.begin(), par.end(), langre), end; it != end; ++it) { + sub = *it; + if (sub.str(2) != doclang) { + toIgnoreLang = false; + break; + } + } + setIgnoreFormat("language", toIgnoreLang, false); + + } result = splitOnKnownMacros(par.substr(0,parlen), isPatternString); - LYXERR(Debug::FIND, "After split: \"" << result << "\""); + LYXERR(Debug::FIND, "After splitOnKnownMacros:\n\"" << result << "\""); } else result = par.substr(0, parlen); @@ -3033,6 +3320,7 @@ void MatchStringAdv::CreateRegexp(FindAndReplaceOptions const & opt, string rege regexError += "Invalid regexp2 \"" + regexp2_str + "\", error = " + regexp2.errorString().toStdString(); } #else + (void)par_as_string; if (opt.casesensitive) { regexp = regex(regexp_str); regexp2 = regex(regexp2_str); @@ -3093,8 +3381,8 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt) size_t lead_size = 0; // correct the language settings - par_as_string = correctlanguagesetting(par_as_string, true, !opt.ignoreformat); - opt.matchstart = false; + par_as_string = correctlanguagesetting(par_as_string, true, !opt.ignoreformat, &buf); + opt.matchAtStart = false; if (!use_regexp) { identifyClosing(par_as_string); // Removes math closings ($, ], ...) at end of string if (opt.ignoreformat) { @@ -3135,16 +3423,15 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt) string lead_as_regexp; if (lead_size > 0) { lead_as_regexp = string2regex(par_as_string.substr(0, lead_size)); - regex_replace(par_as_string_nolead, par_as_string_nolead, "}$", ""); + (void)regex_replace(par_as_string_nolead, par_as_string_nolead, "}$", ""); par_as_string = par_as_string_nolead; LYXERR(Debug::FIND, "lead_as_regexp is '" << lead_as_regexp << "'"); LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'"); } - LYXERR(Debug::FIND, "par_as_string before escape_for_regex() is '" << par_as_string << "'"); + // LYXERR(Debug::FIND, "par_as_string before escape_for_regex() is '" << par_as_string << "'"); par_as_string = escape_for_regex(par_as_string, !opt.ignoreformat); // Insert (.*?) before trailing closure of math, macros and environments, so to catch parts of them. - LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'"); - LYXERR(Debug::FIND, "par_as_string after correctRegex is '" << par_as_string << "'"); + // LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'"); ++close_wildcards; size_t lng = par_as_string.size(); if (!opt.ignoreformat) { @@ -3164,14 +3451,15 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt) if (lng < par_as_string.size()) par_as_string = par_as_string.substr(0,lng); } + LYXERR(Debug::FIND, "par_as_string after correctRegex is '" << par_as_string << "'"); if ((lng > 0) && (par_as_string[0] == '^')) { par_as_string = par_as_string.substr(1); --lng; - opt.matchstart = true; + opt.matchAtStart = true; } - LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'"); - LYXERR(Debug::FIND, "Open braces: " << open_braces); - LYXERR(Debug::FIND, "Replaced text (to be used as regex): " << par_as_string); + // LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'"); + // LYXERR(Debug::FIND, "Open braces: " << open_braces); + // LYXERR(Debug::FIND, "Replaced text (to be used as regex): " << par_as_string); // If entered regexp must match at begin of searched string buffer // Kornel: Added parentheses to use $1 for size of the leading string @@ -3199,68 +3487,6 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt) } } -#if 0 -// Count number of characters in string -// {]} ==> 1 -// \& ==> 1 -// --- ==> 1 -// \\[a-zA-Z]+ ==> 1 -#if QTSEARCH -static int computeSize(QStringRef s, int len) -#define isLyxAlpha(arg) arg.isLetter() -#else -static int computeSize(string s, int len) -#define isLyxAlpha(arg) isalpha(arg) -#endif -{ - if (len == 0) - return 0; - int skip = 1; - int count = 0; - for (int i = 0; i < len; i += skip, count++) { - if (s.at(i) == '\\') { - skip = 2; - if (i + 1 < len && isLyxAlpha(s.at(i+1))) { - for (int j = 2; i+j < len; j++) { - if (! isLyxAlpha(s.at(i+j))) { - if (s.at(i+j) == ' ') - skip++; - else if (s.at(i+j) == '{') { - if (i+j+1 < len && s.at(i+j+1) == '}') - skip += 2; - else if (i + j + 1 >= len) - skip++; - } - break; - } - skip++; - } - } - } - else if (s.at(i) == '{') { - if (i + 1 < len && s.at(i+1) == '}') - skip = 2; - else - skip = 3; - } - else if (s.at(i) == '-') { - if (i+1 < len && s.at(i+1) == '-') { - if (i + 2 < len && s.at(i+2) == '-') - skip = 3; - else - skip = 2; - } - else - skip = 1; - } - else { - skip = 1; - } - } - return count; -} -#endif - MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_begin) const { MatchResult mres; @@ -3272,10 +3498,7 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be docstring docstr = stringifyFromForSearch(opt, cur, len); string str; - if (use_regexp || opt.casesensitive) - str = normalize(docstr); - else - str = normalize(lowercase(docstr)); + str = normalize(docstr); if (!opt.ignoreformat) { str = correctlanguagesetting(str, false, !opt.ignoreformat); // remove closing '}' and '\n' to allow for use of '$' in regex @@ -3290,10 +3513,11 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be mres.match_len = -1; return mres; } - LYXERR(Debug::FIND, "Matching against '" << lyx::to_utf8(docstr) << "'"); - LYXERR(Debug::FIND, "After normalization: '" << str << "'"); + LYXERR(Debug::FIND, "After normalization: Matching against:\n'" << str << "'"); - if (use_regexp) { + LASSERT(use_regexp, /**/); + { + // use_regexp always true LYXERR(Debug::FIND, "Searching in regexp mode: at_begin=" << at_begin); #if QTSEARCH QString qstr = QString::fromStdString(str); @@ -3347,23 +3571,25 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be // we have to 'unify' the length of the post-match. // Done by ignoring closing parenthesis and linefeeds at string end int matchend = match.capturedEnd(0); - while (mres.match_len > 0) { - QChar c = qstr.at(matchend - 1); - if ((c == '\n') || (c == '}') || (c == '{')) { - mres.match_len--; - matchend--; - } - else - break; - } size_t strsize = qstr.size(); - while (strsize > (size_t) match.capturedEnd(0)) { - QChar c = qstr.at(strsize-1); - if ((c == '\n') || (c == '}')) { - --strsize; + if (!opt.ignoreformat) { + while (mres.match_len > 0) { + QChar c = qstr.at(matchend - 1); + if ((c == '\n') || (c == '}') || (c == '{')) { + mres.match_len--; + matchend--; + } + else + break; + } + while (strsize > (size_t) match.capturedEnd(0)) { + QChar c = qstr.at(strsize-1); + if ((c == '\n') || (c == '}')) { + --strsize; + } + else + break; } - else - break; } // LYXERR0(qstr.toStdString()); mres.match2end = strsize - matchend; @@ -3374,22 +3600,24 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be // ignore closing parenthesis and linefeeds at string end size_t strend = m[0].second - m[0].first; int matchend = strend; - while (mres.match_len > 0) { - char c = str.at(matchend - 1); - if ((c == '\n') || (c == '}') || (c == '{')) { - mres.match_len--; - matchend--; - } - else - break; - } size_t strsize = str.size(); - while (strsize > strend) { - if ((str.at(strsize-1) == '}') || (str.at(strsize-1) == '\n')) { - --strsize; + if (!opt.ignoreformat) { + while (mres.match_len > 0) { + char c = str.at(matchend - 1); + if ((c == '\n') || (c == '}') || (c == '{')) { + mres.match_len--; + matchend--; + } + else + break; + } + while (strsize > strend) { + if ((str.at(strsize-1) == '}') || (str.at(strsize-1) == '\n')) { + --strsize; + } + else + break; } - else - break; } // LYXERR0(str); mres.match2end = strsize - matchend; @@ -3417,34 +3645,6 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be #endif return mres; } - - // else !use_regexp: but all code paths above return - LYXERR(Debug::FIND, "Searching in normal mode: par_as_string='" - << par_as_string << "', str='" << str << "'"); - LYXERR(Debug::FIND, "Searching in normal mode: lead_as_string='" - << lead_as_string << "', par_as_string_nolead='" - << par_as_string_nolead << "'"); - - if (at_begin) { - LYXERR(Debug::FIND, "size=" << par_as_string.size() - << ", substr='" << str.substr(0, par_as_string.size()) << "'"); - if (str.substr(0, par_as_string.size()) == par_as_string) { - mres.match_len = par_as_string.size(); - mres.match2end = str.size(); - mres.pos = 0; - return mres; - } - } else { - // Start the search _after_ the leading part - size_t pos = str.find(par_as_string_nolead, lead_as_string.size()); - if (pos != string::npos) { - mres.match_len = par_as_string.size(); - mres.match2end = str.size() - pos; - mres.pos = pos; - return mres; - } - } - return mres; } @@ -3454,9 +3654,9 @@ MatchResult MatchStringAdv::operator()(DocIterator const & cur, int len, bool at int res = mres.match_len; LYXERR(Debug::FIND, "res=" << res << ", at_begin=" << at_begin - << ", matchstart=" << opt.matchstart + << ", matchAtStart=" << opt.matchAtStart << ", inTexted=" << cur.inTexted()); - if (opt.matchstart) { + if (opt.matchAtStart) { if (cur.pos() != 0) mres.match_len = 0; else if (mres.match_prefix > 0) @@ -3526,7 +3726,7 @@ string MatchStringAdv::normalize(docstring const & s) const // Remove stale empty \emph{}, \textbf{} and similar blocks from latexify // Kornel: Added textsl, textsf, textit, texttt and noun // + allow to seach for colored text too - LYXERR(Debug::FIND, "Removing stale empty \\emph{}, \\textbf{}, \\*section{} macros from: " << t); + LYXERR(Debug::FIND, "Removing stale empty macros from: " << t); while (regex_replace(t, t, "\\\\(emph|noun|text(bf|sl|sf|it|tt)|(u|uu)line|(s|x)out|uwave)(\\{(\\{\\})?\\})+", "")) LYXERR(Debug::FIND, " further removing stale empty \\emph{}, \\textbf{} macros from: " << t); while (regex_replace(t, t, "\\\\((sub)?(((sub)?section)|paragraph)|part)\\*?(\\{(\\{\\})?\\})+", "")) @@ -3553,11 +3753,18 @@ docstring stringifyFromCursor(DocIterator const & cur, int len) runparams.linelen = 10000; //lyxrc.plaintext_linelen; // No side effect of file copying and image conversion runparams.dryrun = true; - runparams.for_search = true; + int option = AS_STR_INSETS | AS_STR_PLAINTEXT; + if (ignoreFormats.getDeleted()) { + option |= AS_STR_SKIPDELETE; + runparams.for_searchAdv = OutputParams::SearchWithoutDeleted; + } + else { + runparams.for_searchAdv = OutputParams::SearchWithDeleted; + } LYXERR(Debug::FIND, "Stringifying with cur: " << cur << ", from pos: " << cur.pos() << ", end: " << end); return par.asString(cur.pos(), end, - AS_STR_INSETS | AS_STR_SKIPDELETE | AS_STR_PLAINTEXT, + option, &runparams); } else if (cur.inMathed()) { CursorSlice cs = cur.top(); @@ -3585,9 +3792,11 @@ docstring stringifyFromCursor(DocIterator const & cur, int len) */ docstring latexifyFromCursor(DocIterator const & cur, int len) { + /* LYXERR(Debug::FIND, "Latexifying with len=" << len << " from cursor at pos: " << cur); LYXERR(Debug::FIND, " with cur.lastpost=" << cur.lastpos() << ", cur.lastrow=" << cur.lastrow() << ", cur.lastcol=" << cur.lastcol()); + */ Buffer const & buf = *cur.buffer(); odocstringstream ods; @@ -3599,7 +3808,12 @@ docstring latexifyFromCursor(DocIterator const & cur, int len) runparams.linelen = 8000; //lyxrc.plaintext_linelen; // No side effect of file copying and image conversion runparams.dryrun = true; - runparams.for_search = true; + if (ignoreFormats.getDeleted()) { + runparams.for_searchAdv = OutputParams::SearchWithoutDeleted; + } + else { + runparams.for_searchAdv = OutputParams::SearchWithDeleted; + } if (cur.inTexted()) { // @TODO what about searching beyond/across paragraph breaks ? @@ -3691,20 +3905,24 @@ static void displayMResult(MatchResult &mres, string from, DocIterator & cur) ** be selected ** Return the cur.pos() difference between start and end of found match **/ -MatchResult &findAdvFinalize(DocIterator & cur, MatchStringAdv const & match, MatchResult const & expected = MatchResult(-1)) +MatchResult findAdvFinalize(DocIterator & cur, MatchStringAdv const & match, MatchResult const & expected = MatchResult(-1)) { // Search the foremost position that matches (avoids find of entire math // inset when match at start of it) DocIterator old_cur(cur.buffer()); MatchResult mres; static MatchResult fail = MatchResult(); - static MatchResult max_match; + MatchResult max_match; // If (prefix_len > 0) means that forwarding 1 position will remove the complete entry // Happens with e.g. hyperlinks // either one sees "http://www.bla.bla" or nothing // so the search for "www" gives prefix_len = 7 (== sizeof("http://") // and although we search for only 3 chars, we find the whole hyperlink inset bool at_begin = (expected.match_prefix == 0); + if (!match.opt.forward && match.opt.ignoreformat) { + if (expected.pos > 0) + return fail; + } LASSERT(at_begin, /**/); if (expected.match_len > 0 && at_begin) { // Search for deepest match @@ -3749,29 +3967,9 @@ MatchResult &findAdvFinalize(DocIterator & cur, MatchStringAdv const & match, Ma int len = 1; if (cur.pos() + len > cur.lastpos()) return fail; - // regexp should use \w+, \S+, or \b(some string)\b - // to search for whole words - if (match.opt.matchword && !match.use_regexp) { - LYXERR(Debug::FIND, "verifying unmatch with len = " << len); - while (cur.pos() + len <= cur.lastpos() && match(cur, len).match_len <= 0) { - ++len; - LYXERR(Debug::FIND, "verifying unmatch with len = " << len); - } - // Length of matched text (different from len param) - static MatchResult old_match = match(cur, len, at_begin); - if (old_match.match_len < 0) - old_match = fail; - MatchResult new_match; - // Greedy behaviour while matching regexps - while ((new_match = match(cur, len + 1, at_begin)).match_len > old_match.match_len) { - ++len; - old_match = new_match; - LYXERR(Debug::FIND, "verifying match with len = " << len); - } - displayMres(old_match, "SEARCH RESULT", cur) - return old_match; - } - else { + + LASSERT(match.use_regexp, /**/); + { int minl = 1; int maxl = cur.lastpos() - cur.pos(); // Greedy behaviour while matching regexps @@ -3792,14 +3990,14 @@ MatchResult &findAdvFinalize(DocIterator & cur, MatchStringAdv const & match, Ma max_match.match_len = actual_match_len; maxl = len; if (maxl - minl < 4) - len = (int)((maxl + minl)/2); + len = (maxl + minl)/2; else - len = (int)(minl + (maxl - minl + 3)/4); + len = minl + (maxl - minl + 3)/4; } else { // (actual_match_len < max_match.match_len) minl = len + 1; - len = (int)((maxl + minl)/2); + len = (maxl + minl)/2; } } len = minl; @@ -3855,6 +4053,8 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match) if (!cur) return 0; bool repeat = false; + DocIterator orig_cur; // to be used if repeat not successful + MatchResult orig_mres; while (!theApp()->longOperationCancelled() && cur) { //(void) findAdvForwardInnermost(cur); LYXERR(Debug::FIND, "findForwardAdv() cur: " << cur); @@ -3877,10 +4077,10 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match) else { // match_len > 0 // Try to find the begin of searched string int increment; - int firstInvalid = 100000; + int firstInvalid = cur.lastpos() - cur.pos(); { int incrmatch = (mres.match_prefix + mres.pos - mres.leadsize + 1)*3/4; - int incrcur = (cur.lastpos() - cur.pos() + 1 )*3/4; + int incrcur = (firstInvalid + 1 )*3/4; if (incrcur < incrmatch) increment = incrcur; else @@ -3891,70 +4091,69 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match) LYXERR(Debug::FIND, "Set increment to " << increment); while (increment > 0) { DocIterator old_cur = cur; - size_t skipping = cur.depth(); - for (int i = 0; i < increment && cur; i++) { - cur.forwardPos(); - while (cur && cur.depth() > skipping) { - cur.pos() = cur.lastpos(); - cur.forwardPos(); - } - } - if (! cur || (cur.pit() > old_cur.pit())) { - // Are we outside of the paragraph? - // This can happen if moving past some UTF8-encoded chars - cur = old_cur; + if (cur.pos() + increment >= cur.lastpos()) { increment /= 2; + continue; } - else { - MatchResult mres2 = match(cur, -1, false); - displayMres(mres2, "findForwardAdv loop", cur) - switch (interpretMatch(mres, mres2)) { + cur.pos() = cur.pos() + increment; + MatchResult mres2 = match(cur, -1, false); + displayMres(mres2, "findForwardAdv loop", cur) + switch (interpretMatch(mres, mres2)) { case MatchResult::newIsTooFar: - // behind the expected match - firstInvalid = increment; - cur = old_cur; - increment /= 2; - break; + // behind the expected match + firstInvalid = increment; + cur = old_cur; + increment /= 2; + break; case MatchResult::newIsBetter: - // not reached yet, but cur.pos()+increment is bettert - mres = mres2; - firstInvalid -= increment; - if (increment > firstInvalid*3/4) - increment = firstInvalid*3/4; - if ((mres2.pos == mres2.leadsize) && (increment >= mres2.match_prefix)) { - if (increment >= mres2.match_prefix) - increment = (mres2.match_prefix+1)*3/4; - } - break; + // not reached yet, but cur.pos()+increment is bettert + mres = mres2; + firstInvalid -= increment; + if (increment > firstInvalid*3/4) + increment = firstInvalid*3/4; + if ((mres2.pos == mres2.leadsize) && (increment >= mres2.match_prefix)) { + if (increment >= mres2.match_prefix) + increment = (mres2.match_prefix+1)*3/4; + } + break; default: - // Todo@ - // Handle not like MatchResult::newIsTooFar - LYXERR0( "Something is wrong: Increment = " << increment << " match_prefix = " << mres.match_prefix); - firstInvalid--; - increment = increment*3/4; - cur = old_cur; - break; - } + // Todo@ + // Handle not like MatchResult::newIsTooFar + LYXERR0( "Probably too far: Increment = " << increment << " match_prefix = " << mres.match_prefix); + firstInvalid--; + increment = increment*3/4; + cur = old_cur; + break; } } - if (mres.match_len > 0 && mres.match_prefix + mres.pos - mres.leadsize > 0) { - repeat = true; - cur.forwardPos(); - continue; + if (mres.match_len > 0) { + if (mres.match_prefix + mres.pos - mres.leadsize > 0) { + // The match seems to indicate some deeper level + repeat = true; + orig_cur = cur; + orig_mres = mres; + cur.forwardPos(); + continue; + } + } + else if (repeat) { + // should never be reached. + cur = orig_cur; + mres = orig_mres; } // LYXERR0("Leaving first loop"); LYXERR(Debug::FIND, "Finalizing 1"); MatchResult found_match = findAdvFinalize(cur, match, mres); if (found_match.match_len > 0) { - LASSERT(found_match.pos_len > 0, /**/); - match.FillResults(found_match); - return found_match.pos_len; + LASSERT(found_match.pos_len > 0, /**/); + match.FillResults(found_match); + return found_match.pos_len; } else { - // try next possible match - cur.forwardPos(); - repeat = false; - continue; + // try next possible match + cur.forwardPos(); + repeat = false; + continue; } } } @@ -3963,11 +4162,12 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match) /// Find the most backward consecutive match within same paragraph while searching backwards. -MatchResult &findMostBackwards(DocIterator & cur, MatchStringAdv const & match) +MatchResult findMostBackwards(DocIterator & cur, MatchStringAdv const & match, MatchResult &expected) { - DocIterator cur_begin = doc_iterator_begin(cur.buffer()); + DocIterator cur_begin = cur; + cur_begin.pos() = 0; DocIterator tmp_cur = cur; - static MatchResult mr = findAdvFinalize(tmp_cur, match, MatchResult(-1)); + MatchResult mr = findAdvFinalize(tmp_cur, match, expected); Inset & inset = cur.inset(); for (; cur != cur_begin; cur.backwardPos()) { LYXERR(Debug::FIND, "findMostBackwards(): cur=" << cur); @@ -3975,7 +4175,7 @@ MatchResult &findMostBackwards(DocIterator & cur, MatchStringAdv const & match) new_cur.backwardPos(); if (new_cur == cur || &new_cur.inset() != &inset || !match(new_cur).match_len) break; - MatchResult new_mr = findAdvFinalize(new_cur, match, MatchResult(-1)); + MatchResult new_mr = findAdvFinalize(new_cur, match, expected); if (new_mr.match_len == mr.match_len) break; mr = new_mr; @@ -3999,9 +4199,9 @@ int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) bool pit_changed = false; do { cur.pos() = 0; - bool found_match = (match(cur, -1, false).match_len > 0); + MatchResult found_match = match(cur, -1, false); - if (found_match) { + if (found_match.match_len > 0) { if (pit_changed) cur.pos() = cur.lastpos(); else @@ -4009,14 +4209,15 @@ int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) LYXERR(Debug::FIND, "findBackAdv2: cur: " << cur); DocIterator cur_prev_iter; do { - found_match = (match(cur).match_len > 0); + found_match = match(cur); LYXERR(Debug::FIND, "findBackAdv3: found_match=" - << found_match << ", cur: " << cur); - if (found_match) { - MatchResult found_mr = findMostBackwards(cur, match); - match.FillResults(found_mr); - LASSERT(found_mr.pos_len > 0, /**/); - return found_mr.pos_len; + << (found_match.match_len > 0) << ", cur: " << cur); + if (found_match.match_len > 0) { + MatchResult found_mr = findMostBackwards(cur, match, found_match); + if (found_mr.pos_len > 0) { + match.FillResults(found_mr); + return found_mr.pos_len; + } } // Stop if begin of document reached @@ -4120,7 +4321,6 @@ static void changeFirstCase(Buffer & buffer, TextCase first_case, TextCase other } } // namespace -#if 1 static bool replaceMatches(string &t, int maxmatchnum, vector const & replacements) { // Should replace the string "$" + std::to_string(matchnum) with replacement @@ -4148,7 +4348,6 @@ static bool replaceMatches(string &t, int maxmatchnum, vector const & r t = s; return true; } -#endif /// static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, MatchStringAdv & matchAdv) @@ -4180,10 +4379,10 @@ static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, Ma ostringstream oss; repl_buffer_orig.write(oss); string lyx = oss.str(); - if (matchAdv.valid_matches > 0) { - replaceMatches(lyx, matchAdv.valid_matches, matchAdv.matches); - } - Buffer repl_buffer("", false); + if (matchAdv.valid_matches > 0) + replaceMatches(lyx, matchAdv.valid_matches, matchAdv.matches); + Buffer repl_buffer(string(), false); + repl_buffer.setInternal(true); repl_buffer.setUnnamed(true); LASSERT(repl_buffer.readString(lyx), return 0); if (opt.keep_case && sel_len >= 2) { @@ -4204,6 +4403,7 @@ static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, Ma LYXERR(Debug::FIND, "Before pasteParagraphList() cur=" << cur << endl); cap::pasteParagraphList(cur, repl_buffer.paragraphs(), repl_buffer.params().documentClassPtr(), + repl_buffer.params().authors(), bv->buffer().errorList("Paste")); LYXERR(Debug::FIND, "After pasteParagraphList() cur=" << cur << endl); sel_len = repl_buffer.paragraphs().begin()->size(); @@ -4336,7 +4536,7 @@ ostringstream & operator<<(ostringstream & os, FindAndReplaceOptions const & opt istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt) { - LYXERR(Debug::FIND, "parsing"); + // LYXERR(Debug::FIND, "parsing"); string s; string line; getline(is, line); @@ -4348,7 +4548,7 @@ istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt) break; getline(is, line); } - LYXERR(Debug::FIND, "file_buf_name: '" << s << "'"); + // LYXERR(Debug::FIND, "file_buf_name: '" << s << "'"); opt.find_buf_name = from_utf8(s); is >> opt.casesensitive >> opt.matchword >> opt.forward >> opt.expandmacros >> opt.ignoreformat >> opt.replace_all; is.get(); // Waste space before replace string @@ -4362,7 +4562,7 @@ istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt) break; getline(is, line); } - LYXERR(Debug::FIND, "repl_buf_name: '" << s << "'"); + // LYXERR(Debug::FIND, "repl_buf_name: '" << s << "'"); opt.repl_buf_name = from_utf8(s); is >> opt.keep_case; int i; @@ -4371,9 +4571,11 @@ istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt) is >> i; opt.restr = FindAndReplaceOptions::SearchRestriction(i); + /* LYXERR(Debug::FIND, "parsed: " << opt.casesensitive << ' ' << opt.matchword << ' ' << opt.forward << ' ' << opt.expandmacros << ' ' << opt.ignoreformat << ' ' << opt.keep_case << ' ' << opt.scope << ' ' << opt.restr); + */ return is; }