]> git.lyx.org Git - lyx.git/blob - src/lyxfind.C
Fix crash when running lyx -dbg insets -e ...
[lyx.git] / src / lyxfind.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "lyxtext.h"
8 #include "lyxfind.h"
9 #include "LyXView.h"
10 #include "lyx_gui_misc.h"
11 #include "support/textutils.h"
12 #include "support/lstrings.h"
13 #include "BufferView.h"
14 #include "buffer.h"
15 #include "gettext.h"
16
17 int LyXReplace(BufferView * bv,
18                string const & searchstr,
19                string const & replacestr,
20                bool const & casesens,
21                bool const & matchwrd,
22                bool const & forward,
23                bool const & replaceall)
24 {
25    int replace_count = 0;
26  
27    if (!bv->available() || bv->buffer()->isReadonly()) 
28      return replace_count;
29    
30    // CutSelection cannot cut a single space, so we have to stop
31    // in order to avoid endless loop :-(
32    if (searchstr.length() == 0
33        || (searchstr.length() == 1 && searchstr[0] == ' ')) {
34       WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
35                                 "nor an empty character."));
36       return replace_count;
37    }
38    // now we can start searching for the first 
39    // start at top if replaceall
40    bool fw = forward;
41    if (replaceall) {
42       bv->text->clearSelection(bv);
43       bv->text->cursorTop(bv);
44       // override search direction because we search top to bottom
45       fw = true;
46    }
47
48    // if nothing selected or selection does not equal search string
49    // search and select next occurance and return if no replaceall
50    if (searchstr!=bv->text->selectionAsString(bv->buffer())) {
51       LyXFind(bv, searchstr, casesens, matchwrd, fw);
52       if (!replaceall)
53         return replace_count;
54    }
55    
56    bool found;
57    do {
58       bv->hideCursor();
59       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
60       bv->toggleSelection(false);
61       bv->text->replaceSelectionWithString(bv, replacestr);
62       bv->text->setSelectionOverString(bv, replacestr);
63       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
64       ++replace_count;
65       found = LyXFind(bv, searchstr, casesens, matchwrd, fw);
66    } while (replaceall && found);
67    
68    if (bv->focus())
69      bv->showCursor();
70
71    return replace_count;
72 }
73
74 bool LyXFind(BufferView * bv,
75              string const & searchstr,
76              bool const & casesens,
77              bool const & matchwrd,
78              bool const & forward)
79 {
80    bool found = false;
81    
82    if (!bv->available() || searchstr.empty())
83      return found;
84
85    bv->hideCursor();
86    bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
87    
88    LyXText * ltCur = bv->text;
89    if (ltCur->selection.set())
90      ltCur->cursor = forward ? ltCur->selection.end
91              : ltCur->selection.start;
92
93    if (forward 
94        ? SearchForward(bv, searchstr, casesens, matchwrd)
95        : SearchBackward(bv, searchstr, casesens, matchwrd)) {
96       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
97       bv->toggleSelection();
98       bv->text->clearSelection(bv);
99       bv->text->setSelectionOverString(bv, searchstr);
100       bv->toggleSelection(false);
101       found = true;
102    };
103    
104    if (bv->focus())
105      bv->showCursor();
106    
107    return found;
108 }
109
110
111 // returns true if the specified string is at the specified position
112 bool IsStringInText(Paragraph * par, Paragraph::size_type pos,
113                     string const & str, bool const & cs,
114                     bool const & mw)
115 {
116         if (!par)
117                 return false;
118    
119         string::size_type size = str.length();
120         Paragraph::size_type i = 0;
121         while (((pos + i) < par->size())
122                && (string::size_type(i) < size)
123                && (cs ? (str[i] == par->getChar(pos + i))
124                    : (toupper(str[i]) == toupper(par->getChar(pos + i)))))
125         {
126                 ++i;
127         }
128         if (size == string::size_type(i)) {
129           // if necessary, check whether string matches word
130           if (!mw || 
131               (mw && ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
132                       && (pos + Paragraph::size_type(size) >= par->size()
133                           || !IsLetterCharOrDigit(par->getChar(pos + size))))
134                ))
135             return true;
136         }
137         return false;
138 }
139
140 // forward search:
141 // if the string can be found: return true and set the cursor to
142 // the new position, cs = casesensitive, mw = matchword
143 bool SearchForward(BufferView * bv, string const & str,
144                    bool const & cs, bool const & mw)
145 {
146         Paragraph * par = bv->text->cursor.par();
147         Paragraph::size_type pos = bv->text->cursor.pos();
148    
149         while (par && !IsStringInText(par, pos, str, cs, mw)) {
150                 if (pos < par->size() - 1)
151                         ++pos;
152                 else {
153                         pos = 0;
154                         par = par->next();
155                 }
156         }
157         if (par) {
158                 bv->text->setCursor(bv, par, pos);
159                 return true;
160         }
161         else
162                 return false;
163 }
164
165
166 // backward search:
167 // if the string can be found: return true and set the cursor to
168 // the new position, cs = casesensitive, mw = matchword
169 bool SearchBackward(BufferView * bv, string const & str,
170                     bool const & cs, bool const & mw)
171 {
172         Paragraph * par = bv->text->cursor.par();
173         Paragraph::size_type pos = bv->text->cursor.pos();
174
175         do {
176                 if (pos > 0)
177                         --pos;
178                 else {
179                         // We skip empty paragraphs (Asger)
180                         do {
181                                 par = par->previous();
182                                 if (par)
183                                         pos = par->size() - 1;
184                         } while (par && pos < 0);
185                 }
186         } while (par && !IsStringInText(par, pos, str, cs, mw));
187   
188         if (par) {
189                 bv->text->setCursor(bv, par, pos);
190                 return true;
191         } else
192                 return false;
193 }
194