00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "katesearch.h"
00025 #include "katesearch.moc"
00026
00027 #include "kateview.h"
00028 #include "katedocument.h"
00029 #include "katesupercursor.h"
00030 #include "katearbitraryhighlight.h"
00031 #include "kateconfig.h"
00032 #include "katehighlight.h"
00033
00034 #include <tdelocale.h>
00035 #include <kstdaction.h>
00036 #include <tdemessagebox.h>
00037 #include <kstringhandler.h>
00038 #include <kdebug.h>
00039 #include <kfinddialog.h>
00040 #include <kreplacedialog.h>
00041 #include <kpushbutton.h>
00042
00043 #include <tqlayout.h>
00044 #include <tqlabel.h>
00045
00046
00047 TQStringList KateSearch::s_searchList = TQStringList();
00048 TQStringList KateSearch::s_replaceList = TQStringList();
00049 TQString KateSearch::s_pattern = TQString();
00050 static const bool arbitraryHLExample = false;
00051
00052 KateSearch::KateSearch( KateView* view )
00053 : TQObject( view, "kate search" )
00054 , m_view( view )
00055 , m_doc( view->doc() )
00056 , replacePrompt( new KateReplacePrompt( view ) )
00057 {
00058 m_arbitraryHLList = new KateSuperRangeList();
00059 if (arbitraryHLExample) m_doc->arbitraryHL()->addHighlightToView(m_arbitraryHLList, m_view);
00060
00061 connect(replacePrompt,TQT_SIGNAL(clicked()),this,TQT_SLOT(replaceSlot()));
00062 }
00063
00064 KateSearch::~KateSearch()
00065 {
00066 delete m_arbitraryHLList;
00067 }
00068
00069 void KateSearch::createActions( TDEActionCollection* ac )
00070 {
00071 KStdAction::find( this, TQT_SLOT(find()), ac )->setWhatsThis(
00072 i18n("Look up the first occurrence of a piece of text or regular expression."));
00073 KStdAction::findNext( this, TQT_SLOT(slotFindNext()), ac )->setWhatsThis(
00074 i18n("Look up the next occurrence of the search phrase."));
00075 KStdAction::findPrev( this, TQT_SLOT(slotFindPrev()), ac, "edit_find_prev" )->setWhatsThis(
00076 i18n("Look up the previous occurrence of the search phrase."));
00077 KStdAction::replace( this, TQT_SLOT(replace()), ac )->setWhatsThis(
00078 i18n("Look up a piece of text or regular expression and replace the result with some given text."));
00079 }
00080
00081 void KateSearch::addToList( TQStringList& list, const TQString& s )
00082 {
00083 if( list.count() > 0 ) {
00084 TQStringList::Iterator it = list.find( s );
00085 if( *it != 0L )
00086 list.remove( it );
00087 if( list.count() >= 16 )
00088 list.remove( list.fromLast() );
00089 }
00090 list.prepend( s );
00091 }
00092
00093 void KateSearch::find()
00094 {
00095
00096 long searchf = KateViewConfig::global()->searchFlags();
00097 if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
00098 searchf |= KFindDialog::SelectedText;
00099
00100 KFindDialog *findDialog = new KFindDialog ( m_view, "", searchf,
00101 s_searchList, m_view->hasSelection() );
00102
00103 findDialog->setPattern (getSearchText());
00104
00105
00106 if( findDialog->exec() == TQDialog::Accepted ) {
00107 s_searchList = findDialog->findHistory () ;
00108
00109 find( TQString(s_searchList.first()), findDialog->options(), true, true );
00110 }
00111
00112 delete findDialog;
00113 m_view->repaintText ();
00114 }
00115
00116 void KateSearch::find( const TQString &pattern, long flags, bool add, bool shownotfound )
00117 {
00118 KateViewConfig::global()->setSearchFlags( flags );
00119 if( add )
00120 addToList( s_searchList, pattern );
00121
00122 s_pattern = pattern;
00123
00124 SearchFlags searchFlags;
00125
00126 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
00127 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
00128 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
00129 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
00130 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
00131 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
00132 searchFlags.prompt = false;
00133 searchFlags.replace = false;
00134 searchFlags.finished = false;
00135 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
00136 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
00137
00138 if ( searchFlags.selected )
00139 {
00140 s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
00141 s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
00142 s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
00143 } else {
00144 s.cursor = getCursor( searchFlags );
00145 }
00146
00147 s.wrappedEnd = s.cursor;
00148 s.wrapped = false;
00149 s.showNotFound = shownotfound;
00150
00151 search( searchFlags );
00152 }
00153
00154 void KateSearch::replace()
00155 {
00156 if (!doc()->isReadWrite()) return;
00157
00158
00159 long searchf = KateViewConfig::global()->searchFlags();
00160 if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
00161 searchf |= KFindDialog::SelectedText;
00162
00163 KReplaceDialog *replaceDialog = new KReplaceDialog ( m_view, "", searchf,
00164 s_searchList, s_replaceList, m_view->hasSelection() );
00165
00166 replaceDialog->setPattern (getSearchText());
00167
00168 if( replaceDialog->exec() == TQDialog::Accepted ) {
00169 long opts = replaceDialog->options();
00170 m_replacement = replaceDialog->replacement();
00171 s_searchList = replaceDialog->findHistory () ;
00172 s_replaceList = replaceDialog->replacementHistory () ;
00173
00174
00175 replace( TQString(s_searchList.first()), m_replacement, opts );
00176 }
00177
00178 delete replaceDialog;
00179 m_view->update ();
00180 }
00181
00182 void KateSearch::replace( const TQString& pattern, const TQString &replacement, long flags )
00183 {
00184 if (!doc()->isReadWrite()) return;
00185
00186 addToList( s_searchList, pattern );
00187 s_pattern = pattern;
00188 addToList( s_replaceList, replacement );
00189 m_replacement = replacement;
00190 KateViewConfig::global()->setSearchFlags( flags );
00191
00192 SearchFlags searchFlags;
00193 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
00194 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
00195 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
00196 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
00197 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
00198 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
00199 searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
00200 searchFlags.replace = true;
00201 searchFlags.finished = false;
00202 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
00203 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
00204 if ( searchFlags.selected )
00205 {
00206 s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
00207 s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
00208 s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
00209 } else {
00210 s.cursor = getCursor( searchFlags );
00211 }
00212
00213 s.wrappedEnd = s.cursor;
00214 s.wrapped = false;
00215
00216 search( searchFlags );
00217 }
00218
00219 void KateSearch::findAgain( bool reverseDirection )
00220 {
00221 SearchFlags searchFlags;
00222 searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
00223 searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
00224 searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
00225 && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
00226 searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
00227 searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
00228 searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
00229 searchFlags.replace = false;
00230 searchFlags.finished = false;
00231 searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
00232 searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
00233
00234 if (reverseDirection)
00235 searchFlags.backward = !searchFlags.backward;
00236
00237 searchFlags.fromBeginning = false;
00238 searchFlags.prompt = true;
00239
00240 s.cursor = getCursor( searchFlags );
00241 search( searchFlags );
00242 }
00243
00244 void KateSearch::search( SearchFlags flags )
00245 {
00246 s.flags = flags;
00247
00248 if( s.flags.fromBeginning ) {
00249 if( !s.flags.backward ) {
00250 s.cursor.setPos(0, 0);
00251 } else {
00252 s.cursor.setLine(doc()->numLines() - 1);
00253 s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
00254 }
00255 }
00256
00257 if((!s.flags.backward &&
00258 s.cursor.col() == 0 &&
00259 s.cursor.line() == 0 ) ||
00260 ( s.flags.backward &&
00261 s.cursor.col() == doc()->lineLength( s.cursor.line() ) &&
00262 s.cursor.line() == (((int)doc()->numLines()) - 1) ) ) {
00263 s.flags.finished = true;
00264 }
00265
00266 if( s.flags.replace ) {
00267 replaces = 0;
00268 if( s.flags.prompt )
00269 promptReplace();
00270 else
00271 replaceAll();
00272 } else {
00273 findAgain();
00274 }
00275 }
00276
00277 void KateSearch::wrapSearch()
00278 {
00279 if( s.flags.selected )
00280 {
00281 KateTextCursor start (s.selBegin);
00282 KateTextCursor end (s.selEnd);
00283
00284
00285 if (m_view->blockSelectionMode())
00286 {
00287 start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
00288 end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
00289 }
00290
00291 s.cursor = s.flags.backward ? end : start;
00292 }
00293 else
00294 {
00295 if( !s.flags.backward ) {
00296 s.cursor.setPos(0, 0);
00297 } else {
00298 s.cursor.setLine(doc()->numLines() - 1);
00299 s.cursor.setCol(doc()->lineLength( s.cursor.line() ) );
00300 }
00301 }
00302
00303
00304
00305 s.wrapped = s.flags.replace;
00306
00307 replaces = 0;
00308 s.flags.finished = true;
00309 }
00310
00311 void KateSearch::findAgain()
00312 {
00313 if( s_pattern.isEmpty() ) {
00314 find();
00315 return;
00316 }
00317
00318 if ( doSearch( s_pattern ) ) {
00319 exposeFound( s.cursor, s.matchedLength );
00320 } else if( !s.flags.finished ) {
00321 if( askContinue() ) {
00322 wrapSearch();
00323 findAgain();
00324 } else {
00325 if (arbitraryHLExample) m_arbitraryHLList->clear();
00326 }
00327 } else {
00328 if (arbitraryHLExample) m_arbitraryHLList->clear();
00329 if ( s.showNotFound )
00330 KMessageBox::sorry( view(),
00331 i18n("Search string '%1' not found!")
00332 .arg( KStringHandler::csqueeze( s_pattern ) ),
00333 i18n("Find"));
00334 }
00335 }
00336
00337 void KateSearch::replaceAll()
00338 {
00339 doc()->editStart ();
00340
00341 while( doSearch( s_pattern ) )
00342 replaceOne();
00343
00344 doc()->editEnd ();
00345
00346 if( !s.flags.finished ) {
00347 if( askContinue() ) {
00348 wrapSearch();
00349 replaceAll();
00350 }
00351 } else {
00352 KMessageBox::information( view(),
00353 i18n("%n replacement made.","%n replacements made.",replaces),
00354 i18n("Replace") );
00355 }
00356 }
00357
00358 void KateSearch::promptReplace()
00359 {
00360 if ( doSearch( s_pattern ) ) {
00361 exposeFound( s.cursor, s.matchedLength );
00362 replacePrompt->show();
00363 replacePrompt->setFocus ();
00364 } else if( !s.flags.finished && askContinue() ) {
00365 wrapSearch();
00366 promptReplace();
00367 } else {
00368 if (arbitraryHLExample) m_arbitraryHLList->clear();
00369 replacePrompt->hide();
00370 KMessageBox::information( view(),
00371 i18n("%n replacement made.","%n replacements made.",replaces),
00372 i18n("Replace") );
00373 }
00374 }
00375
00376 void KateSearch::replaceOne()
00377 {
00378 TQString replaceWith = m_replacement;
00379 if ( s.flags.regExp && s.flags.useBackRefs ) {
00380
00381
00382
00383
00384 TQRegExp br("\\\\(.)");
00385 int pos = br.search( replaceWith );
00386 int ncaps = m_re.numCaptures();
00387 while ( pos >= 0 ) {
00388 TQString substitute;
00389 TQChar argument = TQString(br.cap(1)).at(0);
00390 if ( argument.isDigit() ) {
00391
00392 int ccap = argument.digitValue();
00393 if (ccap <= ncaps ) {
00394 substitute = m_re.cap( ccap );
00395 } else {
00396 kdDebug()<<"KateSearch::replaceOne(): you don't have "<<ccap<<" backreferences in regexp '"<<TQString(m_re.pattern())<<"'"<<endl;
00397 break;
00398 }
00399 } else if ( argument == 'n' ) {
00400 substitute = '\n';
00401 } else if ( argument == 't' ) {
00402 substitute = '\t';
00403 } else {
00404
00405 substitute = argument;
00406 }
00407 replaceWith.replace( pos, br.matchedLength(), substitute );
00408 pos = br.search( replaceWith, pos + substitute.length() );
00409 }
00410 }
00411
00412 doc()->editStart();
00413 doc()->removeText( s.cursor.line(), s.cursor.col(),
00414 s.cursor.line(), s.cursor.col() + s.matchedLength );
00415 doc()->insertText( s.cursor.line(), s.cursor.col(), replaceWith );
00416 doc()->editEnd(),
00417
00418 replaces++;
00419
00420
00421 uint newlines = replaceWith.contains('\n');
00422 if ( newlines )
00423 {
00424 if ( ! s.flags.backward )
00425 {
00426 s.cursor.setLine( s.cursor.line() + newlines );
00427 s.cursor.setCol( replaceWith.length() - replaceWith.findRev('\n') );
00428 }
00429
00430 if ( s.flags.selected )
00431 s.selEnd.setLine( s.selEnd.line() + newlines );
00432 }
00433
00434
00435
00436 if( s.flags.selected && s.cursor.line() == s.selEnd.line() )
00437 {
00438 s.selEnd.setCol(s.selEnd.col() + replaceWith.length() - s.matchedLength );
00439 }
00440
00441
00442 if( s.cursor.line() == s.wrappedEnd.line() && s.cursor.col() <= s.wrappedEnd.col())
00443 {
00444 s.wrappedEnd.setCol(s.wrappedEnd.col() + replaceWith.length() - s.matchedLength );
00445 }
00446
00447 if( !s.flags.backward ) {
00448 s.cursor.setCol(s.cursor.col() + replaceWith.length());
00449 } else if( s.cursor.col() > 0 ) {
00450 s.cursor.setCol(s.cursor.col() - 1);
00451 } else {
00452 s.cursor.setLine(s.cursor.line() - 1);
00453 if( s.cursor.line() >= 0 ) {
00454 s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
00455 }
00456 }
00457 }
00458
00459 void KateSearch::skipOne()
00460 {
00461 if( !s.flags.backward ) {
00462 s.cursor.setCol(s.cursor.col() + s.matchedLength);
00463 } else if( s.cursor.col() > 0 ) {
00464 s.cursor.setCol(s.cursor.col() - 1);
00465 } else {
00466 s.cursor.setLine(s.cursor.line() - 1);
00467 if( s.cursor.line() >= 0 ) {
00468 s.cursor.setCol(doc()->lineLength(s.cursor.line()));
00469 }
00470 }
00471 }
00472
00473 void KateSearch::replaceSlot() {
00474 switch( (Dialog_results)replacePrompt->result() ) {
00475 case srCancel: replacePrompt->hide(); break;
00476 case srAll: replacePrompt->hide(); replaceAll(); break;
00477 case srYes: replaceOne(); promptReplace(); break;
00478 case srLast: replacePrompt->hide(), replaceOne(); break;
00479 case srNo: skipOne(); promptReplace(); break;
00480 }
00481 }
00482
00483 bool KateSearch::askContinue()
00484 {
00485 TQString made =
00486 i18n( "%n replacement made.",
00487 "%n replacements made.",
00488 replaces );
00489
00490 TQString reached = !s.flags.backward ?
00491 i18n( "End of document reached." ) :
00492 i18n( "Beginning of document reached." );
00493
00494 if (KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText)
00495 {
00496 reached = !s.flags.backward ?
00497 i18n( "End of selection reached." ) :
00498 i18n( "Beginning of selection reached." );
00499 }
00500
00501 TQString question = !s.flags.backward ?
00502 i18n( "Continue from the beginning?" ) :
00503 i18n( "Continue from the end?" );
00504
00505 TQString text = s.flags.replace ?
00506 made + "\n" + reached + "\n" + question :
00507 reached + "\n" + question;
00508
00509 return KMessageBox::Yes == KMessageBox::questionYesNo(
00510 view(), text, s.flags.replace ? i18n("Replace") : i18n("Find"),
00511 KStdGuiItem::cont(), i18n("&Stop") );
00512 }
00513
00514 TQString KateSearch::getSearchText()
00515 {
00516
00517
00518
00519
00520 TQString str;
00521
00522 int getFrom = view()->config()->textToSearchMode();
00523 switch (getFrom)
00524 {
00525 case KateViewConfig::SelectionOnly:
00526
00527 if( m_view->hasSelection() )
00528 str = m_view->selection();
00529 break;
00530
00531 case KateViewConfig::SelectionWord:
00532
00533 if( m_view->hasSelection() )
00534 str = m_view->selection();
00535 else
00536 str = view()->currentWord();
00537 break;
00538
00539 case KateViewConfig::WordOnly:
00540
00541 str = view()->currentWord();
00542 break;
00543
00544 case KateViewConfig::WordSelection:
00545
00546 str = view()->currentWord();
00547 if (str.isEmpty() && m_view->hasSelection() )
00548 str = m_view->selection();
00549 break;
00550
00551 default:
00552
00553 break;
00554 }
00555
00556 str.replace( TQRegExp("^\\n"), "" );
00557 str.replace( TQRegExp("\\n.*"), "" );
00558
00559 return str;
00560 }
00561
00562 KateTextCursor KateSearch::getCursor( SearchFlags flags )
00563 {
00564 if (flags.backward && !flags.selected && view()->hasSelection())
00565 {
00566
00567
00568 return kMin( KateTextCursor(view()->selStartLine(), view()->selStartCol()),
00569 KateTextCursor(view()->cursorLine(), view()->cursorColumnReal()));
00570 }
00571 return KateTextCursor(view()->cursorLine(), view()->cursorColumnReal());
00572 }
00573
00574 bool KateSearch::doSearch( const TQString& text )
00575 {
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592 #if 0
00593 static int oldLine = -1;
00594 static int oldCol = -1;
00595 #endif
00596
00597 uint line = s.cursor.line();
00598 uint col = s.cursor.col();
00599 bool backward = s.flags.backward;
00600 bool caseSensitive = s.flags.caseSensitive;
00601 bool regExp = s.flags.regExp;
00602 bool wholeWords = s.flags.wholeWords;
00603 uint foundLine, foundCol, matchLen;
00604 bool found = false;
00605
00606
00607
00608 if (backward)
00609 {
00610 KateDocCursor docCursor(line, col, doc());
00611
00612
00613 if (docCursor.line() == 0 && docCursor.col() == 0)
00614 return false;
00615
00616
00617
00618 docCursor.moveBackward(1);
00619 line = docCursor.line();
00620 col = docCursor.col();
00621 }
00622
00623 do {
00624 if( regExp ) {
00625 m_re = TQRegExp( text, caseSensitive );
00626 found = doc()->searchText( line, col, m_re,
00627 &foundLine, &foundCol,
00628 &matchLen, backward );
00629 }
00630 else if ( wholeWords )
00631 {
00632 bool maybefound = false;
00633 do
00634 {
00635 maybefound = doc()->searchText( line, col, text,
00636 &foundLine, &foundCol,
00637 &matchLen, caseSensitive, backward );
00638 if ( maybefound )
00639 {
00640 found = (
00641 ( foundCol == 0 ||
00642 ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol - 1 ) ) ) &&
00643 ( foundCol + matchLen == doc()->lineLength( foundLine ) ||
00644 ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol + matchLen ) ) )
00645 );
00646 if ( found )
00647 {
00648 break;
00649 }
00650 else if ( backward && foundCol == 0 )
00651 {
00652 if ( line == 0 )
00653 break;
00654 else
00655 line--;
00656 }
00657 else
00658 {
00659 line = foundLine;
00660 col = foundCol + 1;
00661 }
00662 }
00663 } while ( maybefound );
00664 }
00665 else {
00666 found = doc()->searchText( line, col, text,
00667 &foundLine, &foundCol,
00668 &matchLen, caseSensitive, backward );
00669 }
00670
00671 if ( found && s.flags.selected )
00672 {
00673 KateTextCursor start (s.selBegin);
00674 KateTextCursor end (s.selEnd);
00675
00676
00677 if (m_view->blockSelectionMode())
00678 {
00679 start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
00680 end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
00681 }
00682
00683 if ( !s.flags.backward && KateTextCursor( foundLine, foundCol ) >= end
00684 || s.flags.backward && KateTextCursor( foundLine, foundCol ) < start )
00685 {
00686 found = false;
00687 }
00688 else if (m_view->blockSelectionMode())
00689 {
00690 if ((int)foundCol >= start.col() && (int)foundCol < end.col())
00691 break;
00692 }
00693 }
00694
00695 line = foundLine;
00696 col = foundCol+1;
00697 }
00698 while (s.flags.selected && m_view->blockSelectionMode() && found);
00699
00700
00701 if( !found ) return false;
00702
00703
00704 s.cursor.setPos(foundLine, foundCol);
00705 s.matchedLength = matchLen;
00706
00707
00708 if (s.wrapped)
00709 {
00710 if (s.flags.backward)
00711 {
00712 if ( (s.cursor.line() < s.wrappedEnd.line())
00713 || ( (s.cursor.line() == s.wrappedEnd.line()) && ((s.cursor.col()+matchLen) <= uint(s.wrappedEnd.col())) ) )
00714 return false;
00715 }
00716 else
00717 {
00718 if ( (s.cursor.line() > s.wrappedEnd.line())
00719 || ( (s.cursor.line() == s.wrappedEnd.line()) && (s.cursor.col() > s.wrappedEnd.col()) ) )
00720 return false;
00721 }
00722 }
00723
00724
00725
00726
00727
00728
00729 if (arbitraryHLExample) {
00730 KateArbitraryHighlightRange* hl = new KateArbitraryHighlightRange(new KateSuperCursor(m_doc, true, s.cursor), new KateSuperCursor(m_doc, true, s.cursor.line(), s.cursor.col() + s.matchedLength), this);
00731 hl->setBold();
00732 hl->setTextColor(Qt::white);
00733 hl->setBGColor(Qt::black);
00734
00735 connect(hl, TQT_SIGNAL(contentsChanged()), hl, TQT_SIGNAL(eliminated()));
00736 m_arbitraryHLList->append(hl);
00737 }
00738
00739 return true;
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752 }
00753
00754 void KateSearch::exposeFound( KateTextCursor &cursor, int slen )
00755 {
00756 view()->setCursorPositionInternal ( cursor.line(), cursor.col() + slen, 1 );
00757 view()->setSelection( cursor.line(), cursor.col(), cursor.line(), cursor.col() + slen );
00758 view()->syncSelectionCache();
00759 }
00760
00761
00762
00763
00764 KateReplacePrompt::KateReplacePrompt ( TQWidget *parent )
00765 : KDialogBase ( parent, 0L, false, i18n( "Replace Confirmation" ),
00766 User3 | User2 | User1 | Close | Ok , Ok, true,
00767 i18n("Replace &All"), i18n("Re&place && Close"), i18n("&Replace") )
00768 {
00769 setButtonOK( i18n("&Find Next") );
00770 TQWidget *page = new TQWidget(this);
00771 setMainWidget(page);
00772
00773 TQBoxLayout *topLayout = new TQVBoxLayout( page, 0, spacingHint() );
00774 TQLabel *label = new TQLabel(i18n("Found an occurrence of your search term. What do you want to do?"),page);
00775 topLayout->addWidget(label );
00776 }
00777
00778 void KateReplacePrompt::slotOk ()
00779 {
00780 done(KateSearch::srNo);
00781 actionButton(Ok)->setFocus();
00782 }
00783
00784 void KateReplacePrompt::slotClose ()
00785 {
00786 done(KateSearch::srCancel);
00787 actionButton(Close)->setFocus();
00788 }
00789
00790 void KateReplacePrompt::slotUser1 ()
00791 {
00792 done(KateSearch::srAll);
00793 actionButton(User1)->setFocus();
00794 }
00795
00796 void KateReplacePrompt::slotUser2 ()
00797 {
00798 done(KateSearch::srLast);
00799 actionButton(User2)->setFocus();
00800 }
00801
00802 void KateReplacePrompt::slotUser3 ()
00803 {
00804 done(KateSearch::srYes);
00805 actionButton(User3)->setFocus();
00806 }
00807
00808 void KateReplacePrompt::done (int result)
00809 {
00810 setResult(result);
00811
00812 emit clicked();
00813 }
00814
00815
00816
00817 bool SearchCommand::exec(class Kate::View *view, const TQString &cmd, TQString &msg)
00818 {
00819 TQString flags, pattern, replacement;
00820 if ( cmd.startsWith( "find" ) )
00821 {
00822
00823 static TQRegExp re_find("find(?::([bcersw]*))?\\s+(.+)");
00824 if ( re_find.search( cmd ) < 0 )
00825 {
00826 msg = i18n("Usage: find[:[bcersw]] PATTERN");
00827 return false;
00828 }
00829 flags = re_find.cap( 1 );
00830 pattern = re_find.cap( 2 );
00831 }
00832
00833 else if ( cmd.startsWith( "ifind" ) )
00834 {
00835 static TQRegExp re_ifind("ifind(?::([bcrs]*))?\\s+(.*)");
00836 if ( re_ifind.search( cmd ) < 0 )
00837 {
00838 msg = i18n("Usage: ifind[:[bcrs]] PATTERN");
00839 return false;
00840 }
00841 ifindClear();
00842 return true;
00843 }
00844
00845 else if ( cmd.startsWith( "replace" ) )
00846 {
00847
00848 static TQRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00849
00850 TQRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
00851
00852 TQRegExp re_rep2("replace(?::([bceprsw]*))?\\s+(\\S+)(.*)");
00853 #define unbackslash(s) p=0;\
00854 while ( (p = pattern.find( '\\' + delim, p )) > -1 )\
00855 {\
00856 if ( !p || pattern[p-1] != '\\' )\
00857 pattern.remove( p, 1 );\
00858 p++;\
00859 }
00860
00861 if ( re_rep.search( cmd ) >= 0 )
00862 {
00863 flags = re_rep.cap(1);
00864 pattern = re_rep.cap( 3 );
00865 replacement = re_rep.cap( 4 );
00866
00867 int p(0);
00868
00869
00870 TQString delim = re_rep.cap( 2 );
00871 unbackslash(pattern);
00872
00873 unbackslash(replacement);
00874 }
00875 else if ( re_rep1.search( cmd ) >= 0 )
00876 {
00877 flags = re_rep1.cap(1);
00878 pattern = re_rep1.cap( 3 );
00879
00880 int p(0);
00881 TQString delim = re_rep1.cap( 2 );
00882 unbackslash(pattern);
00883 }
00884 else if ( re_rep2.search( cmd ) >= 0 )
00885 {
00886 flags = re_rep2.cap( 1 );
00887 pattern = re_rep2.cap( 2 );
00888 replacement = TQString(re_rep2.cap( 3 )).stripWhiteSpace();
00889 }
00890 else
00891 {
00892 msg = i18n("Usage: replace[:[bceprsw]] PATTERN [REPLACEMENT]");
00893 return false;
00894 }
00895 kdDebug()<<"replace '"<<pattern<<"' with '"<<replacement<<"'"<<endl;
00896 #undef unbackslash
00897 }
00898
00899 long f = 0;
00900 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
00901 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
00902 if ( flags.contains( 'e' ) ) f |= KFindDialog::SelectedText;
00903 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
00904 if ( flags.contains( 'p' ) ) f |= KReplaceDialog::PromptOnReplace;
00905 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
00906 if ( flags.contains( 'w' ) ) f |= KFindDialog::WholeWordsOnly;
00907
00908 if ( cmd.startsWith( "find" ) )
00909 {
00910 ((KateView*)view)->find( pattern, f );
00911 return true;
00912 }
00913 else if ( cmd.startsWith( "replace" ) )
00914 {
00915 f |= KReplaceDialog::BackReference;
00916 ((KateView*)view)->replace( pattern, replacement, f );
00917 return true;
00918 }
00919
00920 return false;
00921 }
00922
00923 bool SearchCommand::help(class Kate::View *, const TQString &cmd, TQString &msg)
00924 {
00925 if ( cmd == "find" )
00926 msg = i18n("<p>Usage: <code>find[:bcersw] PATTERN</code></p>");
00927
00928 else if ( cmd == "ifind" )
00929 msg = i18n("<p>Usage: <code>ifind:[:bcrs] PATTERN</code>"
00930 "<br>ifind does incremental or 'as-you-type' search</p>");
00931
00932 else
00933 msg = i18n("<p>Usage: <code>replace[:bceprsw] PATTERN REPLACEMENT</code></p>");
00934
00935 msg += i18n(
00936 "<h4><caption>Options</h4><p>"
00937 "<b>b</b> - Search backward"
00938 "<br><b>c</b> - Search from cursor"
00939 "<br><b>r</b> - Pattern is a regular expression"
00940 "<br><b>s</b> - Case sensitive search"
00941 );
00942
00943 if ( cmd == "find" )
00944 msg += i18n(
00945 "<br><b>e</b> - Search in selected text only"
00946 "<br><b>w</b> - Search whole words only"
00947 );
00948
00949 if ( cmd == "replace" )
00950 msg += i18n(
00951 "<br><b>p</b> - Prompt for replace</p>"
00952 "<p>If REPLACEMENT is not present, an empty string is used.</p>"
00953 "<p>If you want to have whitespace in your PATTERN, you need to "
00954 "quote both PATTERN and REPLACEMENT with either single or double "
00955 "quotes. To have the quote characters in the strings, prepend them "
00956 "with a backslash.");
00957
00958 msg += "</p>";
00959 return true;
00960 }
00961
00962 TQStringList SearchCommand::cmds()
00963 {
00964 TQStringList l;
00965 l << "find" << "replace" << "ifind";
00966 return l;
00967 }
00968
00969 bool SearchCommand::wantsToProcessText( const TQString &cmdname )
00970 {
00971 return cmdname == "ifind";
00972 }
00973
00974 void SearchCommand::processText( Kate::View *view, const TQString &cmd )
00975 {
00976 static TQRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)");
00977 if ( re_ifind.search( cmd ) > -1 )
00978 {
00979 TQString flags = re_ifind.cap( 1 );
00980 TQString pattern = re_ifind.cap( 2 );
00981
00982
00983
00984 if ( ! m_ifindFlags || pattern.isEmpty() )
00985 ifindInit( flags );
00986
00987 else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
00988 m_ifindFlags |= KFindDialog::FromCursor;
00989
00990
00991 if ( ! pattern.isEmpty() )
00992 {
00993 KateView *v = (KateView*)view;
00994
00995
00996
00997
00998
00999 if ( pattern.startsWith( v->selection() ) &&
01000 v->selection().length() + 1 == pattern.length() )
01001 v->setCursorPositionInternal( v->selStartLine(), v->selStartCol() );
01002
01003 v->find( pattern, m_ifindFlags, false );
01004 }
01005 }
01006 }
01007
01008 void SearchCommand::ifindInit( const TQString &flags )
01009 {
01010 long f = 0;
01011 if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
01012 if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
01013 if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
01014 if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
01015 m_ifindFlags = f;
01016 }
01017
01018 void SearchCommand::ifindClear()
01019 {
01020 m_ifindFlags = 0;
01021 }
01022
01023
01024