summaryrefslogtreecommitdiffstats
path: root/kate/part/katesearch.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kate/part/katesearch.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kate/part/katesearch.cpp')
-rw-r--r--kate/part/katesearch.cpp1012
1 files changed, 1012 insertions, 0 deletions
diff --git a/kate/part/katesearch.cpp b/kate/part/katesearch.cpp
new file mode 100644
index 000000000..8f4911137
--- /dev/null
+++ b/kate/part/katesearch.cpp
@@ -0,0 +1,1012 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2004-2005 Anders Lund <anders@alweb.dk>
+ Copyright (C) 2003 Clarence Dang <dang@kde.org>
+ Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
+ Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
+ Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "katesearch.h"
+#include "katesearch.moc"
+
+#include "kateview.h"
+#include "katedocument.h"
+#include "katesupercursor.h"
+#include "katearbitraryhighlight.h"
+#include "kateconfig.h"
+#include "katehighlight.h"
+
+#include <klocale.h>
+#include <kstdaction.h>
+#include <kmessagebox.h>
+#include <kstringhandler.h>
+#include <kdebug.h>
+#include <kfinddialog.h>
+#include <kreplacedialog.h>
+#include <kpushbutton.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+
+//BEGIN KateSearch
+QStringList KateSearch::s_searchList = QStringList();
+QStringList KateSearch::s_replaceList = QStringList();
+QString KateSearch::s_pattern = QString();
+static const bool arbitraryHLExample = false;
+
+KateSearch::KateSearch( KateView* view )
+ : QObject( view, "kate search" )
+ , m_view( view )
+ , m_doc( view->doc() )
+ , replacePrompt( new KateReplacePrompt( view ) )
+{
+ m_arbitraryHLList = new KateSuperRangeList();
+ if (arbitraryHLExample) m_doc->arbitraryHL()->addHighlightToView(m_arbitraryHLList, m_view);
+
+ connect(replacePrompt,SIGNAL(clicked()),this,SLOT(replaceSlot()));
+}
+
+KateSearch::~KateSearch()
+{
+ delete m_arbitraryHLList;
+}
+
+void KateSearch::createActions( KActionCollection* ac )
+{
+ KStdAction::find( this, SLOT(find()), ac )->setWhatsThis(
+ i18n("Look up the first occurrence of a piece of text or regular expression."));
+ KStdAction::findNext( this, SLOT(slotFindNext()), ac )->setWhatsThis(
+ i18n("Look up the next occurrence of the search phrase."));
+ KStdAction::findPrev( this, SLOT(slotFindPrev()), ac, "edit_find_prev" )->setWhatsThis(
+ i18n("Look up the previous occurrence of the search phrase."));
+ KStdAction::replace( this, SLOT(replace()), ac )->setWhatsThis(
+ i18n("Look up a piece of text or regular expression and replace the result with some given text."));
+}
+
+void KateSearch::addToList( QStringList& list, const QString& s )
+{
+ if( list.count() > 0 ) {
+ QStringList::Iterator it = list.find( s );
+ if( *it != 0L )
+ list.remove( it );
+ if( list.count() >= 16 )
+ list.remove( list.fromLast() );
+ }
+ list.prepend( s );
+}
+
+void KateSearch::find()
+{
+ // if multiline selection around, search in it
+ long searchf = KateViewConfig::global()->searchFlags();
+ if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
+ searchf |= KFindDialog::SelectedText;
+
+ KFindDialog *findDialog = new KFindDialog ( m_view, "", searchf,
+ s_searchList, m_view->hasSelection() );
+
+ findDialog->setPattern (getSearchText());
+
+
+ if( findDialog->exec() == QDialog::Accepted ) {
+ s_searchList = findDialog->findHistory () ;
+ // Do *not* remove the QString() wrapping, it fixes a nasty crash
+ find( QString(s_searchList.first()), findDialog->options(), true, true );
+ }
+
+ delete findDialog;
+ m_view->repaintText ();
+}
+
+void KateSearch::find( const QString &pattern, long flags, bool add, bool shownotfound )
+{
+ KateViewConfig::global()->setSearchFlags( flags );
+ if( add )
+ addToList( s_searchList, pattern );
+
+ s_pattern = pattern;
+
+ SearchFlags searchFlags;
+
+ searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
+ searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
+ searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
+ && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
+ searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
+ searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
+ searchFlags.prompt = false;
+ searchFlags.replace = false;
+ searchFlags.finished = false;
+ searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
+ searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
+
+ if ( searchFlags.selected )
+ {
+ s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
+ s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
+ s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
+ } else {
+ s.cursor = getCursor( searchFlags );
+ }
+
+ s.wrappedEnd = s.cursor;
+ s.wrapped = false;
+ s.showNotFound = shownotfound;
+
+ search( searchFlags );
+}
+
+void KateSearch::replace()
+{
+ if (!doc()->isReadWrite()) return;
+
+ // if multiline selection around, search in it
+ long searchf = KateViewConfig::global()->searchFlags();
+ if (m_view->hasSelection() && m_view->selStartLine() != m_view->selEndLine())
+ searchf |= KFindDialog::SelectedText;
+
+ KReplaceDialog *replaceDialog = new KReplaceDialog ( m_view, "", searchf,
+ s_searchList, s_replaceList, m_view->hasSelection() );
+
+ replaceDialog->setPattern (getSearchText());
+
+ if( replaceDialog->exec() == QDialog::Accepted ) {
+ long opts = replaceDialog->options();
+ m_replacement = replaceDialog->replacement();
+ s_searchList = replaceDialog->findHistory () ;
+ s_replaceList = replaceDialog->replacementHistory () ;
+
+ // Do *not* remove the QString() wrapping, it fixes a nasty crash
+ replace( QString(s_searchList.first()), m_replacement, opts );
+ }
+
+ delete replaceDialog;
+ m_view->update ();
+}
+
+void KateSearch::replace( const QString& pattern, const QString &replacement, long flags )
+{
+ if (!doc()->isReadWrite()) return;
+
+ addToList( s_searchList, pattern );
+ s_pattern = pattern;
+ addToList( s_replaceList, replacement );
+ m_replacement = replacement;
+ KateViewConfig::global()->setSearchFlags( flags );
+
+ SearchFlags searchFlags;
+ searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
+ searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
+ searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
+ && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
+ searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
+ searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
+ searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
+ searchFlags.replace = true;
+ searchFlags.finished = false;
+ searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
+ searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
+ if ( searchFlags.selected )
+ {
+ s.selBegin = KateTextCursor( m_view->selStartLine(), m_view->selStartCol() );
+ s.selEnd = KateTextCursor( m_view->selEndLine(), m_view->selEndCol() );
+ s.cursor = s.flags.backward ? s.selEnd : s.selBegin;
+ } else {
+ s.cursor = getCursor( searchFlags );
+ }
+
+ s.wrappedEnd = s.cursor;
+ s.wrapped = false;
+
+ search( searchFlags );
+}
+
+void KateSearch::findAgain( bool reverseDirection )
+{
+ SearchFlags searchFlags;
+ searchFlags.caseSensitive = KateViewConfig::global()->searchFlags() & KFindDialog::CaseSensitive;
+ searchFlags.wholeWords = KateViewConfig::global()->searchFlags() & KFindDialog::WholeWordsOnly;
+ searchFlags.fromBeginning = !(KateViewConfig::global()->searchFlags() & KFindDialog::FromCursor)
+ && !(KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText);
+ searchFlags.backward = KateViewConfig::global()->searchFlags() & KFindDialog::FindBackwards;
+ searchFlags.selected = KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText;
+ searchFlags.prompt = KateViewConfig::global()->searchFlags() & KReplaceDialog::PromptOnReplace;
+ searchFlags.replace = false;
+ searchFlags.finished = false;
+ searchFlags.regExp = KateViewConfig::global()->searchFlags() & KFindDialog::RegularExpression;
+ searchFlags.useBackRefs = KateViewConfig::global()->searchFlags() & KReplaceDialog::BackReference;
+
+ if (reverseDirection)
+ searchFlags.backward = !searchFlags.backward;
+
+ searchFlags.fromBeginning = false;
+ searchFlags.prompt = true; // ### why is the above assignment there?
+
+ s.cursor = getCursor( searchFlags );
+ search( searchFlags );
+}
+
+void KateSearch::search( SearchFlags flags )
+{
+ s.flags = flags;
+
+ if( s.flags.fromBeginning ) {
+ if( !s.flags.backward ) {
+ s.cursor.setPos(0, 0);
+ } else {
+ s.cursor.setLine(doc()->numLines() - 1);
+ s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
+ }
+ }
+
+ if((!s.flags.backward &&
+ s.cursor.col() == 0 &&
+ s.cursor.line() == 0 ) ||
+ ( s.flags.backward &&
+ s.cursor.col() == doc()->lineLength( s.cursor.line() ) &&
+ s.cursor.line() == (((int)doc()->numLines()) - 1) ) ) {
+ s.flags.finished = true;
+ }
+
+ if( s.flags.replace ) {
+ replaces = 0;
+ if( s.flags.prompt )
+ promptReplace();
+ else
+ replaceAll();
+ } else {
+ findAgain();
+ }
+}
+
+void KateSearch::wrapSearch()
+{
+ if( s.flags.selected )
+ {
+ KateTextCursor start (s.selBegin);
+ KateTextCursor end (s.selEnd);
+
+ // recalc for block sel, to have start with lowest col, end with highest
+ if (m_view->blockSelectionMode())
+ {
+ start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
+ end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
+ }
+
+ s.cursor = s.flags.backward ? end : start;
+ }
+ else
+ {
+ if( !s.flags.backward ) {
+ s.cursor.setPos(0, 0);
+ } else {
+ s.cursor.setLine(doc()->numLines() - 1);
+ s.cursor.setCol(doc()->lineLength( s.cursor.line() ) );
+ }
+ }
+
+ // oh, we wrapped around one time allready now !
+ // only check that on replace
+ s.wrapped = s.flags.replace;
+
+ replaces = 0;
+ s.flags.finished = true;
+}
+
+void KateSearch::findAgain()
+{
+ if( s_pattern.isEmpty() ) {
+ find();
+ return;
+ }
+
+ if ( doSearch( s_pattern ) ) {
+ exposeFound( s.cursor, s.matchedLength );
+ } else if( !s.flags.finished ) {
+ if( askContinue() ) {
+ wrapSearch();
+ findAgain();
+ } else {
+ if (arbitraryHLExample) m_arbitraryHLList->clear();
+ }
+ } else {
+ if (arbitraryHLExample) m_arbitraryHLList->clear();
+ if ( s.showNotFound )
+ KMessageBox::sorry( view(),
+ i18n("Search string '%1' not found!")
+ .arg( KStringHandler::csqueeze( s_pattern ) ),
+ i18n("Find"));
+ }
+}
+
+void KateSearch::replaceAll()
+{
+ doc()->editStart ();
+
+ while( doSearch( s_pattern ) )
+ replaceOne();
+
+ doc()->editEnd ();
+
+ if( !s.flags.finished ) {
+ if( askContinue() ) {
+ wrapSearch();
+ replaceAll();
+ }
+ } else {
+ KMessageBox::information( view(),
+ i18n("%n replacement made.","%n replacements made.",replaces),
+ i18n("Replace") );
+ }
+}
+
+void KateSearch::promptReplace()
+{
+ if ( doSearch( s_pattern ) ) {
+ exposeFound( s.cursor, s.matchedLength );
+ replacePrompt->show();
+ replacePrompt->setFocus ();
+ } else if( !s.flags.finished && askContinue() ) {
+ wrapSearch();
+ promptReplace();
+ } else {
+ if (arbitraryHLExample) m_arbitraryHLList->clear();
+ replacePrompt->hide();
+ KMessageBox::information( view(),
+ i18n("%n replacement made.","%n replacements made.",replaces),
+ i18n("Replace") );
+ }
+}
+
+void KateSearch::replaceOne()
+{
+ QString replaceWith = m_replacement;
+ if ( s.flags.regExp && s.flags.useBackRefs ) {
+ // replace each "(?!\)\d+" with the corresponding capture
+ QRegExp br("\\\\(\\d+)");
+ int pos = br.search( replaceWith );
+ int ncaps = m_re.numCaptures();
+ while ( pos >= 0 ) {
+ QString sc;
+ if ( !pos || replaceWith.at( pos-1) != '\\' ) {
+ int ccap = br.cap(1).toInt();
+ if (ccap <= ncaps ) {
+ sc = m_re.cap( ccap );
+ replaceWith.replace( pos, br.matchedLength(), sc );
+ }
+ else {
+ kdDebug()<<"KateSearch::replaceOne(): you don't have "<<ccap<<" backreferences in regexp '"<<m_re.pattern()<<"'"<<endl;
+ }
+ }
+ pos = br.search( replaceWith, pos + (int)sc.length() );
+ }
+ }
+
+ doc()->editStart();
+ doc()->removeText( s.cursor.line(), s.cursor.col(),
+ s.cursor.line(), s.cursor.col() + s.matchedLength );
+ doc()->insertText( s.cursor.line(), s.cursor.col(), replaceWith );
+ doc()->editEnd(),
+
+ replaces++;
+
+ // if we inserted newlines, we better adjust.
+ uint newlines = replaceWith.contains('\n');
+ if ( newlines )
+ {
+ if ( ! s.flags.backward )
+ {
+ s.cursor.setLine( s.cursor.line() + newlines );
+ s.cursor.setCol( replaceWith.length() - replaceWith.findRev('\n') );
+ }
+ // selection?
+ if ( s.flags.selected )
+ s.selEnd.setLine( s.selEnd.line() + newlines );
+ }
+
+
+ // adjust selection endcursor if needed
+ if( s.flags.selected && s.cursor.line() == s.selEnd.line() )
+ {
+ s.selEnd.setCol(s.selEnd.col() + replaceWith.length() - s.matchedLength );
+ }
+
+ // adjust wrap cursor if needed
+ if( s.cursor.line() == s.wrappedEnd.line() && s.cursor.col() <= s.wrappedEnd.col())
+ {
+ s.wrappedEnd.setCol(s.wrappedEnd.col() + replaceWith.length() - s.matchedLength );
+ }
+
+ if( !s.flags.backward ) {
+ s.cursor.setCol(s.cursor.col() + replaceWith.length());
+ } else if( s.cursor.col() > 0 ) {
+ s.cursor.setCol(s.cursor.col() - 1);
+ } else {
+ s.cursor.setLine(s.cursor.line() - 1);
+ if( s.cursor.line() >= 0 ) {
+ s.cursor.setCol(doc()->lineLength( s.cursor.line() ));
+ }
+ }
+}
+
+void KateSearch::skipOne()
+{
+ if( !s.flags.backward ) {
+ s.cursor.setCol(s.cursor.col() + s.matchedLength);
+ } else if( s.cursor.col() > 0 ) {
+ s.cursor.setCol(s.cursor.col() - 1);
+ } else {
+ s.cursor.setLine(s.cursor.line() - 1);
+ if( s.cursor.line() >= 0 ) {
+ s.cursor.setCol(doc()->lineLength(s.cursor.line()));
+ }
+ }
+}
+
+void KateSearch::replaceSlot() {
+ switch( (Dialog_results)replacePrompt->result() ) {
+ case srCancel: replacePrompt->hide(); break;
+ case srAll: replacePrompt->hide(); replaceAll(); break;
+ case srYes: replaceOne(); promptReplace(); break;
+ case srLast: replacePrompt->hide(), replaceOne(); break;
+ case srNo: skipOne(); promptReplace(); break;
+ }
+}
+
+bool KateSearch::askContinue()
+{
+ QString made =
+ i18n( "%n replacement made.",
+ "%n replacements made.",
+ replaces );
+
+ QString reached = !s.flags.backward ?
+ i18n( "End of document reached." ) :
+ i18n( "Beginning of document reached." );
+
+ if (KateViewConfig::global()->searchFlags() & KFindDialog::SelectedText)
+ {
+ reached = !s.flags.backward ?
+ i18n( "End of selection reached." ) :
+ i18n( "Beginning of selection reached." );
+ }
+
+ QString question = !s.flags.backward ?
+ i18n( "Continue from the beginning?" ) :
+ i18n( "Continue from the end?" );
+
+ QString text = s.flags.replace ?
+ made + "\n" + reached + "\n" + question :
+ reached + "\n" + question;
+
+ return KMessageBox::Yes == KMessageBox::questionYesNo(
+ view(), text, s.flags.replace ? i18n("Replace") : i18n("Find"),
+ KStdGuiItem::cont(), i18n("&Stop") );
+}
+
+QString KateSearch::getSearchText()
+{
+ // SelectionOnly: use selection
+ // WordOnly: use word under cursor
+ // SelectionWord: use selection if available, else use word under cursor
+ // WordSelection: use word if available, else use selection
+ QString str;
+
+ int getFrom = view()->config()->textToSearchMode();
+ switch (getFrom)
+ {
+ case KateViewConfig::SelectionOnly: // (Windows)
+ //kdDebug() << "getSearchText(): SelectionOnly" << endl;
+ if( m_view->hasSelection() )
+ str = m_view->selection();
+ break;
+
+ case KateViewConfig::SelectionWord: // (classic Kate behavior)
+ //kdDebug() << "getSearchText(): SelectionWord" << endl;
+ if( m_view->hasSelection() )
+ str = m_view->selection();
+ else
+ str = view()->currentWord();
+ break;
+
+ case KateViewConfig::WordOnly: // (weird?)
+ //kdDebug() << "getSearchText(): WordOnly" << endl;
+ str = view()->currentWord();
+ break;
+
+ case KateViewConfig::WordSelection: // (persistent selection lover)
+ //kdDebug() << "getSearchText(): WordSelection" << endl;
+ str = view()->currentWord();
+ if (str.isEmpty() && m_view->hasSelection() )
+ str = m_view->selection();
+ break;
+
+ default: // (nowhere)
+ //kdDebug() << "getSearchText(): Nowhere" << endl;
+ break;
+ }
+
+ str.replace( QRegExp("^\\n"), "" );
+ str.replace( QRegExp("\\n.*"), "" );
+
+ return str;
+}
+
+KateTextCursor KateSearch::getCursor( SearchFlags flags )
+{
+ if (flags.backward && !flags.selected && view()->hasSelection())
+ {
+ // We're heading backwards (and not within a selection),
+ // the selection might start before the cursor.
+ return kMin( KateTextCursor(view()->selStartLine(), view()->selStartCol()),
+ KateTextCursor(view()->cursorLine(), view()->cursorColumnReal()));
+ }
+ return KateTextCursor(view()->cursorLine(), view()->cursorColumnReal());
+}
+
+bool KateSearch::doSearch( const QString& text )
+{
+/*
+ rodda: Still Working on this... :)
+
+ bool result = false;
+
+ if (m_searchResults.count()) {
+ m_resultIndex++;
+ if (m_resultIndex < (int)m_searchResults.count()) {
+ s = m_searchResults[m_resultIndex];
+ result = true;
+ }
+
+ } else {
+ int temp = 0;
+ do {*/
+
+#if 0
+ static int oldLine = -1;
+ static int oldCol = -1;
+#endif
+
+ uint line = s.cursor.line();
+ uint col = s.cursor.col();// + (result ? s.matchedLength : 0);
+ bool backward = s.flags.backward;
+ bool caseSensitive = s.flags.caseSensitive;
+ bool regExp = s.flags.regExp;
+ bool wholeWords = s.flags.wholeWords;
+ uint foundLine, foundCol, matchLen;
+ bool found = false;
+ //kdDebug() << "Searching at " << line << ", " << col << endl;
+// kdDebug()<<"KateSearch::doSearch: "<<line<<", "<<col<<", "<<backward<<endl;
+
+ if (backward)
+ {
+ KateDocCursor docCursor(line, col, doc());
+
+ // If we're at the top of the document, we're not gonna find anything, so bail.
+ if (docCursor.line() == 0 && docCursor.col() == 0)
+ return false;
+
+ // Move one step backward before searching, if this is a "find again", we don't
+ // want to find the same match.
+ docCursor.moveBackward(1);
+ line = docCursor.line();
+ col = docCursor.col();
+ }
+
+ do {
+ if( regExp ) {
+ m_re = QRegExp( text, caseSensitive );
+ found = doc()->searchText( line, col, m_re,
+ &foundLine, &foundCol,
+ &matchLen, backward );
+ }
+ else if ( wholeWords )
+ {
+ bool maybefound = false;
+ do
+ {
+ maybefound = doc()->searchText( line, col, text,
+ &foundLine, &foundCol,
+ &matchLen, caseSensitive, backward );
+ if ( maybefound )
+ {
+ found = (
+ ( foundCol == 0 ||
+ ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol - 1 ) ) ) &&
+ ( foundCol + matchLen == doc()->lineLength( foundLine ) ||
+ ! doc()->highlight()->isInWord( doc()->textLine( foundLine ).at( foundCol + matchLen ) ) )
+ );
+ if ( found )
+ {
+ break;
+ }
+ else if ( backward && foundCol == 0 ) // we are done on this line and want to avoid endless loops like in #137312
+ {
+ if ( line == 0 ) // we are completely done...
+ break;
+ else
+ line--;
+ }
+ else
+ {
+ line = foundLine;
+ col = foundCol + 1;
+ }
+ }
+ } while ( maybefound );
+ }
+ else {
+ found = doc()->searchText( line, col, text,
+ &foundLine, &foundCol,
+ &matchLen, caseSensitive, backward );
+ }
+
+ if ( found && s.flags.selected )
+ {
+ KateTextCursor start (s.selBegin);
+ KateTextCursor end (s.selEnd);
+
+ // recalc for block sel, to have start with lowest col, end with highest
+ if (m_view->blockSelectionMode())
+ {
+ start.setCol (kMin(s.selBegin.col(), s.selEnd.col()));
+ end.setCol (kMax(s.selBegin.col(), s.selEnd.col()));
+ }
+
+ if ( !s.flags.backward && KateTextCursor( foundLine, foundCol ) >= end
+ || s.flags.backward && KateTextCursor( foundLine, foundCol ) < start )
+ {
+ found = false;
+ }
+ else if (m_view->blockSelectionMode())
+ {
+ if ((int)foundCol >= start.col() && (int)foundCol < end.col())
+ break;
+ }
+ }
+
+ line = foundLine;
+ col = foundCol+1;
+ }
+ while (s.flags.selected && m_view->blockSelectionMode() && found);
+ // in the case we want to search in selection + blockselection we need to loop
+
+ if( !found ) return false;
+
+ // save the search result
+ s.cursor.setPos(foundLine, foundCol);
+ s.matchedLength = matchLen;
+
+ // we allready wrapped around one time
+ if (s.wrapped)
+ {
+ if (s.flags.backward)
+ {
+ if ( (s.cursor.line() < s.wrappedEnd.line())
+ || ( (s.cursor.line() == s.wrappedEnd.line()) && ((s.cursor.col()+matchLen) <= uint(s.wrappedEnd.col())) ) )
+ return false;
+ }
+ else
+ {
+ if ( (s.cursor.line() > s.wrappedEnd.line())
+ || ( (s.cursor.line() == s.wrappedEnd.line()) && (s.cursor.col() > s.wrappedEnd.col()) ) )
+ return false;
+ }
+ }
+
+// kdDebug() << "Found at " << s.cursor.line() << ", " << s.cursor.col() << endl;
+
+
+ //m_searchResults.append(s);
+
+ if (arbitraryHLExample) {
+ 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);
+ hl->setBold();
+ hl->setTextColor(Qt::white);
+ hl->setBGColor(Qt::black);
+ // destroy the highlight upon change
+ connect(hl, SIGNAL(contentsChanged()), hl, SIGNAL(eliminated()));
+ m_arbitraryHLList->append(hl);
+ }
+
+ return true;
+
+ /* rodda: more of my search highlighting work
+
+ } while (++temp < 100);
+
+ if (result) {
+ s = m_searchResults.first();
+ m_resultIndex = 0;
+ }
+ }
+
+ return result;*/
+}
+
+void KateSearch::exposeFound( KateTextCursor &cursor, int slen )
+{
+ view()->setCursorPositionInternal ( cursor.line(), cursor.col() + slen, 1 );
+ view()->setSelection( cursor.line(), cursor.col(), cursor.line(), cursor.col() + slen );
+ view()->syncSelectionCache();
+}
+//END KateSearch
+
+//BEGIN KateReplacePrompt
+// this dialog is not modal
+KateReplacePrompt::KateReplacePrompt ( QWidget *parent )
+ : KDialogBase ( parent, 0L, false, i18n( "Replace Confirmation" ),
+ User3 | User2 | User1 | Close | Ok , Ok, true,
+ i18n("Replace &All"), i18n("Re&place && Close"), i18n("&Replace") )
+{
+ setButtonOK( i18n("&Find Next") );
+ QWidget *page = new QWidget(this);
+ setMainWidget(page);
+
+ QBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+ QLabel *label = new QLabel(i18n("Found an occurrence of your search term. What do you want to do?"),page);
+ topLayout->addWidget(label );
+}
+
+void KateReplacePrompt::slotOk ()
+{ // Search Next
+ done(KateSearch::srNo);
+ actionButton(Ok)->setFocus();
+}
+
+void KateReplacePrompt::slotClose ()
+{ // Close
+ done(KateSearch::srCancel);
+ actionButton(Close)->setFocus();
+}
+
+void KateReplacePrompt::slotUser1 ()
+{ // Replace All
+ done(KateSearch::srAll);
+ actionButton(User1)->setFocus();
+}
+
+void KateReplacePrompt::slotUser2 ()
+{ // Replace & Close
+ done(KateSearch::srLast);
+ actionButton(User2)->setFocus();
+}
+
+void KateReplacePrompt::slotUser3 ()
+{ // Replace
+ done(KateSearch::srYes);
+ actionButton(User3)->setFocus();
+}
+
+void KateReplacePrompt::done (int result)
+{
+ setResult(result);
+
+ emit clicked();
+}
+//END KateReplacePrompt
+
+//BEGIN SearchCommand
+bool SearchCommand::exec(class Kate::View *view, const QString &cmd, QString &msg)
+{
+ QString flags, pattern, replacement;
+ if ( cmd.startsWith( "find" ) )
+ {
+
+ static QRegExp re_find("find(?::([bcersw]*))?\\s+(.+)");
+ if ( re_find.search( cmd ) < 0 )
+ {
+ msg = i18n("Usage: find[:[bcersw]] PATTERN");
+ return false;
+ }
+ flags = re_find.cap( 1 );
+ pattern = re_find.cap( 2 );
+ }
+
+ else if ( cmd.startsWith( "ifind" ) )
+ {
+ static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s+(.*)");
+ if ( re_ifind.search( cmd ) < 0 )
+ {
+ msg = i18n("Usage: ifind[:[bcrs]] PATTERN");
+ return false;
+ }
+ ifindClear();
+ return true;
+ }
+
+ else if ( cmd.startsWith( "replace" ) )
+ {
+ // Try if the pattern and replacement is quoted, using a quote character ["']
+ static QRegExp re_rep("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s+\\2((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
+ // Or one quoted argument
+ QRegExp re_rep1("replace(?::([bceprsw]*))?\\s+([\"'])((?:[^\\\\\\\\2]|\\\\.)*)\\2\\s*$");
+ // Else, it's just one or two (space separated) words
+ QRegExp re_rep2("replace(?::([bceprsw]*))?\\s+(\\S+)(.*)");
+#define unbackslash(s) p=0;\
+while ( (p = pattern.find( '\\' + delim, p )) > -1 )\
+{\
+ if ( !p || pattern[p-1] != '\\' )\
+ pattern.remove( p, 1 );\
+ p++;\
+}
+
+ if ( re_rep.search( cmd ) >= 0 )
+ {
+ flags = re_rep.cap(1);
+ pattern = re_rep.cap( 3 );
+ replacement = re_rep.cap( 4 );
+
+ int p(0);
+ // unbackslash backslashed delimiter strings
+ // in pattern ..
+ QString delim = re_rep.cap( 2 );
+ unbackslash(pattern);
+ // .. and in replacement
+ unbackslash(replacement);
+ }
+ else if ( re_rep1.search( cmd ) >= 0 )
+ {
+ flags = re_rep1.cap(1);
+ pattern = re_rep1.cap( 3 );
+
+ int p(0);
+ QString delim = re_rep1.cap( 2 );
+ unbackslash(pattern);
+ }
+ else if ( re_rep2.search( cmd ) >= 0 )
+ {
+ flags = re_rep2.cap( 1 );
+ pattern = re_rep2.cap( 2 );
+ replacement = re_rep2.cap( 3 ).stripWhiteSpace();
+ }
+ else
+ {
+ msg = i18n("Usage: replace[:[bceprsw]] PATTERN [REPLACEMENT]");
+ return false;
+ }
+ kdDebug()<<"replace '"<<pattern<<"' with '"<<replacement<<"'"<<endl;
+#undef unbackslash
+ }
+
+ long f = 0;
+ if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
+ if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
+ if ( flags.contains( 'e' ) ) f |= KFindDialog::SelectedText;
+ if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
+ if ( flags.contains( 'p' ) ) f |= KReplaceDialog::PromptOnReplace;
+ if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
+ if ( flags.contains( 'w' ) ) f |= KFindDialog::WholeWordsOnly;
+
+ if ( cmd.startsWith( "find" ) )
+ {
+ ((KateView*)view)->find( pattern, f );
+ return true;
+ }
+ else if ( cmd.startsWith( "replace" ) )
+ {
+ f |= KReplaceDialog::BackReference; // mandatory here?
+ ((KateView*)view)->replace( pattern, replacement, f );
+ return true;
+ }
+
+ return false;
+}
+
+bool SearchCommand::help(class Kate::View *, const QString &cmd, QString &msg)
+{
+ if ( cmd == "find" )
+ msg = i18n("<p>Usage: <code>find[:bcersw] PATTERN</code></p>");
+
+ else if ( cmd == "ifind" )
+ msg = i18n("<p>Usage: <code>ifind:[:bcrs] PATTERN</code>"
+ "<br>ifind does incremental or 'as-you-type' search</p>");
+
+ else
+ msg = i18n("<p>Usage: <code>replace[:bceprsw] PATTERN REPLACEMENT</code></p>");
+
+ msg += i18n(
+ "<h4><caption>Options</h4><p>"
+ "<b>b</b> - Search backward"
+ "<br><b>c</b> - Search from cursor"
+ "<br><b>r</b> - Pattern is a regular expression"
+ "<br><b>s</b> - Case sensitive search"
+ );
+
+ if ( cmd == "find" )
+ msg += i18n(
+ "<br><b>e</b> - Search in selected text only"
+ "<br><b>w</b> - Search whole words only"
+ );
+
+ if ( cmd == "replace" )
+ msg += i18n(
+ "<br><b>p</b> - Prompt for replace</p>"
+ "<p>If REPLACEMENT is not present, an empty string is used.</p>"
+ "<p>If you want to have whitespace in your PATTERN, you need to "
+ "quote both PATTERN and REPLACEMENT with either single or double "
+ "quotes. To have the quote characters in the strings, prepend them "
+ "with a backslash.");
+
+ msg += "</p>";
+ return true;
+}
+
+QStringList SearchCommand::cmds()
+{
+ QStringList l;
+ l << "find" << "replace" << "ifind";
+ return l;
+}
+
+bool SearchCommand::wantsToProcessText( const QString &cmdname )
+{
+ return cmdname == "ifind";
+}
+
+void SearchCommand::processText( Kate::View *view, const QString &cmd )
+{
+ static QRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)");
+ if ( re_ifind.search( cmd ) > -1 )
+ {
+ QString flags = re_ifind.cap( 1 );
+ QString pattern = re_ifind.cap( 2 );
+
+
+ // if there is no setup, or the text length is 0, set up the properties
+ if ( ! m_ifindFlags || pattern.isEmpty() )
+ ifindInit( flags );
+ // if there is no fromCursor, add it if this is not the first character
+ else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() )
+ m_ifindFlags |= KFindDialog::FromCursor;
+
+ // search..
+ if ( ! pattern.isEmpty() )
+ {
+ KateView *v = (KateView*)view;
+
+ // If it *looks like* we are continuing, place the cursor
+ // at the beginning of the selection, so that the search continues.
+ // ### check more carefully, like is the cursor currently at the end
+ // of the selection.
+ if ( pattern.startsWith( v->selection() ) &&
+ v->selection().length() + 1 == pattern.length() )
+ v->setCursorPositionInternal( v->selStartLine(), v->selStartCol() );
+
+ v->find( pattern, m_ifindFlags, false );
+ }
+ }
+}
+
+void SearchCommand::ifindInit( const QString &flags )
+{
+ long f = 0;
+ if ( flags.contains( 'b' ) ) f |= KFindDialog::FindBackwards;
+ if ( flags.contains( 'c' ) ) f |= KFindDialog::FromCursor;
+ if ( flags.contains( 'r' ) ) f |= KFindDialog::RegularExpression;
+ if ( flags.contains( 's' ) ) f |= KFindDialog::CaseSensitive;
+ m_ifindFlags = f;
+}
+
+void SearchCommand::ifindClear()
+{
+ m_ifindFlags = 0;
+}
+//END SearchCommand
+
+// kate: space-indent on; indent-width 2; replace-tabs on;