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