#include "lyxfind.h"
#include "Buffer.h"
+#include "BufferList.h"
#include "buffer_funcs.h"
#include "BufferParams.h"
#include "BufferView.h"
#include "support/lstrings.h"
#include "support/lassert.h"
+#include "frontends/Application.h"
+#include "frontends/LyXView.h"
+
#include <boost/regex.hpp>
#include <boost/next_prior.hpp>
// clear the selection and search the other way around (see the end
// of this function). This will avoid changes to be selected half.
bool search_both_sides = false;
- if (cur.pos() > 1) {
+ if (cur.pos() > 0) {
Change change_next_pos
= cur.paragraph().lookupChange(cur.pos());
Change change_prev_pos
}
}
if (open_pars != unmatched) {
- LYXERR(Debug::FIND, "Found " << open_pars << " instead of " << unmatched << " unmatched open braces at the end of count");
+ 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");
**/
class MatchStringAdv {
public:
- MatchStringAdv(lyx::Buffer const & buf, FindAndReplaceOptions const & opt);
+ MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const & opt);
/** Tests if text starting at the supplied position matches with the one provided to the MatchStringAdv
** constructor as opt.search, under the opt.* options settings.
public:
/// buffer
- lyx::Buffer const & buf;
+ lyx::Buffer * p_buf;
+ /// first buffer on which search was started
+ lyx::Buffer * const p_first_buf;
/// options
FindAndReplaceOptions const & opt;
};
-MatchStringAdv::MatchStringAdv(lyx::Buffer const & buf, FindAndReplaceOptions const & opt)
- : buf(buf), opt(opt)
+MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const & opt)
+ : p_buf(&buf), p_first_buf(&buf), opt(opt)
{
par_as_string = normalize(opt.search);
open_braces = 0;
// Insert .* before trailing '\\\]' ('\]' has been escaped by escape_for_regex)
|| regex_replace(par_as_string, par_as_string, "(.*[^\\\\])(\\\\\\\\\\\\\\])\\'", "$1(.*?)$2")
// Insert .* before trailing '\\end\{...}' ('\end{...}' has been escaped by escape_for_regex)
- || regex_replace(par_as_string, par_as_string, "(.*[^\\\\])(\\\\\\\\end\\\\\\{[a-zA-Z_]*\\\\\\})\\'", "$1(.*?)$2")
+ || regex_replace(par_as_string, par_as_string,
+ "(.*[^\\\\])(\\\\\\\\end\\\\\\{[a-zA-Z_]*\\\\\\})\\'", "$1(.*?)$2")
// Insert .* before trailing '\}' ('}' has been escaped by escape_for_regex)
|| regex_replace(par_as_string, par_as_string, "(.*[^\\\\])(\\\\\\})\\'", "$1(.*?)$2")
) {
return par_as_string.size();
}
} else {
- // Try all possible regexp matches, until one that verifies the braces match test is found
+ // Try all possible regexp matches,
+ //until one that verifies the braces match test is found
boost::regex const *p_regexp = at_begin ? ®exp : ®exp2;
boost::sregex_iterator re_it(str.begin(), str.end(), *p_regexp);
boost::sregex_iterator re_it_end;
for (size_t i = 1; i < m.size(); ++i)
if (! braces_match(m[i].first, m[i].second))
return false;
- // Exclude from the returned match length any length due to close wildcards added at end of regexp
+ // Exclude from the returned match length any length
+ // due to close wildcards added at end of regexp
if (close_wildcards == 0)
return m[0].second - m[0].first;
else
Paragraph const & par = cur.paragraph();
// TODO what about searching beyond/across paragraph breaks ?
// 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;
+ pos_type end = ( len == -1 || cur.pos() + len > int(par.size()) ) ?
+ int(par.size()) : cur.pos() + len;
OutputParams runparams(&cur.buffer()->params().encoding());
odocstringstream os;
runparams.nice = true;
runparams.linelen = 100000; //lyxrc.plaintext_linelen;
// No side effect of file copying and image conversion
runparams.dryrun = true;
- LYXERR(Debug::FIND, "Stringifying with cur: " << cur << ", from pos: " << cur.pos() << ", end: " << end);
+ LYXERR(Debug::FIND, "Stringifying with cur: "
+ << cur << ", from pos: " << cur.pos() << ", end: " << end);
return par.stringify(cur.pos(), end, AS_STR_INSETS, runparams);
} else if (cur.inMathed()) {
odocstringstream os;
CursorSlice cs = cur.top();
MathData md = cs.cell();
- MathData::const_iterator it_end = ( ( len == -1 || cs.pos() + len > int(md.size()) ) ? md.end() : md.begin() + cs.pos() + len );
+ MathData::const_iterator it_end =
+ ( ( len == -1 || cs.pos() + len > int(md.size()) )
+ ? md.end() : md.begin() + cs.pos() + len );
for (MathData::const_iterator it = md.begin() + cs.pos(); it != it_end; ++it)
os << *it;
return os.str();
return ods.str();
}
+
/** Finalize an advanced find operation, advancing the cursor to the innermost
** position that matches, plus computing the length of the matching text to
** be selected
/// Finds forward
-int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
+int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
{
if (!cur)
return 0;
- int wrap_answer;
- do {
- while (cur && !match(cur, -1, false)) {
- if (cur.pit() < cur.lastpit())
- cur.forwardPar();
- else {
- cur.forwardPos();
- }
- }
- for (; cur; cur.forwardPos()) {
- if (match(cur))
- return findAdvFinalize(cur, match);
+ while (cur && !match(cur, -1, false)) {
+ if (cur.pit() < cur.lastpit())
+ cur.forwardPar();
+ else {
+ cur.forwardPos();
}
- wrap_answer = frontend::Alert::prompt(
- _("Wrap search ?"),
- _("End of document reached while searching forward\n"
- "\n"
- "Continue searching from beginning ?"),
- 0, 1, _("&Yes"), _("&No"));
- cur.clear();
- cur.push_back(CursorSlice(match.buf.inset()));
- } while (wrap_answer == 0);
+ }
+ for (; cur; cur.forwardPos()) {
+ if (match(cur))
+ return findAdvFinalize(cur, match);
+ }
return 0;
}
+
/// Find the most backward consecutive match within same paragraph while searching backwards.
-void findMostBackwards(DocIterator & cur, MatchStringAdv const & match, int & len) {
+void findMostBackwards(DocIterator & cur, MatchStringAdv const & match, int & len)
+{
DocIterator cur_begin = doc_iterator_begin(cur.buffer());
len = findAdvFinalize(cur, match);
if (cur != cur_begin) {
old_cur = cur;
old_len = len;
cur.backwardPos();
- LYXERR(Debug::FIND, "findMostBackwards(): old_cur=" << old_cur << ", old_len=" << len << ", cur=" << cur);
+ LYXERR(Debug::FIND, "findMostBackwards(): old_cur="
+ << old_cur << ", old_len=" << len << ", cur=" << cur);
dit2 = cur;
} while (cur != cur_begin && &cur.inset() == &inset && match(cur)
&& (len = findAdvFinalize(dit2, match)) > old_len);
LYXERR(Debug::FIND, "findMostBackwards(): cur=" << cur);
}
+
/// Finds backwards
-int findBackwardsAdv(DocIterator & cur, MatchStringAdv const & match) {
+int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) {
if (! cur)
return 0;
+ // Backup of original position
DocIterator cur_orig(cur);
DocIterator cur_begin = doc_iterator_begin(cur.buffer());
-/* if (match(cur_orig)) */
-/* findAdvFinalize(cur_orig, match); */
- int wrap_answer = 0;
+ if (cur == cur_begin)
+ return 0;
bool found_match;
+ bool pit_changed = false;
+ found_match = false;
do {
- bool pit_changed = false;
- found_match = false;
- // Search in current par occurs from start to end, but in next loop match is discarded if pos > original pos
cur.pos() = 0;
found_match = match(cur, -1, false);
- LYXERR(Debug::FIND, "findBackAdv0: found_match=" << found_match << ", cur: " << cur);
- while (cur != cur_begin) {
- if (found_match)
- break;
- if (cur.pit() > 0)
- --cur.pit();
- else
- cur.backwardPos();
- pit_changed = true;
- // Search in previous pars occurs from start to end
- cur.pos() = 0;
- found_match = match(cur, -1, false);
- LYXERR(Debug::FIND, "findBackAdv1: found_match=" << found_match << ", cur: " << cur);
- }
- if (pit_changed)
- cur.pos() = cur.lastpos();
- else
- cur.pos() = cur_orig.pos();
- LYXERR(Debug::FIND, "findBackAdv2: cur: " << cur);
+
if (found_match) {
+ if (pit_changed)
+ cur.pos() = cur.lastpos();
+ else
+ cur.pos() = cur_orig.pos();
+ LYXERR(Debug::FIND, "findBackAdv2: cur: " << cur);
+ DocIterator cur_prev_iter;
while (true) {
- found_match=match(cur);
- LYXERR(Debug::FIND, "findBackAdv3: found_match=" << found_match << ", cur: " << cur);
+ found_match = match(cur);
+ LYXERR(Debug::FIND, "findBackAdv3: found_match="
+ << found_match << ", cur: " << cur);
if (found_match) {
int len;
findMostBackwards(cur, match, len);
- if (&cur.inset() != &cur_orig.inset() || !(cur.pit()==cur_orig.pit()) || cur.pos() < cur_orig.pos())
+ if (cur < cur_orig)
return len;
}
- if (cur == cur_begin)
+ // Prevent infinite loop at begin of document
+ if (cur == cur_begin || cur == cur_prev_iter)
break;
+ cur_prev_iter = cur;
cur.backwardPos();
- };
+ }
}
- wrap_answer = frontend::Alert::prompt(
- _("Wrap search ?"),
- _("Beginning of document reached while searching backwards\n"
- "\n"
- "Continue searching from end ?"),
- 0, 1, _("&Yes"), _("&No"));
- cur = doc_iterator_end(&match.buf);
- cur.backwardPos();
- } while (wrap_answer == 0);
- cur = cur_orig;
+ if (cur == cur_begin)
+ break;
+ if (cur.pit() > 0)
+ --cur.pit();
+ else
+ cur.backwardPos();
+ pit_changed = true;
+ } while (true);
return 0;
}
+
} // anonym namespace
FindAndReplaceOptions::FindAndReplaceOptions(docstring const & search, bool casesensitive,
bool matchword, bool forward, bool expandmacros, bool ignoreformat,
- bool regexp, docstring const & replace, bool keep_case)
+ bool regexp, docstring const & replace, bool keep_case,
+ SearchScope scope)
: search(search), casesensitive(casesensitive), matchword(matchword),
forward(forward), expandmacros(expandmacros), ignoreformat(ignoreformat),
- regexp(regexp), replace(replace), keep_case(keep_case)
+ regexp(regexp), replace(replace), keep_case(keep_case), scope(scope)
{
}
ch2 = cur.paragraph().getChar(cur.pos()+1);
bool result = isUpperCase(ch1) && isLowerCase(ch2);
LYXERR(Debug::FIND, "firstUppercase(): "
- << "ch1=" << ch1 << "(" << char(ch1) << "), ch2=" << ch2 << "(" << char(ch2) << ")"
+ << "ch1=" << ch1 << "(" << char(ch1) << "), ch2="
+ << ch2 << "(" << char(ch2) << ")"
<< ", result=" << result << ", cur=" << cur);
return result;
}
bv->message(_("Search text is empty!"));
return false;
}
-// if (! bv->buffer()) {
-// bv->message(_("No open document !"));
-// return false;
-// }
+ MatchStringAdv matchAdv(bv->buffer(), opt);
try {
- MatchStringAdv const matchAdv(bv->buffer(), opt);
if (opt.forward)
match_len = findForwardAdv(cur, matchAdv);
else
return false;
}
- LYXERR(Debug::FIND, "Putting selection at " << cur << " with len: " << match_len);
+ LYXERR(Debug::FIND, "Putting selection at buf=" << matchAdv.p_buf
+ << "cur=" << cur << " with len: " << match_len);
+
bv->putSelectionAt(cur, match_len, ! opt.forward);
if (opt.replace == docstring(from_utf8(LYX_FR_NULL_STRING))) {
- bv->message(_("Match found !"));
+ bv->message(_("Match found!"));
} else {
string lyx = to_utf8(opt.replace);
// FIXME: Seems so stupid to me to rebuild a buffer here,
runparams.linelen = 8000; //lyxrc.plaintext_linelen;
runparams.dryrun = true;
TexRow texrow;
- TeXOnePar(repl_buffer, repl_buffer.text(), repl_buffer.paragraphs().begin(), ods, texrow, runparams);
+ TeXOnePar(repl_buffer, repl_buffer.text(),
+ repl_buffer.paragraphs().begin(), ods, texrow, runparams);
//repl_buffer.getSourceCode(ods, 0, repl_buffer.paragraphs().size(), false);
docstring repl_latex = ods.str();
LYXERR(Debug::FIND, "Latexified replace_buffer: '" << repl_latex << "'");
bv->message(_("Match found and replaced !"));
} else
LASSERT(false, /**/);
- // dispatch(FuncRequest(LFUN_SELF_INSERT, opt.replace));
}
return true;
}
-void findAdv(BufferView * bv, FuncRequest const & ev)
-{
- if (!bv || ev.action != LFUN_WORD_FINDADV)
- return;
-
- FindAndReplaceOptions opt;
- istringstream iss(to_utf8(ev.argument()));
- iss >> opt;
- findAdv(bv, opt);
-}
-
-
ostringstream & operator<<(ostringstream & os, lyx::FindAndReplaceOptions const & opt)
{
os << to_utf8(opt.search) << "\nEOSS\n"
<< opt.ignoreformat << ' '
<< opt.regexp << ' '
<< to_utf8(opt.replace) << "\nEOSS\n"
- << opt.keep_case;
+ << opt.keep_case << ' '
+ << int(opt.scope);
LYXERR(Debug::FIND, "built: " << os.str());
getline(is, line);
}
is >> opt.keep_case;
+ int i;
+ is >> i;
+ opt.scope = FindAndReplaceOptions::SearchScope(i);
LYXERR(Debug::FIND, "parsed: " << opt.casesensitive << ' ' << opt.matchword << ' ' << opt.forward << ' '
<< opt.expandmacros << ' ' << opt.ignoreformat << ' ' << opt.regexp << ' ' << opt.keep_case);
LYXERR(Debug::FIND, "replacing with: '" << s << "'");