]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
Typo
[lyx.git] / src / lyxfind.cpp
index d6391d549f606785aeb48f2e25cda8fc392bba93..0d7d539d1bebf563a6f382082c7dff890a0a80a6 100644 (file)
@@ -32,6 +32,7 @@
 #include "ParIterator.h"
 #include "TexRow.h"
 #include "Text.h"
+#include "Encoding.h"
 
 #include "frontends/Application.h"
 #include "frontends/alert.h"
@@ -910,7 +911,8 @@ private:
 
 static docstring buffer_to_latex(Buffer & buffer)
 {
-       OutputParams runparams(&buffer.params().encoding());
+       //OutputParams runparams(&buffer.params().encoding());
+       OutputParams runparams(encodings.fromLyXName("utf8"));
        odocstringstream ods;
        otexstream os(ods);
        runparams.nice = true;
@@ -934,7 +936,8 @@ static docstring stringifySearchBuffer(Buffer & buffer, FindAndReplaceOptions co
        if (!opt.ignoreformat) {
                str = buffer_to_latex(buffer);
        } else {
-               OutputParams runparams(&buffer.params().encoding());
+               // OutputParams runparams(&buffer.params().encoding());
+               OutputParams runparams(encodings.fromLyXName("utf8"));
                runparams.nice = true;
                runparams.flavor = OutputParams::XETEX;
                runparams.linelen = 10000; //lyxrc.plaintext_linelen;
@@ -1248,25 +1251,38 @@ void Intervall::addIntervall(int low, int upper)
 typedef map<string, string> AccentsMap;
 static AccentsMap accents = map<string, string>();
 
-static void buildaccent(string name, string param, string values)
+static void buildaccent(string n, string param, string values)
 {
-  size_t start = 0;
-  for (size_t i = 0; i < param.size(); i++) {
-    string key = name + "{" + param[i] + "}";
-    // get the corresponding utf8-value
-    if ((values[start] & 0xc0) != 0xc0) {
-      // should not happen, utf8 encoding starts at least with 11xxxxxx
-      start++;
-      continue;
-    }
-    for (int j = 1; ;j++) {
-      if (start + j >= values.size())
-        break;
-      if ((values[start+j] & 0xc0) == 0xc0) {
-        // This is the first byte of following utf8 char
-        accents[key] = values.substr(start, j);
-        start += j;
-        break;
+  stringstream s(n);
+  string name;
+  const char delim = '|';
+  while (getline(s, name, delim)) {
+    size_t start = 0;
+    for (size_t i = 0; i < param.size(); i++) {
+      string key = name + "{" + param[i] + "}";
+      // get the corresponding utf8-value
+      if ((values[start] & 0xc0) != 0xc0) {
+        // should not happen, utf8 encoding starts at least with 11xxxxxx
+       // but value for '\dot{i}' is 'i', which is ascii
+       if ((values[start] & 0x80) == 0) {
+         // is ascii
+         accents[key] = values.substr(start, 1);
+       }
+       start++;
+       continue;
+      }
+      for (int j = 1; ;j++) {
+        if (start + j >= values.size()) {
+          accents[key] = values.substr(start, j);
+          start = values.size() - 1;
+          break;
+        }
+        else if ((values[start+j] & 0xc0) != 0x80) {
+          // This is the first byte of following utf8 char
+          accents[key] = values.substr(start, j);
+          start += j;
+          break;
+        }
       }
     }
   }
@@ -1275,21 +1291,43 @@ static void buildaccent(string name, string param, string values)
 static void buildAccentsMap()
 {
   accents["imath"] = "ı";
+  accents["i"] = "ı";
+  accents["jmath"] = "ȷ";
+  accents["lyxmathsym{ß}"] = "ß";
+  accents["text{ß}"] = "ß";
   accents["ddot{\\imath}"] = "ï";
+  buildaccent("ddot", "aAeEiIioOuUyY",
+                      "äÄëËïÏïöÖüÜÿŸ");   // umlaut
+  buildaccent("dot|.", "cCeEGgIizZaAoObBdDfFyY",
+                       "ċĊėĖĠġİİżŻȧȦȯȮḃḂḋḊḟḞẏẎ"); // dot{i} can only happen if ignoring case, but there is no lowercase of 'İ'
   accents["acute{\\imath}"] = "í";
-  accents["lyxmathsym{ß}"] = "ß";
-  buildaccent("ddot", "aeouyAEOUY", "äëöüÿÄËÖÜŸ");
-  buildaccent("dot", "aeoyzAEOYZ", "ȧėȯẏżȦĖȮẎŻ");
-  buildaccent("acute", "aeouyAEOUY", "äëöüÿÄËÖÜŸ");
-  /*
-  buildaccent("dacute", "oOuU", "őŐűŰ");
-  buildaccent("H", "oOuU", "őŐűŰ");        // dacute in text
-  */
-  buildaccent("mathring", "uU", "ůŮ");
-  buildaccent("r", "uU", "ůŮ");      //mathring in text
-  buildaccent("check", "cdnrszCDNRSZ", "čďřňšžČĎŘŇŠŽ");
-  buildaccent("hat", "cCoOgGhHsS", "ĉĈôÔĝĜĥĤŝŜ");
-  buildaccent("bar", "aAeE", "āĀēĒ");
+  buildaccent("acute", "aAcCeElLoOnNrRsSuUyYzZiI",
+                       "áÁćĆéÉĺĹóÓńŃŕŔśŚúÚýÝźŹíÍ");
+  buildaccent("dacute|H|h", "oOuU", "őŐűŰ");       // double acute
+  buildaccent("mathring|r", "aAuUwy",
+                            "åÅůŮẘẙ");  // ring
+  accents["check{\\imath}"] = "ǐ";
+  accents["check{\\jmath}"] = "ǰ";
+  buildaccent("check|v", "cCdDaAeEiIoOuUgGkKhHlLnNrRsSTtzZ",
+                         "čČďĎǎǍěĚǐǏǒǑǔǓǧǦǩǨȟȞľĽňŇřŘšŠŤťžŽ");  // caron
+  accents["hat{\\imath}"] = "î";
+  accents["hat{\\jmath}"] = "ĵ";
+  buildaccent("hat|^", "aAeEiIcCgGhHjJsSwWyYzZoOuU",
+                       "âÂêÊîÎĉĈĝĜĥĤĵĴŝŜŵŴŷŶẑẐôÔûÛ");      // circ
+  accents["bar{\\imath}"] = "ī";
+  buildaccent("bar|=", "aAeEiIoOuUyY",
+                       "āĀēĒīĪōŌūŪȳȲ");    // macron
+  accents["tilde{\\imath}"] = "ĩ";
+  buildaccent("tilde", "aAnNoOiIuU",
+                       "ãÃñÑõÕĩĨũŨ");        // tilde
+  accents["breve{\\imath}"] = "ĭ";
+  buildaccent("breve|u", "aAeEgGiIoOuU",
+                         "ăĂĕĔğĞĭĬŏŎŭŬ");    // breve
+  accents["grave{\\imath}"] = "ì";
+  buildaccent("grave|`", "aAeEiIoOuUnNwWyY",
+                         "àÀèÈìÌòÒùÙǹǸẁẀỳỲ");   // grave
+  buildaccent("subdot|d", "BbDdHhKkLlMmNnRrSsTtVvWwZzAaEeIiOoUuYy",
+                          "ḄḅḌḍḤḥḲḳḶḷṂṃṆṇṚṛṢṣṬṭṾṿẈẉẒẓẠạẸẹỊịỌọỤụỴỵ");  // dot below
 }
 
 /*
@@ -1300,7 +1338,7 @@ void Intervall::removeAccents()
 {
   if (accents.empty())
     buildAccentsMap();
-  static regex const accre("\\\\((lyxmathsym|ddot|dot|acute|mathring|r|check|check|hat|bar)\\{[^\\{\\}]+\\}|imath)");
+  static regex const accre("\\\\((.|grave|breve|lyxmathsym|text|ddot|dot|acute|dacute|mathring|check|hat|bar|tilde|subdot)\\{[^\\{\\}]+\\}|(i|imath|jmath)(?![a-zA-Z]))");
   smatch sub;
   for (sregex_iterator itacc(par.begin(), par.end(), accre), end; itacc != end; ++itacc) {
     sub = *itacc;
@@ -1312,6 +1350,10 @@ void Intervall::removeAccents()
         par[pos+i] = val[i];
       }
       addIntervall(pos+val.size(), pos + sub.str(0).size());
+      for (size_t i = pos+val.size(); i < pos + sub.str(0).size(); i++) {
+        // remove traces of any remaining chars
+        par[i] = ' ';
+      }
     }
     else {
       LYXERR0("Not added accent for \"" << key << "\"");
@@ -2546,14 +2588,14 @@ static string correctlanguagesetting(string par, bool isPatternString, bool with
                missed = 0;
                if (withformat) {
                        regex_f = identifyFeatures(result);
-                        string features = "";
+                       string features = "";
                        for (auto it = regex_f.cbegin(); it != regex_f.cend(); ++it) {
                                string a = it->first;
                                regex_with_format = true;
-                                features += " " + a;
+                               features += " " + a;
                                // LYXERR0("Identified regex format:" << a);
                        }
-                        LYXERR(Debug::FIND, "Identified Features" << features);
+                       LYXERR(Debug::FIND, "Identified Features" << features);
 
                }
        } else if (regex_with_format) {
@@ -2596,6 +2638,7 @@ static int identifyClosing(string & t)
        return open_braces;
 }
 
+static int num_replaced = 0;
 
 MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const & opt)
        : p_buf(&buf), p_first_buf(&buf), opt(opt)
@@ -2603,6 +2646,8 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
        Buffer & find_buf = *theBufferList().getBuffer(FileName(to_utf8(opt.find_buf_name)), true);
        docstring const & ds = stringifySearchBuffer(find_buf, opt);
        use_regexp = lyx::to_utf8(ds).find("\\regexp{") != std::string::npos;
+       if (!opt.replace_all)
+               num_replaced = 0;       // count number of replaced strings
        // When using regexp, braces are hacked already by escape_for_regex()
        par_as_string = normalize(ds, !use_regexp);
        open_braces = 0;
@@ -2819,7 +2864,7 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be
 
                // Exclude from the returned match length any length
                // due to close wildcards added at end of regexp
-               // and also the length of the leading (e.g. '\emph{')
+               // and also the length of the leading (e.g. '\emph{}')
                //
                // Whole found string, including the leading: m[0].second - m[0].first
                // Size of the leading string: m[1].second - m[1].first
@@ -2993,7 +3038,8 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
                // TODO Try adding a AS_STR_INSERTS as last arg
                pos_type end = ( len == -1 || cur.pos() + len > int(par.size()) ) ?
                        int(par.size()) : cur.pos() + len;
-               OutputParams runparams(&cur.buffer()->params().encoding());
+               // OutputParams runparams(&cur.buffer()->params().encoding());
+               OutputParams runparams(encodings.fromLyXName("utf8"));
                runparams.nice = true;
                runparams.flavor = OutputParams::XETEX;
                runparams.linelen = 10000; //lyxrc.plaintext_linelen;
@@ -3038,7 +3084,8 @@ docstring latexifyFromCursor(DocIterator const & cur, int len)
 
        odocstringstream ods;
        otexstream os(ods);
-       OutputParams runparams(&buf.params().encoding());
+       //OutputParams runparams(&buf.params().encoding());
+       OutputParams runparams(encodings.fromLyXName("utf8"));
        runparams.nice = false;
        runparams.flavor = OutputParams::XETEX;
        runparams.linelen = 8000; //lyxrc.plaintext_linelen;
@@ -3224,7 +3271,9 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
                                DocIterator old_cur = cur;
                                for (int i = 0; i < increment && cur; cur.forwardPos(), i++) {
                                }
-                               if (! cur) {
+                               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;
                                        increment /= 2;
                                }
@@ -3391,10 +3440,10 @@ FindAndReplaceOptions::FindAndReplaceOptions(
        docstring const & find_buf_name, bool casesensitive,
        bool matchword, bool forward, bool expandmacros, bool ignoreformat,
        docstring const & repl_buf_name, bool keep_case,
-       SearchScope scope, SearchRestriction restr)
+       SearchScope scope, SearchRestriction restr, bool replace_all)
        : find_buf_name(find_buf_name), casesensitive(casesensitive), matchword(matchword),
          forward(forward), expandmacros(expandmacros), ignoreformat(ignoreformat),
-         repl_buf_name(repl_buf_name), keep_case(keep_case), scope(scope), restr(restr)
+         repl_buf_name(repl_buf_name), keep_case(keep_case), scope(scope), restr(restr), replace_all(replace_all)
 {
 }
 
@@ -3456,29 +3505,29 @@ static void changeFirstCase(Buffer & buffer, TextCase first_case, TextCase other
 } // namespace
 
 ///
-static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, MatchStringAdv & matchAdv)
+static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, MatchStringAdv & matchAdv)
 {
        Cursor & cur = bv->cursor();
        if (opt.repl_buf_name == docstring()
            || theBufferList().getBuffer(FileName(to_utf8(opt.repl_buf_name)), true) == 0
            || theBufferList().getBuffer(FileName(to_utf8(opt.find_buf_name)), true) == 0)
-               return;
+               return 0;
 
        DocIterator sel_beg = cur.selectionBegin();
        DocIterator sel_end = cur.selectionEnd();
        if (&sel_beg.inset() != &sel_end.inset()
            || sel_beg.pit() != sel_end.pit()
            || sel_beg.idx() != sel_end.idx())
-               return;
+               return 0;
        int sel_len = sel_end.pos() - sel_beg.pos();
        LYXERR(Debug::FIND, "sel_beg: " << sel_beg << ", sel_end: " << sel_end
               << ", sel_len: " << sel_len << endl);
        if (sel_len == 0)
-               return;
-       LASSERT(sel_len > 0, return);
+               return 0;
+       LASSERT(sel_len > 0, return 0);
 
        if (!matchAdv(sel_beg, sel_len).match_len)
-               return;
+               return 0;
 
        // Build a copy of the replace buffer, adapted to the KeepCase option
        Buffer & repl_buffer_orig = *theBufferList().getBuffer(FileName(to_utf8(opt.repl_buf_name)), true);
@@ -3487,7 +3536,7 @@ static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, M
        string lyx = oss.str();
        Buffer repl_buffer("", false);
        repl_buffer.setUnnamed(true);
-       LASSERT(repl_buffer.readString(lyx), return);
+       LASSERT(repl_buffer.readString(lyx), return 0);
        if (opt.keep_case && sel_len >= 2) {
                LYXERR(Debug::FIND, "keep_case true: cur.pos()=" << cur.pos() << ", sel_len=" << sel_len);
                if (cur.inTexted()) {
@@ -3512,7 +3561,8 @@ static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, M
        } else if (cur.inMathed()) {
                odocstringstream ods;
                otexstream os(ods);
-               OutputParams runparams(&repl_buffer.params().encoding());
+               // OutputParams runparams(&repl_buffer.params().encoding());
+               OutputParams runparams(encodings.fromLyXName("utf8"));
                runparams.nice = false;
                runparams.flavor = OutputParams::XETEX;
                runparams.linelen = 8000; //lyxrc.plaintext_linelen;
@@ -3539,6 +3589,7 @@ static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, M
        LYXERR(Debug::FIND, "After pos adj cur=" << cur << " with depth: " << cur.depth() << " and len: " << sel_len);
        bv->putSelectionAt(DocIterator(cur), sel_len, !opt.forward);
        bv->processUpdateFlags(Update::Force);
+       return 1;
 }
 
 
@@ -3558,7 +3609,7 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt)
                int length = bv->cursor().selectionEnd().pos() - bv->cursor().selectionBegin().pos();
                if (length > 0)
                        bv->putSelectionAt(bv->cursor().selectionBegin(), length, !opt.forward);
-               findAdvReplace(bv, opt, matchAdv);
+               num_replaced += findAdvReplace(bv, opt, matchAdv);
                cur = bv->cursor();
                if (opt.forward)
                        match_len = findForwardAdv(cur, matchAdv);
@@ -3571,11 +3622,31 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt)
        }
 
        if (match_len == 0) {
-               bv->message(_("Match not found!"));
+               if (num_replaced > 0) {
+                       switch (num_replaced)
+                       {
+                               case 1:
+                                       bv->message(_("One match has been replaced."));
+                                       break;
+                               case 2:
+                                       bv->message(_("Two matches have been replaced."));
+                                       break;
+                               default:
+                                       bv->message(bformat(_("%1$d matches have been replaced."), num_replaced));
+                                       break;
+                       }
+                       num_replaced = 0;
+               }
+               else {
+                       bv->message(_("Match not found."));
+               }
                return false;
        }
 
-       bv->message(_("Match found!"));
+       if (num_replaced > 0)
+               bv->message(_("Match has been replaced."));
+       else
+               bv->message(_("Match found."));
 
        LYXERR(Debug::FIND, "Putting selection at cur=" << cur << " with len: " << match_len);
        bv->putSelectionAt(cur, match_len, !opt.forward);
@@ -3592,6 +3663,7 @@ ostringstream & operator<<(ostringstream & os, FindAndReplaceOptions const & opt
           << opt.forward << ' '
           << opt.expandmacros << ' '
           << opt.ignoreformat << ' '
+          << opt.replace_all << ' '
           << to_utf8(opt.repl_buf_name) << "\nEOSS\n"
           << opt.keep_case << ' '
           << int(opt.scope) << ' '
@@ -3619,7 +3691,7 @@ istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt)
        }
        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;
+       is >> opt.casesensitive >> opt.matchword >> opt.forward >> opt.expandmacros >> opt.ignoreformat >> opt.replace_all;
        is.get();       // Waste space before replace string
        s = "";
        getline(is, line);