X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxfind.cpp;h=c8fc40947e75643cb281589fc41b62b30508858c;hb=3bf1b97ae547aea5d0243e41b2d8af463a6e40c5;hp=83bb13a22af3aa36db8af6433d94e8693ec3950b;hpb=1ef1808c935ae7e89a988ea390ee26e9aa499b86;p=features.git diff --git a/src/lyxfind.cpp b/src/lyxfind.cpp index 83bb13a22a..c8fc40947e 100644 --- a/src/lyxfind.cpp +++ b/src/lyxfind.cpp @@ -1111,7 +1111,7 @@ private: ** @todo Normalization should also expand macros, if the corresponding ** search option was checked. **/ - string normalize(docstring const & s, bool ignore_fomat) const; + string convertLF2Space(docstring const & s, bool ignore_fomat) const; // normalized string to search string par_as_string; // regular expression to use for searching @@ -2424,7 +2424,7 @@ void LatexInfo::buildEntries(bool isPatternString) } // Ignore language if there is math somewhere in pattern-string if (isPatternString) { - for (auto s: usedText) { + for (auto const & s: usedText) { // Remove entries created in previous search runs keys.erase(s); } @@ -3669,7 +3669,7 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions & opt) previous_single_replace = true; } // When using regexp, braces are hacked already by escape_for_regex() - par_as_string = normalize(ds, opt.ignoreformat); + par_as_string = convertLF2Space(ds, opt.ignoreformat); open_braces = 0; close_wildcards = 0; @@ -3794,7 +3794,7 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, MatchStrin docstring docstr = stringifyFromForSearch(opt, cur, len); string str; - str = normalize(docstr, opt.ignoreformat); + str = convertLF2Space(docstr, opt.ignoreformat); if (!opt.ignoreformat) { str = correctlanguagesetting(str, false, !opt.ignoreformat); // remove closing '}' and '\n' to allow for use of '$' in regex @@ -3988,8 +3988,7 @@ static bool simple_replace(string &t, string from, string to) } #endif -#if 1 -static string convertLF2Space(docstring const &s, bool ignore_format) +string MatchStringAdv::convertLF2Space(docstring const &s, bool ignore_format) const { // Using original docstring to handle '\n' @@ -4056,77 +4055,6 @@ static string convertLF2Space(docstring const &s, bool ignore_format) return(t.str()); } -#else -static string convertLF2Space(docstring const & s, bool ignore_format) -{ - // Using utf8-converted string to handle '\n' - - string t; - t = lyx::to_utf8(s); - // Remove \n at begin - while (!t.empty() && t[0] == '\n') - t = t.substr(1); - // Remove \n* at end - while (!t.empty() && t[t.size() - 1] == '\n') { - t = t.substr(0, t.size() - 1); - } - size_t pos; - // Handle all other '\n' - while ((pos = t.find("\n")) != string::npos) { - if (pos > 1 && t[pos-1] == '\\' && t[pos-2] == '\\' ) { - // Handle '\\\n' - if (isPrintableNonspace(t[pos+1]) && ((pos < 3) || isPrintableNonspace(t[pos-3]))) { - t.replace(pos-2, 3, " "); - } - else { - // Already a space there - t.replace(pos-2, 3, ""); - } - } - else { - if (!isAlnumASCII(t[pos+1]) || !isAlnumASCII(t[pos-1])) { - // '\n' adjacent to non-alpha-numerics, discard - t.replace(pos, 1, ""); - } - else { - // Replace all other \n with spaces - t.replace(pos, 1, " "); - } - if (!ignore_format) { - size_t count = 0; - while ((pos > count + 1) && (t[pos - 1 -count] == '%')) { - count++; - } - if (count > 0) { - t.replace(pos - count, count, ""); - } - } - } - } - return(t); - -} -#endif - -string MatchStringAdv::normalize(docstring const & s, bool ignore_format) const -{ - string t = convertLF2Space(s, ignore_format); - - // The following replaces are not appropriate in non-format-search mode - if (!ignore_format) { - // 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::FINDVERBOSE, "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::FINDVERBOSE, " further removing stale empty \\emph{}, \\textbf{} macros from: " << t); - while (regex_replace(t, t, "\\\\((sub)?(((sub)?section)|paragraph)|part)\\*?(\\{(\\{\\})?\\})+", "")) - LYXERR(Debug::FINDVERBOSE, " further removing stale empty \\section{}, \\part{}, \\paragraph{} macros from: " << t); - while (regex_replace(t, t, "\\\\(foreignlanguage|textcolor|item)\\{[a-z]+\\}(\\{(\\{\\})?\\})+", "")); - } - return t; -} - docstring stringifyFromCursor(DocIterator const & cur, int len) { LYXERR(Debug::FINDVERBOSE, "Stringifying with len=" << len << " from cursor at pos: " << cur); @@ -4831,6 +4759,10 @@ static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, Ma return 1; } +static bool isWordChar(char_type c) +{ + return isLetterChar(c) || isNumberChar(c); +} /// Perform a FindAdv operation. bool findAdv(BufferView * bv, FindAndReplaceOptions & opt) @@ -4857,14 +4789,45 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions & opt) num_replaced += findAdvReplace(bv, opt, matchAdv); cur = bv->cursor(); if (opt.forward) { - if (opt.matchword) { // Skip word-characters if we are in the mid of a word - Paragraph const & par = cur.paragraph(); - if ((cur.pos() > 0) && !par.isWordSeparator(cur.pos() -1, true)) { - while (cur.pos() < par.size()) { - if (par.isWordSeparator(cur.pos(), true)) + if (opt.matchword && cur.pos() > 0) { // Skip word-characters if we are in the mid of a word + if (cur.inTexted()) { + Paragraph const & par = cur.paragraph(); + int len_limit, new_pos; + if (cur.lastpos() < par.size()) + len_limit = cur.lastpos(); + else + len_limit = par.size(); + for (new_pos = cur.pos() - 1; new_pos < len_limit; new_pos++) { + if (!isWordChar(par.getChar(new_pos))) break; - else - cur.forwardPos(); + } + if (new_pos > cur.pos()) + cur.pos() = new_pos; + } + else if (cur.inMathed()) { + // Check if 'cur.pos()-1' and 'cur.pos()' both point to a letter, + // I am not sure, we should consider the selection + bool sel = bv->cursor().selection(); + if (!sel && cur.pos() < cur.lastpos()) { + CursorSlice const & cs = cur.top(); + MathData md = cs.cell(); + int len = -1; + MathData::const_iterator it_end = md.end(); + MathData md2; + // Start the check with one character before actual cursor position + for (MathData::const_iterator it = md.begin() + cs.pos() - 1; + it != it_end; ++it) + md2.push_back(*it); + docstring inp = asString(md2); + for (len = 0; (unsigned) len < inp.size() && len + cur.pos() <= cur.lastpos(); len++) { + if (!isWordChar(inp[len])) + break; + } + // len == 0 means previous char was a word separator + // len == 1 search starts with a word separator + // len == 2 ... we have to skip len -1 chars + if (len > 1) + cur.pos() = cur.pos() + len - 1; } } opt.matchword = false;