@@ -46,16 +46,52 @@ void Finder::setSearchText(const QString &text)
4646 this ->text = text;
4747}
4848
49+ void Finder::setSelectionRange (Sci_CharacterRange range)
50+ {
51+ use_selection_range = true ;
52+ selection_range = range;
53+ }
54+
55+ void Finder::clearSelectionRange ()
56+ {
57+ use_selection_range = false ;
58+ }
59+
4960Sci_CharacterRange Finder::findNext (int startPos)
5061{
5162 did_latest_search_wrap = false ;
5263
5364 if (text.isEmpty ())
5465 return {INVALID_POSITION, INVALID_POSITION};
5566
56- const int pos = startPos == INVALID_POSITION ? editor->selectionEnd () : startPos;
5767 const QByteArray textData = text.toUtf8 ();
5868
69+ if (use_selection_range) {
70+ // Clamp start position to within the selection
71+ const int rangeEnd = selection_range.cpMax ;
72+ int pos = startPos == INVALID_POSITION ? editor->selectionEnd () : startPos;
73+ if (pos < selection_range.cpMin ) pos = selection_range.cpMin ;
74+ if (pos > rangeEnd) pos = rangeEnd;
75+
76+ editor->setTargetRange (pos, rangeEnd);
77+ editor->setSearchFlags (search_flags);
78+
79+ if (editor->searchInTarget (textData.length (), textData.constData ()) != INVALID_POSITION) {
80+ return {static_cast <Sci_PositionCR>(editor->targetStart ()), static_cast <Sci_PositionCR>(editor->targetEnd ())};
81+ }
82+ // Wrap within selection
83+ if (wrap && pos > selection_range.cpMin ) {
84+ editor->setTargetRange (selection_range.cpMin , pos);
85+ if (editor->searchInTarget (textData.length (), textData.constData ()) != INVALID_POSITION) {
86+ did_latest_search_wrap = true ;
87+ return {static_cast <Sci_PositionCR>(editor->targetStart ()), static_cast <Sci_PositionCR>(editor->targetEnd ())};
88+ }
89+ }
90+ return {INVALID_POSITION, INVALID_POSITION};
91+ }
92+
93+ const int pos = startPos == INVALID_POSITION ? editor->selectionEnd () : startPos;
94+
5995 editor->setTargetRange (pos, editor->length ());
6096 editor->setSearchFlags (search_flags);
6197
@@ -81,9 +117,32 @@ Sci_CharacterRange Finder::findPrev()
81117 if (text.isEmpty ())
82118 return {INVALID_POSITION, INVALID_POSITION};
83119
84- const int pos = editor->selectionStart ();
85120 const QByteArray textData = text.toUtf8 ();
86121
122+ if (use_selection_range) {
123+ int pos = editor->selectionStart ();
124+ if (pos > selection_range.cpMax ) pos = selection_range.cpMax ;
125+ if (pos < selection_range.cpMin ) pos = selection_range.cpMin ;
126+
127+ editor->setSearchFlags (search_flags);
128+ auto range = editor->findText (search_flags, textData.constData (), pos, selection_range.cpMin );
129+
130+ if (range.first != INVALID_POSITION) {
131+ return {static_cast <Sci_PositionCR>(range.first ), static_cast <Sci_PositionCR>(range.second )};
132+ }
133+ // Wrap within selection
134+ if (wrap && pos < selection_range.cpMax ) {
135+ range = editor->findText (search_flags, textData.constData (), selection_range.cpMax , pos);
136+ if (range.first != INVALID_POSITION) {
137+ did_latest_search_wrap = true ;
138+ return {static_cast <Sci_PositionCR>(range.first ), static_cast <Sci_PositionCR>(range.second )};
139+ }
140+ }
141+ return {INVALID_POSITION, INVALID_POSITION};
142+ }
143+
144+ const int pos = editor->selectionStart ();
145+
87146 editor->setTargetRange (pos, editor->length ());
88147 editor->setSearchFlags (search_flags);
89148
@@ -104,17 +163,21 @@ Sci_CharacterRange Finder::findPrev()
104163 return {INVALID_POSITION, INVALID_POSITION};
105164}
106165
107- // Count all occurrences in the document
166+ // Count all occurrences in the document (or selection if set)
108167int Finder::count ()
109168{
110169 int total = 0 ;
111170
112171 if (text.length () > 0 ) {
113- forEachMatch ( [&](int start, int end) {
172+ auto counter = [&](int start, int end) {
114173 Q_UNUSED (start);
115174 total++;
116175 return end;
117- });
176+ };
177+ if (use_selection_range)
178+ forEachMatchInRange (counter, selection_range);
179+ else
180+ forEachMatch (counter);
118181 }
119182
120183 return total;
@@ -123,22 +186,33 @@ int Finder::count()
123186Sci_CharacterRange Finder::replaceSelectionIfMatch (const QString &replaceText)
124187{
125188 const QByteArray textData = text.toUtf8 ();
126- bool isRegex = editor->searchFlags () & SCFIND_REGEXP;
189+ const bool isRegex = search_flags & SCFIND_REGEXP;
190+ const Sci_PositionCR selectionStart = editor->selectionStart ();
191+ const Sci_PositionCR selectionEnd = editor->selectionEnd ();
192+
193+ if (use_selection_range && (selectionStart < selection_range.cpMin || selectionEnd > selection_range.cpMax ))
194+ return {INVALID_POSITION, INVALID_POSITION};
127195
128196 // Search just in the selection to see if the current selection is a match
129- editor->setTargetStart (editor-> selectionStart () );
130- editor->setTargetEnd (editor-> selectionEnd () );
197+ editor->setTargetStart (selectionStart);
198+ editor->setTargetEnd (selectionEnd);
131199 editor->setSearchFlags (search_flags);
132200
133201 if (editor->searchInTarget (textData.length (), textData.constData ()) != INVALID_POSITION) {
134202 const QByteArray replaceData = replaceText.toUtf8 ();
203+ const Sci_PositionCR matchStart = editor->targetStart ();
204+ const Sci_PositionCR matchEnd = editor->targetEnd ();
205+ int replaceLength;
135206
136207 if (isRegex)
137- editor->replaceTargetRE (replaceData.length (), replaceData.constData ());
208+ replaceLength = editor->replaceTargetRE (replaceData.length (), replaceData.constData ());
138209 else
139- editor->replaceTarget (replaceData.length (), replaceData.constData ());
210+ replaceLength = editor->replaceTarget (replaceData.length (), replaceData.constData ());
140211
141- return {static_cast <Sci_PositionCR>(editor->targetStart ()), static_cast <Sci_PositionCR>(editor->targetEnd ())};
212+ if (use_selection_range)
213+ selection_range.cpMax += replaceLength - (matchEnd - matchStart);
214+
215+ return {matchStart, static_cast <Sci_PositionCR>(matchStart + replaceLength)};
142216 }
143217
144218 return {INVALID_POSITION, INVALID_POSITION};
@@ -152,7 +226,9 @@ int Finder::replaceAll(const QString &replaceText)
152226 const QByteArray &replaceData = replaceText.toUtf8 ();
153227 const QByteArray &b = text.toUtf8 ();
154228 const char *c = b.constData ();
155- Sci_TextToFind ttf {{0 , (Sci_PositionCR)editor->length ()}, c, {-1 , -1 }};
229+ const Sci_PositionCR rangeStart = use_selection_range ? selection_range.cpMin : 0 ;
230+ Sci_PositionCR rangeEnd = use_selection_range ? selection_range.cpMax : (Sci_PositionCR)editor->length ();
231+ Sci_TextToFind ttf {{rangeStart, rangeEnd}, c, {-1 , -1 }};
156232 const bool isRegex = search_flags & SCFIND_REGEXP;
157233 int total = 0 ;
158234
@@ -173,11 +249,22 @@ int Finder::replaceAll(const QString &replaceText)
173249 else
174250 ttf.chrg .cpMin = start + editor->replaceTarget (replaceData.length (), replaceData.constData ());
175251
176- // The replace could have changed the document size, so update the end of the search range
177- ttf.chrg .cpMax = editor->length ();
252+ // Update the end of the search range based on the length delta of this replacement.
253+ // When confined to a selection, track the selection boundary precisely; otherwise
254+ // expand to the full (possibly grown) document length.
255+ if (use_selection_range) {
256+ rangeEnd += ttf.chrg .cpMin - end; // delta = newLength - oldMatchLength
257+ ttf.chrg .cpMax = rangeEnd;
258+ } else {
259+ ttf.chrg .cpMax = editor->length ();
260+ }
178261
179262 total++;
180263 }
181264
265+ // Keep the stored selection range in sync with the post-replacement boundary
266+ if (use_selection_range)
267+ selection_range.cpMax = rangeEnd;
268+
182269 return total;
183270}
0 commit comments