X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Flyxfind.C;h=cfee2c9f04435a7be031677ef35ef4764c07eef2;hb=005545f28100fd30afa22313d6e3b1b67aa9a857;hp=9f474c5a36456a5b8c0f58c569ce1f4b0618ebf9;hpb=b0cffd9fc0288a639a7271837ae8efb319d704be;p=lyx.git diff --git a/src/lyxfind.C b/src/lyxfind.C index 9f474c5a36..cfee2c9f04 100644 --- a/src/lyxfind.C +++ b/src/lyxfind.C @@ -16,104 +16,122 @@ #include "lyxfind.h" #include "buffer.h" +#include "cursor.h" +#include "CutAndPaste.h" #include "BufferView.h" #include "debug.h" -#include "iterators.h" +#include "funcrequest.h" #include "gettext.h" #include "lyxtext.h" #include "paragraph.h" -#include "PosIterator.h" +#include "pariterator.h" #include "undo.h" #include "frontends/Alert.h" - -#include "insets/insettext.h" +#include "frontends/LyXView.h" #include "support/textutils.h" +#include "support/tostr.h" + +#include "support/std_sstream.h" using lyx::support::lowercase; using lyx::support::uppercase; -using bv_funcs::put_selection_at; +using lyx::support::split; -using std::string; +using lyx::par_type; +using lyx::pos_type; +using std::advance; +using std::ostringstream; +using std::string; -namespace lyx { -namespace find { namespace { -class MatchString +bool parse_bool(string & howto) +{ + if (howto.empty()) + return false; + string var; + howto = split(howto, var, ' '); + return (var == "1"); +} + + +class MatchString : public std::binary_function { public: MatchString(string const & str, bool cs, bool mw) - : str(str), cs(cs), mw(mw) {}; -// returns true if the specified string is at the specified position - bool operator()(Paragraph const & par, pos_type pos) const - { - string::size_type size = str.length(); - pos_type i = 0; - pos_type parsize = par.size(); - while ((pos + i < parsize) - && (string::size_type(i) < size) - && (cs ? (str[i] == par.getChar(pos + i)) - : (uppercase(str[i]) == uppercase(par.getChar(pos + i))))) { - ++i; + : str(str), cs(cs), mw(mw) + {} + + // returns true if the specified string is at the specified position + bool operator()(Paragraph const & par, lyx::pos_type pos) const + { + string::size_type const size = str.length(); + lyx::pos_type i = 0; + lyx::pos_type const parsize = par.size(); + for (i = 0; pos + i < parsize; ++i) { + if (string::size_type(i) >= size) + break; + if (cs && str[i] != par.getChar(pos + i)) + break; + if (!cs && uppercase(str[i]) != uppercase(par.getChar(pos + i))) + break; } - if (size == string::size_type(i)) { - // if necessary, check whether string matches word - if (!mw) - return true; - if ((pos <= 0 || !IsLetterCharOrDigit(par.getChar(pos - 1))) - && (pos + pos_type(size) >= parsize - || !IsLetterCharOrDigit(par.getChar(pos + size)))) { - return true; - } + + if (size != string::size_type(i)) + return false; + + // if necessary, check whether string matches word + if (mw) { + if (pos > 0 && IsLetterCharOrDigit(par.getChar(pos - 1))) + return false; + if (pos + lyx::pos_type(size) < parsize + && IsLetterCharOrDigit(par.getChar(pos + size))); + return false; } - return false; + + return true; } - + private: + // search string string str; + // case sensitive bool cs; + // match whole words only bool mw; }; -bool findForward(PosIterator & cur, PosIterator const & end, - MatchString & match) +bool findForward(DocIterator & cur, MatchString const & match) { - for (; cur != end && !match(*cur.pit(), cur.pos()); ++cur) - ; - - return cur != end; + for (; cur; cur.forwardChar()) + if (cur.inTexted() && match(cur.paragraph(), cur.pos())) + return true; + return false; } -bool findBackwards(PosIterator & cur, PosIterator const & beg, - MatchString & match) +bool findBackwards(DocIterator & cur, MatchString const & match) { - if (beg == cur) - return false; - do { - --cur; - if (match(*cur.pit(), cur.pos())) - break; - } while (cur != beg); - - return match(*cur.pit(), cur.pos()); + for (; cur; cur.backwardChar()) + if (cur.inTexted() && match(cur.paragraph(), cur.pos())) + return true; + return false; } -bool findChange(PosIterator & cur, PosIterator const & end) +bool findChange(DocIterator & cur) { - for (; cur != end; ++cur) { - if ((!cur.pit()->size() || !cur.at_end()) - && cur.pit()->lookupChange(cur.pos()) != Change::UNCHANGED) - break; - } - - return cur != end; + for (; cur; cur.forwardChar()) + if (cur.inTexted() && !cur.paragraph().empty() && + cur.paragraph().lookupChange(cur.pos()) + != Change::UNCHANGED) + return true; + return false; } @@ -126,32 +144,20 @@ bool searchAllowed(BufferView * bv, string const & str) return bv->available(); } -} // namespace anon - - -bool find(BufferView * bv, string const & searchstr, - bool cs, bool mw, bool fw) +bool find(BufferView * bv, string const & searchstr, bool cs, bool mw, bool fw) { if (!searchAllowed(bv, searchstr)) return false; - PosIterator cur = PosIterator(*bv); + DocIterator cur = bv->cursor(); - MatchString match(searchstr, cs, mw); - - bool found; + MatchString const match(searchstr, cs, mw); + + bool found = fw ? findForward(cur, match) : findBackwards(cur, match); - if (fw) { - PosIterator const end = bv->buffer()->pos_iterator_end(); - found = findForward(cur, end, match); - } else { - PosIterator const beg = bv->buffer()->pos_iterator_begin(); - found = findBackwards(cur, beg, match); - } - if (found) - put_selection_at(bv, cur, searchstr.length(), !fw); + bv->putSelectionAt(cur, searchstr.length(), !fw); return found; } @@ -165,99 +171,187 @@ int replaceAll(BufferView * bv, if (!searchAllowed(bv, searchstr) || buf.isReadonly()) return 0; - - recordUndo(Undo::ATOMIC, bv->text, 0, - buf.paragraphs().size() - 1); - - PosIterator cur = buf.pos_iterator_begin(); - PosIterator const end = buf.pos_iterator_end(); - MatchString match(searchstr, cs, mw); + + recordUndoFullDocument(bv->cursor()); + + MatchString const match(searchstr, cs, mw); int num = 0; int const rsize = replacestr.size(); int const ssize = searchstr.size(); - while (findForward(cur, end, match)) { - pos_type pos = cur.pos(); + + DocIterator cur = doc_iterator_begin(buf.inset()); + while (findForward(cur, match)) { + lyx::pos_type pos = cur.pos(); LyXFont const font - = cur.pit()->getFontSettings(buf.params(), pos); - int striked = ssize - cur.pit()->erase(pos, pos + ssize); - cur.pit()->insert(pos, replacestr, font); - advance(cur, rsize + striked); + = cur.paragraph().getFontSettings(buf.params(), pos); + int striked = ssize - cur.paragraph().erase(pos, pos + ssize); + cur.paragraph().insert(pos, replacestr, font); + for (int i = 0; i < rsize + striked; ++i) + cur.forwardChar(); ++num; } - PosIterator beg = buf.pos_iterator_begin(); - bv->text->init(bv); - put_selection_at(bv, beg, 0, false); + + bv->text()->init(bv); + bv->putSelectionAt(doc_iterator_begin(buf.inset()), 0, false); if (num) buf.markDirty(); return num; } -int replace(BufferView * bv, - string const & searchstr, string const & replacestr, - bool cs, bool mw, bool fw) +bool stringSelected(BufferView * bv, string const & searchstr, + bool cs, bool mw, bool fw) +{ + // if nothing selected or selection does not equal search + // string search and select next occurance and return + string const & str1 = searchstr; + string const str2 = bv->cursor().selectionAsString(false); + if ((cs && str1 != str2) || lowercase(str1) != lowercase(str2)) { + find(bv, searchstr, cs, mw, fw); + return false; + } + + return true; +} + + +int replace(BufferView * bv, string const & searchstr, + string const & replacestr, bool cs, bool mw, bool fw) { if (!searchAllowed(bv, searchstr) || bv->buffer()->isReadonly()) return 0; - - { - LyXText * text = bv->getLyXText(); - // if nothing selected or selection does not equal search - // string search and select next occurance and return - string const str1 = searchstr; - string const str2 = text->selectionAsString(*bv->buffer(), - false); - if ((cs && str1 != str2) - || lowercase(str1) != lowercase(str2)) { - find(bv, searchstr, cs, mw, fw); - return 0; - } - } -#ifdef LOCK - LyXText * text = bv->getLyXText(); - // We have to do this check only because mathed insets don't - // return their own LyXText but the LyXText of it's parent! - if (!bv->innerInset() || - ((text != bv->text) && - (text->inset_owner == text->inset_owner->getLockingInset()))) { - text->replaceSelectionWithString(replacestr); - text->setSelectionRange(replacestr.length()); - text->cursor = fw ? text->selection.end - : text->selection.start; - } -#endif + if (!stringSelected(bv, searchstr, cs, mw, fw)) + return 0; + LCursor & cur = bv->cursor(); + lyx::cap::replaceSelectionWithString(cur, replacestr); + lyx::cap::setSelectionRange(cur, replacestr.length()); + cur.top() = fw ? cur.selEnd() : cur.selBegin(); bv->buffer()->markDirty(); find(bv, searchstr, cs, mw, fw); bv->update(); - + return 1; } +} // namespace anon + + +namespace lyx { +namespace find { + +string const find2string(string const & search, + bool casesensitive, bool matchword, bool forward) +{ + ostringstream ss; + ss << search << '\n' + << int(casesensitive) << ' ' + << int(matchword) << ' ' + << int(forward); + return ss.str(); +} + + +string const replace2string(string const & search, string const & replace, + bool casesensitive, bool matchword, + bool all, bool forward) +{ + ostringstream ss; + ss << search << '\n' + << replace << '\n' + << int(casesensitive) << ' ' + << int(matchword) << ' ' + << int(all) << ' ' + << int(forward); + return ss.str(); +} + + +void find(BufferView * bv, FuncRequest const & ev) +{ + if (!bv || ev.action != LFUN_WORD_FIND) + return; + + lyxerr << "find called, cmd: " << ev << std::endl; + + // data is of the form + // " + // " + string search; + string howto = split(ev.argument, search, '\n'); + + bool casesensitive = parse_bool(howto); + bool matchword = parse_bool(howto); + bool forward = parse_bool(howto); + + bool const found = ::find(bv, search, + casesensitive, matchword, forward); + + if (!found) + bv->owner()->message(_("String not found!")); +} + + +void replace(BufferView * bv, FuncRequest const & ev) +{ + if (!bv || ev.action != LFUN_WORD_REPLACE) + return; + + // data is of the form + // " + // + // " + string search; + string replace; + string howto = split(ev.argument, search, '\n'); + howto = split(howto, replace, '\n'); + + bool casesensitive = parse_bool(howto); + bool matchword = parse_bool(howto); + bool all = parse_bool(howto); + bool forward = parse_bool(howto); + + LyXView * lv = bv->owner(); + + int const replace_count = all + ? ::replaceAll(bv, search, replace, casesensitive, matchword) + : ::replace(bv, search, replace, casesensitive, matchword, forward); + + if (replace_count == 0) { + lv->message(_("String not found!")); + } else { + if (replace_count == 1) { + lv->message(_("String has been replaced.")); + } else { + string str = tostr(replace_count); + str += _(" strings have been replaced."); + lv->message(str); + } + } +} + bool findNextChange(BufferView * bv) { if (!bv->available()) return false; - PosIterator cur = PosIterator(*bv); - PosIterator const endit = bv->buffer()->pos_iterator_end(); + DocIterator cur = DocIterator(bv->cursor()); - if (!findChange(cur, endit)) + if (!findChange(cur)) return false; - - - ParagraphList::iterator pit = cur.pit(); + + Paragraph const & par = cur.paragraph(); pos_type pos = cur.pos(); - - Change orig_change = pit->lookupChangeFull(pos); - pos_type parsize = pit->size(); + + Change orig_change = par.lookupChangeFull(pos); + pos_type parsize = par.size(); pos_type end = pos; for (; end != parsize; ++end) { - Change change = pit->lookupChangeFull(end); + Change change = par.lookupChangeFull(end); if (change != orig_change) { // slight UI optimisation: for replacements, we get // text like : _old_new. Consider that as one change. @@ -267,8 +361,7 @@ bool findNextChange(BufferView * bv) } } pos_type length = end - pos; - bv->text->init(bv); - put_selection_at(bv, cur, length, true); + bv->putSelectionAt(cur, length, true); return true; }