AdvSearch - next patch from Tommaso.

http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg146966.html


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@27938 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Pavel Sanda 2008-12-20 16:00:47 +00:00
parent d5f2772922
commit fd6679bd34
5 changed files with 170 additions and 72 deletions

View File

@ -2448,6 +2448,29 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options) const
} }
docstring Paragraph::stringify(pos_type beg, pos_type end, int options, OutputParams & runparams) const
{
odocstringstream os;
if (beg == 0
&& options & AS_STR_LABEL
&& !d->params_.labelString().empty())
os << d->params_.labelString() << ' ';
for (pos_type i = beg; i < end; ++i) {
char_type const c = d->text_[i];
if (isPrintable(c) || c == '\t'
|| (c == '\n' && options & AS_STR_NEWLINES))
os.put(c);
else if (c == META_INSET && options & AS_STR_INSETS) {
getInset(i)->plaintext(os, runparams);
}
}
return os.str();
}
void Paragraph::setInsetOwner(Inset const * inset) void Paragraph::setInsetOwner(Inset const * inset)
{ {
d->inset_owner_ = inset; d->inset_owner_ = inset;

View File

@ -124,6 +124,10 @@ public:
docstring asString(pos_type beg, pos_type end, docstring asString(pos_type beg, pos_type end,
int options = AS_STR_NONE) const; int options = AS_STR_NONE) const;
/// Extract only the explicitly visible text (without any formatting),
/// descending into insets
docstring stringify(pos_type beg, pos_type end, int options, OutputParams & runparams) const;
/// ///
void write(std::ostream &, BufferParams const &, void write(std::ostream &, BufferParams const &,
depth_type & depth) const; depth_type & depth) const;

View File

@ -106,9 +106,15 @@ void FindAndReplace::findAdv(bool casesensitive,
} else { } else {
ParIterator it = buffer.par_iterator_begin(); ParIterator it = buffer.par_iterator_begin();
ParIterator end = buffer.par_iterator_end(); ParIterator end = buffer.par_iterator_end();
OutputParams runparams(&buffer.params().encoding());
odocstringstream os;
runparams.nice = true;
runparams.flavor = OutputParams::LATEX;
runparams.linelen = 100000; //lyxrc.plaintext_linelen;
runparams.dryrun = true;
for (; it != end; ++it) { for (; it != end; ++it) {
LYXERR0("Adding to search string: '" << it->asString(false) << "'"); LYXERR0("Adding to search string: '" << it->asString(false) << "'");
searchString += it->asString(AS_STR_INSETS); searchString += it->stringify(pos_type(0), it->size(), AS_STR_INSETS, runparams);
} }
} }
// lyxerr << "Searching for '" << to_utf8(searchString) << "'" << std::endl; // lyxerr << "Searching for '" << to_utf8(searchString) << "'" << std::endl;

View File

@ -1,7 +1,7 @@
/** /**
* \file lyxfind.cpp * \file lyxfind.cpp
* This file is part of LyX, the document processor. * This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING. * License details can be found in the file COPYING.
* *
* \author Lars Gullik Bjønnes * \author Lars Gullik Bjønnes
* \author John Levon * \author John Levon
@ -43,8 +43,10 @@
#include "support/docstream.h" #include "support/docstream.h"
#include "support/gettext.h" #include "support/gettext.h"
#include "support/lstrings.h" #include "support/lstrings.h"
#include "support/lassert.h"
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/next_prior.hpp>
using namespace std; using namespace std;
using namespace lyx::support; using namespace lyx::support;
@ -418,7 +420,7 @@ string apply_escapes(string s, Escapes const & escape_map)
**/ **/
size_t find_matching_brace(string const & s, size_t pos) size_t find_matching_brace(string const & s, size_t pos)
{ {
BOOST_ASSERT(s[pos] == '{'); LASSERT(s[pos] == '{', /* */);
int open_braces = 1; int open_braces = 1;
for (++pos; pos < s.size(); ++pos) { for (++pos; pos < s.size(); ++pos) {
if (s[pos] == '\\') if (s[pos] == '\\')
@ -534,10 +536,14 @@ public:
/** Tests if text starting at the supplied position matches with the one provided to the MatchStringAdv /** 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. ** constructor as opt.search, under the opt.* options settings.
** **
** @param at_begin
** If set, then match is searched only against beginning of text starting at cur.
** If unset, then match is searched anywhere in text starting at cur.
**
** @return ** @return
** The length of the matching text, or zero if no match was found. ** The length of the matching text, or zero if no match was found.
**/ **/
int operator()(DocIterator const & cur, int len = -1) const; int operator()(DocIterator const & cur, int len = -1, bool at_begin = true) const;
public: public:
/// buffer /// buffer
@ -564,6 +570,8 @@ private:
string par_as_string; string par_as_string;
// regular expression to use for searching // regular expression to use for searching
boost::regex regexp; boost::regex regexp;
// same as regexp, but prefixed with a ".*"
boost::regex regexp2;
// unmatched open braces in the search string/regexp // unmatched open braces in the search string/regexp
int open_braces; int open_braces;
// number of (.*?) subexpressions added at end of search regexp for closing // number of (.*?) subexpressions added at end of search regexp for closing
@ -599,7 +607,7 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer const & buf, FindAdvOptions const & o
break; break;
} while (true); } while (true);
LYXERR(Debug::DEBUG, "Open braces: " << open_braces); LYXERR(Debug::DEBUG, "Open braces: " << open_braces);
BOOST_ASSERT(braces_match(par_as_string.begin(), par_as_string.end(), open_braces)); LASSERT(braces_match(par_as_string.begin(), par_as_string.end(), open_braces), /* */);
LYXERR(Debug::DEBUG, "Built MatchStringAdv object: par_as_string = '" << par_as_string << "'"); LYXERR(Debug::DEBUG, "Built MatchStringAdv object: par_as_string = '" << par_as_string << "'");
} else { } else {
par_as_string = escape_for_regex(par_as_string); par_as_string = escape_for_regex(par_as_string);
@ -620,26 +628,35 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer const & buf, FindAdvOptions const & o
LYXERR(Debug::DEBUG, "par_as_string now is '" << par_as_string << "'"); LYXERR(Debug::DEBUG, "par_as_string now is '" << par_as_string << "'");
LYXERR(Debug::DEBUG, "Open braces: " << open_braces); LYXERR(Debug::DEBUG, "Open braces: " << open_braces);
LYXERR(Debug::DEBUG, "Close .*? : " << close_wildcards); LYXERR(Debug::DEBUG, "Close .*? : " << close_wildcards);
BOOST_ASSERT(braces_match(par_as_string.begin(), par_as_string.end(), open_braces)); LASSERT(braces_match(par_as_string.begin(), par_as_string.end(), open_braces), /* */);
// Entered regexp must match at begin of searched string buffer // Entered regexp must match at begin of searched string buffer
par_as_string = string("\\`") + par_as_string; par_as_string = string("\\`") + par_as_string;
LYXERR(Debug::DEBUG, "Replaced text (to be used as regex): " << par_as_string); LYXERR(Debug::DEBUG, "Replaced text (to be used as regex): " << par_as_string);
regexp = boost::regex(par_as_string); regexp = boost::regex(par_as_string);
regexp2 = boost::regex(string(".*") + par_as_string);
} }
} }
int MatchStringAdv::operator()(DocIterator const & cur, int len) const
int MatchStringAdv::operator()(DocIterator const & cur, int len, bool at_begin) const
{ {
docstring docstr = stringifyFromForSearch(opt, buf, cur, len); docstring docstr = stringifyFromForSearch(opt, cur, len);
LYXERR(Debug::DEBUG, "Matching against '" << lyx::to_utf8(docstr) << "'"); LYXERR(Debug::DEBUG, "Matching against '" << lyx::to_utf8(docstr) << "'");
string str = normalize(docstr); string str = normalize(docstr);
LYXERR(Debug::DEBUG, "After normalization: '" << str << "'"); LYXERR(Debug::DEBUG, "After normalization: '" << str << "'");
if (! opt.regexp) { if (! opt.regexp) {
if (str.substr(0, par_as_string.size()) == par_as_string) if (at_begin) {
return par_as_string.size(); if (str.substr(0, par_as_string.size()) == par_as_string)
return par_as_string.size();
} else {
size_t pos = str.find(par_as_string);
if (pos != string::npos)
return par_as_string.size();
}
} else { } 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::sregex_iterator re_it(str.begin(), str.end(), regexp); boost::regex const *p_regexp = at_begin ? &regexp : &regexp2;
boost::sregex_iterator re_it(str.begin(), str.end(), *p_regexp);
boost::sregex_iterator re_it_end; boost::sregex_iterator re_it_end;
for (; re_it != re_it_end; ++re_it) { for (; re_it != re_it_end; ++re_it) {
boost::match_results<string::const_iterator> const & m = *re_it; boost::match_results<string::const_iterator> const & m = *re_it;
@ -693,7 +710,16 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
Paragraph const & par = cur.paragraph(); Paragraph const & par = cur.paragraph();
// TODO what about searching beyond/across paragraph breaks ? // TODO what about searching beyond/across paragraph breaks ?
// TODO Try adding a AS_STR_INSERTS as last arg // TODO Try adding a AS_STR_INSERTS as last arg
return par.asString(cur.pos(), ( len == -1 || cur.pos() + len > int(par.size()) ) ? int(par.size()) : cur.pos() + len, AS_STR_INSETS); 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.flavor = OutputParams::LATEX;
runparams.linelen = 100000; //lyxrc.plaintext_linelen;
// No side effect of file copying and image conversion
runparams.dryrun = true;
LYXERR(Debug::DEBUG, "Stringifying with cur: " << cur << ", from pos: " << cur.pos() << ", end: " << end);
return par.stringify(cur.pos(), end, AS_STR_INSETS, runparams);
} else if (cur.inMathed()) { } else if (cur.inMathed()) {
odocstringstream os; odocstringstream os;
CursorSlice cs = cur.top(); CursorSlice cs = cur.top();
@ -712,12 +738,13 @@ docstring stringifyFromCursor(DocIterator const & cur, int len)
* if len is -1. * if len is -1.
*/ */
docstring latexifyFromCursor(Buffer const & buf, DocIterator const & cur, int len) docstring latexifyFromCursor(DocIterator const & cur, int len)
{ {
LYXERR(Debug::DEBUG, "Latexifying with len=" << len << " from cursor at pos: " << cur); LYXERR(Debug::DEBUG, "Latexifying with len=" << len << " from cursor at pos: " << cur);
LYXERR(Debug::DEBUG, " with cur.lastpost=" << cur.lastpos() << ", cur.lastrow=" LYXERR(Debug::DEBUG, " with cur.lastpost=" << cur.lastpos() << ", cur.lastrow="
<< cur.lastrow() << ", cur.lastcol=" << cur.lastcol()); << cur.lastrow() << ", cur.lastcol=" << cur.lastcol());
BOOST_ASSERT(buf.isLatex()); Buffer const & buf = *cur.buffer();
LASSERT(buf.isLatex(), /* */);
TexRow texrow; TexRow texrow;
odocstringstream ods; odocstringstream ods;
@ -795,13 +822,13 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
size_t d; size_t d;
DocIterator old_cur(cur.buffer()); DocIterator old_cur(cur.buffer());
do { do {
LYXERR(Debug::DEBUG, "Forwarding one step (searching for innermost match)"); LYXERR(Debug::DEBUG, "Forwarding one step (searching for innermost match)");
d = cur.depth(); d = cur.depth();
old_cur = cur; old_cur = cur;
cur.forwardPos(); cur.forwardPos();
} while (cur && cur.depth() > d && match(cur) > 0); } while (cur && cur.depth() > d && match(cur) > 0);
cur = old_cur; cur = old_cur;
BOOST_ASSERT(match(cur) > 0); LASSERT(match(cur) > 0, /* */);
LYXERR(Debug::DEBUG, "Ok"); LYXERR(Debug::DEBUG, "Ok");
// Compute the match length // Compute the match length
@ -823,69 +850,104 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
return len; return len;
} }
/// Finds forward /// Finds forward
int findForwardAdv(DocIterator & cur, MatchStringAdv const & match) int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
{ {
if (!cur) if (!cur)
return 0; return 0;
for (; cur; cur.forwardPos()) { int wrap_answer;
// odocstringstream ods; do {
// ods << _("Searching ... ") while (cur && !match(cur, -1, false)) {
// << (cur.bottom().lastpit() - cur.bottom().pit()) * 100 / total; if (cur.pit() < cur.lastpit())
// cur.message(ods.str()); cur.forwardPar();
if (match(cur)) else {
return findAdvFinalize(cur, match); cur.forwardPos();
} }
}
for (; cur; cur.forwardPos()) {
if (match(cur))
return findAdvFinalize(cur, match);
}
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);
return 0; return 0;
} }
/// Finds backwards /// Finds backwards
int findBackwardsAdv(DocIterator & cur, MatchStringAdv const & match) int findBackwardsAdv(DocIterator & cur, MatchStringAdv const & match) {
{
// if (cur.pos() > 0 || cur.depth() > 0) // if (cur.pos() > 0 || cur.depth() > 0)
// cur.backwardPos(); // cur.backwardPos();
DocIterator cur_orig(cur); DocIterator cur_orig(cur);
if (match(cur_orig)) if (match(cur_orig))
findAdvFinalize(cur_orig, match); findAdvFinalize(cur_orig, match);
// int total = cur.bottom().pit() + 1; // int total = cur.bottom().pit() + 1;
for (; cur; cur.backwardPos()) { int wrap_answer;
// odocstringstream ods; do {
// ods << _("Searching ... ") << (total - cur.bottom().pit()) * 100 / total; // TODO No ! così non va.
// cur.message(ods.str()); bool pit_changed = false;
if (match(cur)) { while (cur && !match(cur, -1, false)) {
// Find the most backward consecutive match within same if (cur.pit() > 0)
// paragraph while searching backwards. --cur.pit();
int pit = cur.pit(); else {
int old_len;
DocIterator old_cur;
int len = findAdvFinalize(cur, match);
do {
old_cur = cur;
old_len = len;
cur.backwardPos(); cur.backwardPos();
LYXERR(Debug::DEBUG, "old_cur: " << old_cur if (cur)
<< ", old_len: " << len << ", cur: " << cur); cur.pos() = 0;
} while (cur && cur.pit() == pit && match(cur) }
&& (len = findAdvFinalize(cur, match)) > old_len); pit_changed = true;
cur = old_cur;
len = old_len;
LYXERR(Debug::DEBUG, "cur_orig : " << cur_orig);
LYXERR(Debug::DEBUG, "cur : " << cur);
if (cur != cur_orig)
return len;
} }
} if (cur && pit_changed)
cur.pos() = cur.lastpos();
for (; cur; cur.backwardPos()) {
if (match(cur)) {
// Find the most backward consecutive match within same paragraph while searching backwards.
int pit = cur.pit();
int old_len;
DocIterator old_cur;
int len = findAdvFinalize(cur, match);
do {
old_cur = cur;
old_len = len;
cur.backwardPos();
LYXERR(Debug::DEBUG, "old_cur: " << old_cur << ", old_len=" << len << ", cur: " << cur);
} while (cur && cur.pit() == pit && match(cur)
&& (len = findAdvFinalize(cur, match)) > old_len);
cur = old_cur;
len = old_len;
LYXERR(Debug::DEBUG, "cur_orig : " << cur_orig);
LYXERR(Debug::DEBUG, "cur : " << cur);
if (cur != cur_orig)
return len;
}
}
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);
return 0; return 0;
} }
} // anonym namespace } // anonym namespace
docstring stringifyFromForSearch(FindAdvOptions const & opt, Buffer const & buf, docstring stringifyFromForSearch(FindAdvOptions const & opt,
DocIterator const & cur, int len) DocIterator const & cur, int len)
{ {
if (!opt.ignoreformat) if (!opt.ignoreformat)
return latexifyFromCursor(buf, cur, len); return latexifyFromCursor(cur, len);
else else
return stringifyFromCursor(cur, len); return stringifyFromCursor(cur, len);
} }

View File

@ -68,22 +68,23 @@ bool findNextChange(BufferView * bv);
class FindAdvOptions { class FindAdvOptions {
public: public:
FindAdvOptions( FindAdvOptions(
docstring const & search, docstring const & search,
bool casesensitive, bool casesensitive,
bool matchword, bool matchword,
bool forward, bool forward,
bool expandmacros, bool expandmacros,
bool ignoreformat, bool ignoreformat,
bool regexp); bool regexp
FindAdvOptions() {} );
docstring search; FindAdvOptions() { }
bool casesensitive; docstring search;
bool matchword; bool casesensitive;
bool forward; bool matchword;
bool expandmacros; bool forward;
bool ignoreformat; bool expandmacros;
bool regexp; bool ignoreformat;
bool regexp;
}; };
/// Write a FindAdvOptions instance to a stringstream /// Write a FindAdvOptions instance to a stringstream
@ -105,8 +106,10 @@ bool findAdv(BufferView * bv, FindAdvOptions const & opt);
** This is useful for computing opt.search from the SearchAdvDialog controller (ControlSearchAdv). ** This is useful for computing opt.search from the SearchAdvDialog controller (ControlSearchAdv).
** Ideally, this should not be needed, and the opt.search field should become a Text const &. ** Ideally, this should not be needed, and the opt.search field should become a Text const &.
**/ **/
docstring stringifyFromForSearch(FindAdvOptions const & opt, docstring stringifyFromForSearch(
Buffer const & buf, DocIterator const & cur, int len = -1); FindAdvOptions const & opt,
DocIterator const & cur,
int len = -1);
} // namespace lyx } // namespace lyx