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