32 #include <QtGui/QLineEdit>
33 #include <QtGui/QVBoxLayout>
34 #include <QtGui/QLabel>
35 #include <QtGui/QCompleter>
36 #include <QtGui/QApplication>
37 #include <KDE/KColorScheme>
44 return s1.toLower() < s2.toLower();
47 bool isCharEscaped(
const QString&
string,
int charPos)
53 int numContiguousBackslashesToLeft = 0;
55 while (charPos >= 0 &&
string[charPos] ==
'\\')
57 numContiguousBackslashesToLeft++;
60 return ((numContiguousBackslashesToLeft % 2) == 1);
63 QString toggledEscaped(
const QString& originalString, QChar escapeChar)
66 QString toggledEscapedString = originalString;
69 const int indexOfEscapeChar = toggledEscapedString.indexOf(escapeChar , searchFrom);
70 if (indexOfEscapeChar == -1)
74 if (!isCharEscaped(toggledEscapedString, indexOfEscapeChar))
77 toggledEscapedString.replace(indexOfEscapeChar, 1,
QString(
"\\") + escapeChar);
78 searchFrom = indexOfEscapeChar + 2;
83 toggledEscapedString.remove(indexOfEscapeChar - 1, 1);
84 searchFrom = indexOfEscapeChar;
88 return toggledEscapedString;
91 QString ensuredCharEscaped(
const QString& originalString, QChar charToEscape)
93 QString escapedString = originalString;
94 for (
int i = 0; i < escapedString.length(); i++)
96 if (escapedString[i] == charToEscape && !isCharEscaped(escapedString, i))
98 escapedString.replace(i, 1,
QString(
"\\") + charToEscape);
101 return escapedString;
106 QString qtRegexPattern = vimRegexPattern;
107 qtRegexPattern = toggledEscaped(qtRegexPattern,
'(');
108 qtRegexPattern = toggledEscaped(qtRegexPattern,
')');
109 qtRegexPattern = toggledEscaped(qtRegexPattern,
'+');
110 qtRegexPattern = toggledEscaped(qtRegexPattern,
'|');
111 qtRegexPattern = ensuredCharEscaped(qtRegexPattern,
'?');
115 bool lookingForMatchingCloseBracket =
false;
116 QList<int> matchingClosedCurlyBracketPositions;
117 for (
int i = 0; i < qtRegexPattern.length(); i++)
119 if (qtRegexPattern[i] ==
'{' && isCharEscaped(qtRegexPattern, i))
121 lookingForMatchingCloseBracket =
true;
123 if (qtRegexPattern[i] ==
'}' && lookingForMatchingCloseBracket && qtRegexPattern[i - 1] !=
'\\')
125 matchingClosedCurlyBracketPositions.append(i);
128 if (matchingClosedCurlyBracketPositions.isEmpty())
131 qtRegexPattern = toggledEscaped(qtRegexPattern,
'{');
132 qtRegexPattern = toggledEscaped(qtRegexPattern,
'}');
138 QString qtRegexPatternNonMatchingCurliesToggled;
139 int previousNonMatchingClosedCurlyPos = 0;
142 foreach (
int matchingClosedCurlyPos, matchingClosedCurlyBracketPositions)
144 QString chunkExcludingMatchingCurlyClosed = qtRegexPattern.mid(previousNonMatchingClosedCurlyPos, matchingClosedCurlyPos - previousNonMatchingClosedCurlyPos);
145 chunkExcludingMatchingCurlyClosed = toggledEscaped(chunkExcludingMatchingCurlyClosed,
'{');
146 chunkExcludingMatchingCurlyClosed = toggledEscaped(chunkExcludingMatchingCurlyClosed,
'}');
147 qtRegexPatternNonMatchingCurliesToggled += chunkExcludingMatchingCurlyClosed +
148 qtRegexPattern[matchingClosedCurlyPos];
149 previousNonMatchingClosedCurlyPos = matchingClosedCurlyPos + 1;
151 QString chunkAfterLastMatchingClosedCurly = qtRegexPattern.mid(matchingClosedCurlyBracketPositions.last() + 1);
152 chunkAfterLastMatchingClosedCurly = toggledEscaped(chunkAfterLastMatchingClosedCurly,
'{');
153 chunkAfterLastMatchingClosedCurly = toggledEscaped(chunkAfterLastMatchingClosedCurly,
'}');
154 qtRegexPatternNonMatchingCurliesToggled += chunkAfterLastMatchingClosedCurly;
156 qtRegexPattern = qtRegexPatternNonMatchingCurliesToggled;
163 bool lookingForMatchingCloseBracket =
false;
164 int openingBracketPos = -1;
166 for (
int i = 0; i < qtRegexPattern.length(); i++)
168 if (qtRegexPattern[i] ==
'[' && !isCharEscaped(qtRegexPattern, i) && !lookingForMatchingCloseBracket)
170 lookingForMatchingCloseBracket =
true;
171 openingBracketPos = i;
173 if (qtRegexPattern[i] ==
']' && lookingForMatchingCloseBracket && !isCharEscaped(qtRegexPattern, i))
175 lookingForMatchingCloseBracket =
false;
176 matchingSquareBracketPositions.append(openingBracketPos);
177 matchingSquareBracketPositions.append(i);
181 if (matchingSquareBracketPositions.isEmpty())
184 qtRegexPattern = ensuredCharEscaped(qtRegexPattern,
'[');
185 qtRegexPattern = ensuredCharEscaped(qtRegexPattern,
']');
191 QString qtRegexPatternNonMatchingSquaresMadeLiteral;
192 int previousNonMatchingSquareBracketPos = 0;
195 foreach (
int matchingSquareBracketPos, matchingSquareBracketPositions)
197 QString chunkExcludingMatchingSquareBrackets = qtRegexPattern.mid(previousNonMatchingSquareBracketPos, matchingSquareBracketPos - previousNonMatchingSquareBracketPos);
198 chunkExcludingMatchingSquareBrackets = ensuredCharEscaped(chunkExcludingMatchingSquareBrackets,
'[');
199 chunkExcludingMatchingSquareBrackets = ensuredCharEscaped(chunkExcludingMatchingSquareBrackets,
']');
200 qtRegexPatternNonMatchingSquaresMadeLiteral += chunkExcludingMatchingSquareBrackets + qtRegexPattern[matchingSquareBracketPos];
201 previousNonMatchingSquareBracketPos = matchingSquareBracketPos + 1;
203 QString chunkAfterLastMatchingSquareBracket = qtRegexPattern.mid(matchingSquareBracketPositions.last() + 1);
204 chunkAfterLastMatchingSquareBracket = ensuredCharEscaped(chunkAfterLastMatchingSquareBracket,
'[');
205 chunkAfterLastMatchingSquareBracket = ensuredCharEscaped(chunkAfterLastMatchingSquareBracket,
']');
206 qtRegexPatternNonMatchingSquaresMadeLiteral += chunkAfterLastMatchingSquareBracket;
208 qtRegexPattern = qtRegexPatternNonMatchingSquaresMadeLiteral;
212 qtRegexPattern = qtRegexPattern.replace(
"\\>",
"\\b");
213 qtRegexPattern = qtRegexPattern.replace(
"\\<",
"\\b");
215 return qtRegexPattern;
222 QString escapedForSearchingAsLiteral(
const QString& originalQtRegex)
224 QString escapedForSearchingAsLiteral = originalQtRegex;
225 escapedForSearchingAsLiteral.replace(
'\\',
"\\\\");
226 escapedForSearchingAsLiteral.replace(
'$',
"\\$");
227 escapedForSearchingAsLiteral.replace(
'^',
"\\^");
228 escapedForSearchingAsLiteral.replace(
'.',
"\\.");
229 escapedForSearchingAsLiteral.replace(
'*',
"\\*");
230 escapedForSearchingAsLiteral.replace(
'/',
"\\/");
231 escapedForSearchingAsLiteral.replace(
'[',
"\\[");
232 escapedForSearchingAsLiteral.replace(
']',
"\\]");
233 escapedForSearchingAsLiteral.replace(
'\n',
"\\n");
234 return escapedForSearchingAsLiteral;
240 std::reverse(reversedList.begin(), reversedList.end());
245 QString withCaseSensitivityMarkersStripped(
const QString& originalSearchTerm)
249 QString caseSensitivityMarkersStripped = originalSearchTerm;
250 while (pos < caseSensitivityMarkersStripped.length())
252 if (caseSensitivityMarkersStripped.at(pos) ==
'C' && isCharEscaped(caseSensitivityMarkersStripped, pos))
254 caseSensitivityMarkersStripped.replace(pos - 1, 2,
"");
259 return caseSensitivityMarkersStripped;
262 int findPosOfSearchConfigMarker(
const QString& searchText,
const bool isSearchBackwards)
264 const QChar searchConfigMarkerChar = (isSearchBackwards ?
'?' :
'/');
265 for (
int pos = 0; pos < searchText.length(); pos++)
267 if (searchText.at(pos) == searchConfigMarkerChar)
269 if (!isCharEscaped(searchText, pos))
278 bool isRepeatLastSearch(
const QString& searchText,
const bool isSearchBackwards)
280 const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, isSearchBackwards);
281 if (posOfSearchConfigMarker != -1)
283 if (searchText.left(posOfSearchConfigMarker).isEmpty())
291 bool shouldPlaceCursorAtEndOfMatch(
const QString& searchText,
const bool isSearchBackwards)
293 const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, isSearchBackwards);
294 if (posOfSearchConfigMarker != -1)
296 if (searchText.length() > posOfSearchConfigMarker + 1 && searchText.at(posOfSearchConfigMarker + 1) ==
'e')
304 QString withSearchConfigRemoved(
const QString& originalSearchText,
const bool isSearchBackwards)
306 const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(originalSearchText, isSearchBackwards);
307 if (posOfSearchConfigMarker == -1)
309 return originalSearchText;
313 return originalSearchText.left(posOfSearchConfigMarker);
324 m_suspendEditEventFiltering(false),
325 m_waitingForRegister(false),
326 m_insertedTextShouldBeEscapedForSearchingAsLiteral(false),
327 m_commandResponseMessageTimeOutMS(4000),
328 m_isNextTextChangeDueToCompletionChange(false),
329 m_currentCompletionType(
None),
330 m_currentSearchIsCaseSensitive(false),
331 m_currentSearchIsBackwards(false),
332 m_currentSearchPlacesCursorAtEndOfMatch(false),
333 m_isSendingSyntheticSearchCompletedKeypress(false)
335 QHBoxLayout * layout =
new QHBoxLayout();
337 m_barTypeIndicator =
new QLabel(
this);
338 m_barTypeIndicator->setObjectName(
"bartypeindicator");
339 layout->addWidget(m_barTypeIndicator);
342 m_edit->setObjectName(
"commandtext");
343 layout->addWidget(m_edit);
345 m_commandResponseMessageDisplay =
new QLabel(
this);
346 m_commandResponseMessageDisplay->setObjectName(
"commandresponsemessage");
347 m_commandResponseMessageDisplay->setAlignment(Qt::AlignLeft);
348 layout->addWidget(m_commandResponseMessageDisplay);
350 m_waitingForRegisterIndicator =
new QLabel(
this);
351 m_waitingForRegisterIndicator->setObjectName(
"waitingforregisterindicator");
352 m_waitingForRegisterIndicator->setVisible(
false);
353 m_waitingForRegisterIndicator->setText(
"\"");
354 layout->addWidget(m_waitingForRegisterIndicator);
356 m_interactiveSedReplaceLabel =
new QLabel(
this);
357 m_interactiveSedReplaceLabel->setObjectName(
"interactivesedreplace");
358 m_interactiveSedReplaceActive =
false;
359 layout->addWidget(m_interactiveSedReplaceLabel);
361 updateMatchHighlightAttrib();
363 m_highlightedMatch->
setView(m_view);
366 m_highlightedMatch->
setZDepth (-10000.0);
367 m_highlightedMatch->
setAttribute(m_highlightMatchAttribute);
368 connect(m_view, SIGNAL(configChanged()),
369 this, SLOT(updateMatchHighlightAttrib()));
371 m_edit->installEventFilter(
this);
372 connect(m_edit, SIGNAL(textChanged(
QString)),
this, SLOT(editTextChanged(
QString)));
374 m_completer =
new QCompleter(
QStringList(), m_edit);
377 m_completer->setWidget(m_edit);
378 m_completer->setObjectName(
"completer");
379 m_completionModel =
new QStringListModel;
380 m_completer->setModel(m_completionModel);
381 m_completer->setCaseSensitivity(Qt::CaseInsensitive);
382 m_completer->popup()->installEventFilter(
this);
384 m_commandResponseMessageDisplayHide =
new QTimer(
this);
385 m_commandResponseMessageDisplayHide->setSingleShot(
true);
386 connect(m_commandResponseMessageDisplayHide, SIGNAL(
timeout()),
391 connect(m_view, SIGNAL(focusOut(
KTextEditor::View*)), m_commandResponseMessageDisplayHide, SLOT(
stop()));
393 connect(m_view, SIGNAL(focusIn(
KTextEditor::View*)),
this, SLOT(startHideCommandResponseTimer()));
398 delete m_highlightedMatch;
403 m_currentCompletionType = None;
408 showBarTypeIndicator(mode);
410 setBarBackground(Normal);
414 m_interactiveSedReplaceActive =
false;
415 m_interactiveSedReplaceLabel->hide();
418 m_edit->setText(initialText);
421 m_commandResponseMessageDisplay->hide();
422 m_commandResponseMessageDisplayHide->stop();
428 while(QApplication::hasPendingEvents())
430 QApplication::processEvents();
441 m_commandResponseMessageTimeOutMS = commandResponseMessageTimeOutMS;
447 if (m_startingCursorPos.
isValid())
451 moveCursorTo(m_startingCursorPos);
455 updateMatchHighlight(Range::invalid());
456 m_completer->popup()->hide();
464 const Qt::Key syntheticSearchCompletedKey = (m_wasAborted ?
static_cast<Qt::Key
>(0) : Qt::Key_Enter);
465 QKeyEvent syntheticSearchCompletedKeyPress(QEvent::KeyPress, syntheticSearchCompletedKey, Qt::NoModifier);
466 m_isSendingSyntheticSearchCompletedKeypress =
true;
467 QApplication::sendEvent(m_view->focusProxy(), &syntheticSearchCompletedKeyPress);
468 m_isSendingSyntheticSearchCompletedKeypress =
false;
492 void KateViEmulatedCommandBar::updateMatchHighlightAttrib()
495 if (!m_highlightMatchAttribute)
499 m_highlightMatchAttribute->setBackground(matchColour);
505 void KateViEmulatedCommandBar::updateMatchHighlight(
const Range& matchRange)
509 m_highlightedMatch->
setRange(matchRange);
512 void KateViEmulatedCommandBar::setBarBackground(KateViEmulatedCommandBar::BarBackgroundStatus status)
514 QPalette barBackground(m_edit->palette());
529 barBackground = QPalette();
533 m_edit->setPalette(barBackground);
536 bool KateViEmulatedCommandBar::eventFilter(
QObject*
object,
QEvent* event)
538 Q_ASSERT(
object == m_edit ||
object == m_completer->popup());
539 if (m_suspendEditEventFiltering)
544 if (event->type() == QEvent::KeyPress)
553 void KateViEmulatedCommandBar::deleteSpacesToLeftOfCursor()
555 while (m_edit->cursorPosition() != 0 && m_edit->text()[m_edit->cursorPosition() - 1] ==
' ')
561 void KateViEmulatedCommandBar::deleteWordCharsToLeftOfCursor()
563 while (m_edit->cursorPosition() != 0)
565 const QChar charToTheLeftOfCursor = m_edit->text()[m_edit->cursorPosition() - 1];
566 if (!charToTheLeftOfCursor.isLetterOrNumber() && charToTheLeftOfCursor !=
'_')
575 bool KateViEmulatedCommandBar::deleteNonWordCharsToLeftOfCursor()
577 bool deletionsMade =
false;
578 while (m_edit->cursorPosition() != 0)
580 const QChar charToTheLeftOfCursor = m_edit->text()[m_edit->cursorPosition() - 1];
581 if (charToTheLeftOfCursor.isLetterOrNumber() || charToTheLeftOfCursor ==
'_' || charToTheLeftOfCursor ==
' ')
587 deletionsMade =
true;
589 return deletionsMade;
592 QString KateViEmulatedCommandBar::wordBeforeCursor()
594 int wordBeforeCursorBegin = m_edit->cursorPosition() - 1;
595 while (wordBeforeCursorBegin >= 0 && (m_edit->text()[wordBeforeCursorBegin].isLetterOrNumber() || m_edit->text()[wordBeforeCursorBegin] ==
'_'))
597 wordBeforeCursorBegin--;
599 wordBeforeCursorBegin++;
600 return m_edit->text().mid(wordBeforeCursorBegin, m_edit->cursorPosition() - wordBeforeCursorBegin);
603 QString KateViEmulatedCommandBar::commandBeforeCursor()
605 const QString textWithoutRangeExpression = withoutRangeExpression();
606 const int cursorPositionWithoutRangeExpression = m_edit->cursorPosition() - rangeExpression().length();
607 int commandBeforeCursorBegin = cursorPositionWithoutRangeExpression - 1;
608 while (commandBeforeCursorBegin >= 0 && (textWithoutRangeExpression[commandBeforeCursorBegin].isLetterOrNumber() || textWithoutRangeExpression[commandBeforeCursorBegin] ==
'_' || textWithoutRangeExpression[commandBeforeCursorBegin] ==
'-'))
610 commandBeforeCursorBegin--;
612 commandBeforeCursorBegin++;
613 return textWithoutRangeExpression.mid(commandBeforeCursorBegin, cursorPositionWithoutRangeExpression - commandBeforeCursorBegin);
617 void KateViEmulatedCommandBar::replaceWordBeforeCursorWith(
const QString& newWord)
619 const int wordBeforeCursorStart = m_edit->cursorPosition() - wordBeforeCursor().length();
620 const QString newText = m_edit->text().left(m_edit->cursorPosition() - wordBeforeCursor().length()) +
622 m_edit->text().mid(m_edit->cursorPosition());
623 m_edit->setText(newText);
624 m_edit->setCursorPosition(wordBeforeCursorStart + newWord.length());
627 void KateViEmulatedCommandBar::replaceCommandBeforeCursorWith(
const QString& newCommand)
629 const QString newText = m_edit->text().left(m_edit->cursorPosition() - commandBeforeCursor().length()) +
631 m_edit->text().mid(m_edit->cursorPosition());
632 m_edit->setText(newText);
636 void KateViEmulatedCommandBar::activateSearchHistoryCompletion()
638 m_currentCompletionType = SearchHistory;
639 m_completionModel->setStringList(reversed(
KateGlobal::self()->viInputModeGlobal()->searchHistory()));
640 updateCompletionPrefix();
641 m_completer->complete();
644 void KateViEmulatedCommandBar::activateWordFromDocumentCompletion()
646 m_currentCompletionType = WordFromDocument;
647 QRegExp wordRegEx(
"\\w{1,}");
652 for (
int lineNum = startLine; lineNum < endLine; lineNum++)
655 int wordSearchBeginPos = 0;
656 while (wordRegEx.indexIn(line, wordSearchBeginPos) != -1)
658 const QString foundWord = wordRegEx.cap(0);
659 foundWords << foundWord;
660 wordSearchBeginPos = wordRegEx.indexIn(line, wordSearchBeginPos) + wordRegEx.matchedLength();
664 qSort(foundWords.begin(), foundWords.end(), caseInsensitiveLessThan);
665 m_completionModel->setStringList(foundWords);
666 updateCompletionPrefix();
667 m_completer->complete();
670 void KateViEmulatedCommandBar::activateCommandCompletion()
672 m_completionModel->setStringList(
KateCmd::self()->commandCompletionObject()->items());
673 m_currentCompletionType = Commands;
676 void KateViEmulatedCommandBar::activateCommandHistoryCompletion()
678 m_currentCompletionType = CommandHistory;
679 m_completionModel->setStringList(reversed(
KateGlobal::self()->viInputModeGlobal()->commandHistory()));
680 updateCompletionPrefix();
681 m_completer->complete();
684 void KateViEmulatedCommandBar::activateSedFindHistoryCompletion()
688 m_currentCompletionType = SedFindHistory;
689 m_completionModel->setStringList(reversed(
KateGlobal::self()->viInputModeGlobal()->searchHistory()));
690 m_completer->setCompletionPrefix(sedFindTerm());
691 m_completer->complete();
695 void KateViEmulatedCommandBar::activateSedReplaceHistoryCompletion()
699 m_currentCompletionType = SedReplaceHistory;
700 m_completionModel->setStringList(reversed(
KateGlobal::self()->viInputModeGlobal()->replaceHistory()));
701 m_completer->setCompletionPrefix(sedReplaceTerm());
702 m_completer->complete();
706 void KateViEmulatedCommandBar::deactivateCompletion()
708 kDebug(13070) <<
"Manually dismissing completions";
709 m_completer->popup()->hide();
710 m_currentCompletionType = None;
713 void KateViEmulatedCommandBar::abortCompletionAndResetToPreCompletion()
715 deactivateCompletion();
716 m_isNextTextChangeDueToCompletionChange =
true;
717 m_edit->setText(m_textToRevertToIfCompletionAborted);
718 m_edit->setCursorPosition(m_cursorPosToRevertToIfCompletionAborted);
719 m_isNextTextChangeDueToCompletionChange =
false;
722 void KateViEmulatedCommandBar::updateCompletionPrefix()
725 if (m_currentCompletionType == WordFromDocument)
727 m_completer->setCompletionPrefix(wordBeforeCursor());
729 else if (m_currentCompletionType == SearchHistory)
731 m_completer->setCompletionPrefix(m_edit->text());
733 else if (m_currentCompletionType == CommandHistory)
735 m_completer->setCompletionPrefix(m_edit->text());
737 else if (m_currentCompletionType == Commands)
739 m_completer->setCompletionPrefix(commandBeforeCursor());
743 Q_ASSERT(
false &&
"Unhandled completion type");
746 m_completer->complete();
749 void KateViEmulatedCommandBar::currentCompletionChanged()
752 const QString newCompletion = m_completer->currentCompletion();
753 if (newCompletion.isEmpty())
757 m_isNextTextChangeDueToCompletionChange =
true;
758 if (m_currentCompletionType == WordFromDocument)
760 replaceWordBeforeCursorWith(newCompletion);
762 else if (m_currentCompletionType == SearchHistory)
764 m_edit->setText(newCompletion);
766 else if (m_currentCompletionType == CommandHistory)
768 m_edit->setText(newCompletion);
770 else if (m_currentCompletionType == Commands)
772 const int newCursorPosition = m_edit->cursorPosition() + (newCompletion.length() - commandBeforeCursor().length());
773 replaceCommandBeforeCursorWith(newCompletion);
774 m_edit->setCursorPosition(newCursorPosition);
776 else if (m_currentCompletionType == SedFindHistory)
778 m_edit->setText(withSedFindTermReplacedWith(withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(newCompletion))));
779 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
780 m_edit->setCursorPosition(parsedSedExpression.findEndPos + 1);
782 else if (m_currentCompletionType == SedReplaceHistory)
784 m_edit->setText(withSedReplaceTermReplacedWith(withSedDelimiterEscaped(newCompletion)));
785 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
786 m_edit->setCursorPosition(parsedSedExpression.replaceEndPos + 1);
790 Q_ASSERT(
false &&
"Something went wrong, here - completion with unrecognised completion type");
792 m_isNextTextChangeDueToCompletionChange =
false;
795 void KateViEmulatedCommandBar::setCompletionIndex(
int index)
797 const QModelIndex modelIndex = m_completer->popup()->model()->index(index, 0);
799 m_completer->popup()->setCurrentIndex(modelIndex);
800 m_completer->setCurrentRow(index);
802 m_completer->popup()->scrollTo(modelIndex);
804 currentCompletionChanged();
807 KateViEmulatedCommandBar::ParsedSedExpression KateViEmulatedCommandBar::parseAsSedExpression()
809 const QString commandWithoutRangeExpression = withoutRangeExpression();
810 ParsedSedExpression parsedSedExpression;
812 parsedSedExpression.parsedSuccessfully =
KateCommands::SedReplace::parse(commandWithoutRangeExpression, delimiter, parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos, parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos);
813 if (parsedSedExpression.parsedSuccessfully)
815 parsedSedExpression.delimiter = delimiter.at(0);
816 if (parsedSedExpression.replaceBeginPos == -1)
818 if (parsedSedExpression.findBeginPos != -1)
822 parsedSedExpression.replaceBeginPos = commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.findEndPos) + 1;
823 parsedSedExpression.replaceEndPos = parsedSedExpression.replaceBeginPos - 1;
828 parsedSedExpression.replaceBeginPos = 0;
829 for (
int delimiterCount = 1; delimiterCount <= 3; delimiterCount++)
831 parsedSedExpression.replaceBeginPos = commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.replaceBeginPos + 1);
833 parsedSedExpression.replaceEndPos = parsedSedExpression.replaceBeginPos - 1;
836 if (parsedSedExpression.findBeginPos == -1)
840 parsedSedExpression.findBeginPos = commandWithoutRangeExpression.indexOf(delimiter) + 1;
841 parsedSedExpression.findEndPos = parsedSedExpression.findBeginPos - 1;
846 if (parsedSedExpression.parsedSuccessfully)
848 parsedSedExpression.findBeginPos += rangeExpression().length();
849 parsedSedExpression.findEndPos += rangeExpression().length();
850 parsedSedExpression.replaceBeginPos += rangeExpression().length();
851 parsedSedExpression.replaceEndPos += rangeExpression().length();
853 return parsedSedExpression;
856 QString KateViEmulatedCommandBar::withSedFindTermReplacedWith(
const QString& newFindTerm)
858 const QString command = m_edit->text();
859 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
860 Q_ASSERT(parsedSedExpression.parsedSuccessfully);
861 return command.mid(0, parsedSedExpression.findBeginPos) +
863 command.mid(parsedSedExpression.findEndPos + 1);
867 QString KateViEmulatedCommandBar::withSedReplaceTermReplacedWith(
const QString& newReplaceTerm)
869 const QString command = m_edit->text();
870 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
871 Q_ASSERT(parsedSedExpression.parsedSuccessfully);
872 return command.mid(0, parsedSedExpression.replaceBeginPos) +
874 command.mid(parsedSedExpression.replaceEndPos + 1);
877 QString KateViEmulatedCommandBar::sedFindTerm()
879 const QString command = m_edit->text();
880 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
881 Q_ASSERT(parsedSedExpression.parsedSuccessfully);
882 return command.mid(parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + 1);
885 QString KateViEmulatedCommandBar::sedReplaceTerm()
887 const QString command = m_edit->text();
888 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
889 Q_ASSERT(parsedSedExpression.parsedSuccessfully);
890 return command.mid(parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos - parsedSedExpression.replaceBeginPos + 1);
893 QString KateViEmulatedCommandBar::withSedDelimiterEscaped(
const QString& text)
895 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
896 QString delimiterEscaped = ensuredCharEscaped(text, parsedSedExpression.delimiter);
897 return delimiterEscaped;
900 bool KateViEmulatedCommandBar::isCursorInFindTermOfSed()
902 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
903 return parsedSedExpression.parsedSuccessfully && (m_edit->cursorPosition() >= parsedSedExpression.findBeginPos && m_edit->cursorPosition() <= parsedSedExpression.findEndPos + 1);
906 bool KateViEmulatedCommandBar::isCursorInReplaceTermOfSed()
908 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
909 return parsedSedExpression.parsedSuccessfully && m_edit->cursorPosition() >= parsedSedExpression.replaceBeginPos && m_edit->cursorPosition() <= parsedSedExpression.replaceEndPos + 1;
912 QString KateViEmulatedCommandBar::withoutRangeExpression()
914 const QString originalCommand = m_edit->text();
915 return originalCommand.mid(rangeExpression().length());
918 QString KateViEmulatedCommandBar::rangeExpression()
922 const QString command = m_edit->text();
924 return rangeExpression;
929 if (keyEvent->modifiers() == Qt::ControlModifier && (keyEvent->key() == Qt::Key_C || keyEvent->key() == Qt::Key_BracketLeft) && !m_waitingForRegister)
931 if (m_currentCompletionType == None || !m_completer->popup()->isVisible())
937 abortCompletionAndResetToPreCompletion();
941 if (m_interactiveSedReplaceActive)
946 if (keyEvent->text() ==
"y" || keyEvent->text() ==
"n")
948 const Cursor cursorPosIfFinalMatch = m_interactiveSedReplacer->currentMatch().start();
949 if (keyEvent->text() ==
"y")
951 m_interactiveSedReplacer->replaceCurrentMatch();
955 m_interactiveSedReplacer->skipCurrentMatch();
957 updateMatchHighlight(m_interactiveSedReplacer->currentMatch());
958 updateInteractiveSedReplaceLabelText();
959 moveCursorTo(m_interactiveSedReplacer->currentMatch().start());
961 if (!m_interactiveSedReplacer->currentMatch().isValid())
963 moveCursorTo(cursorPosIfFinalMatch);
964 finishInteractiveSedReplace();
968 else if (keyEvent->text() ==
"l")
970 m_interactiveSedReplacer->replaceCurrentMatch();
971 finishInteractiveSedReplace();
974 else if (keyEvent->text() ==
"q")
976 finishInteractiveSedReplace();
979 else if (keyEvent->text() ==
"a")
981 m_interactiveSedReplacer->replaceAllRemaining();
982 finishInteractiveSedReplace();
987 if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_Space)
989 activateWordFromDocumentCompletion();
992 if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_P)
994 if (!m_completer->popup()->isVisible())
998 if (isCursorInFindTermOfSed())
1000 activateSedFindHistoryCompletion();
1002 else if (isCursorInReplaceTermOfSed())
1004 activateSedReplaceHistoryCompletion();
1008 activateCommandHistoryCompletion();
1013 activateSearchHistoryCompletion();
1015 if (m_currentCompletionType != None)
1017 setCompletionIndex(0);
1023 if (m_completer->currentRow() + 1 == m_completer->completionCount())
1025 setCompletionIndex(0);
1029 setCompletionIndex(m_completer->currentRow() + 1);
1034 if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_N)
1036 if (!m_completer->popup()->isVisible())
1040 activateCommandHistoryCompletion();
1044 activateSearchHistoryCompletion();
1046 setCompletionIndex(m_completer->completionCount() - 1);
1051 if (m_completer->currentRow() == 0)
1053 setCompletionIndex(m_completer->completionCount() - 1);
1057 setCompletionIndex(m_completer->currentRow() - 1);
1062 if (m_waitingForRegister)
1064 if (keyEvent->key() != Qt::Key_Shift && keyEvent->key() != Qt::Key_Control)
1068 const int oldCursorPosition = m_edit->cursorPosition();
1070 if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_W)
1078 if (m_insertedTextShouldBeEscapedForSearchingAsLiteral)
1080 textToInsert = escapedForSearchingAsLiteral(textToInsert);
1081 m_insertedTextShouldBeEscapedForSearchingAsLiteral =
false;
1083 m_edit->setText(m_edit->text().insert(m_edit->cursorPosition(), textToInsert));
1084 m_edit->setCursorPosition(oldCursorPosition + textToInsert.length());
1085 m_waitingForRegister =
false;
1086 m_waitingForRegisterIndicator->setVisible(
false);
1089 else if ((keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_H) || keyEvent->key() == Qt::Key_Backspace)
1091 if (m_edit->text().isEmpty())
1095 m_edit->backspace();
1098 else if (keyEvent->modifiers() == Qt::ControlModifier)
1100 if (keyEvent->key() == Qt::Key_B)
1102 m_edit->setCursorPosition(0);
1105 else if (keyEvent->key() == Qt::Key_W)
1107 deleteSpacesToLeftOfCursor();
1108 if(!deleteNonWordCharsToLeftOfCursor())
1110 deleteWordCharsToLeftOfCursor();
1114 else if (keyEvent->key() == Qt::Key_R || keyEvent->key() == Qt::Key_G)
1116 m_waitingForRegister =
true;
1117 m_waitingForRegisterIndicator->setVisible(
true);
1118 if (keyEvent->key() == Qt::Key_G)
1120 m_insertedTextShouldBeEscapedForSearchingAsLiteral =
true;
1124 else if (keyEvent->key() == Qt::Key_D || keyEvent->key() == Qt::Key_F)
1128 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
1129 if (parsedSedExpression.parsedSuccessfully)
1131 const bool clearFindTerm = (keyEvent->key() == Qt::Key_D);
1134 m_edit->setSelection(parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + 1);
1140 m_edit->setSelection(parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos - parsedSedExpression.replaceBeginPos + 1);
1149 else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
1151 if (m_completer->popup()->isVisible() && m_currentCompletionType == KateViEmulatedCommandBar::WordFromDocument)
1153 deactivateCompletion();
1157 m_wasAborted =
false;
1158 deactivateCompletion();
1161 kDebug(13070) <<
"Executing: " << m_edit->text();
1162 QString commandToExecute = m_edit->text();
1163 ParsedSedExpression parsedSedExpression = parseAsSedExpression();
1164 qDebug() <<
"text:\n" << m_edit->text() <<
"\n is sed replace: " << parsedSedExpression.parsedSuccessfully;
1165 if (parsedSedExpression.parsedSuccessfully)
1167 const QString originalFindTerm = sedFindTerm();
1168 const QString convertedFindTerm = vimRegexToQtRegexPattern(originalFindTerm);
1169 const QString commandWithSedSearchRegexConverted = withSedFindTermReplacedWith(convertedFindTerm);
1171 const QString replaceTerm = sedReplaceTerm();
1173 commandToExecute = commandWithSedSearchRegexConverted;
1174 kDebug(13070) <<
"Command to execute after replacing search term: "<< commandToExecute;
1177 const QString commandResponseMessage = executeCommand(commandToExecute);
1178 if (!m_interactiveSedReplaceActive)
1180 if (commandResponseMessage.isEmpty() && !m_interactiveSedReplaceActive)
1186 switchToCommandResponseDisplay(commandResponseMessage);
1200 m_suspendEditEventFiltering =
true;
1207 QKeyEvent keyEventCopy(keyEvent->type(), keyEvent->key(), keyEvent->modifiers(), keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count());
1208 if (!m_interactiveSedReplaceActive)
1210 qApp->notify(m_edit, &keyEventCopy);
1212 m_suspendEditEventFiltering =
false;
1219 return m_isSendingSyntheticSearchCompletedKeypress;
1224 m_interactiveSedReplaceActive =
true;
1225 m_interactiveSedReplacer = interactiveSedReplace;
1226 if (!interactiveSedReplace->currentMatch().isValid())
1230 finishInteractiveSedReplace();
1233 kDebug(13070) <<
"Starting incremental search and replace";
1234 m_commandResponseMessageDisplay->hide();
1236 m_barTypeIndicator->hide();
1237 m_interactiveSedReplaceLabel->show();
1238 updateMatchHighlight(interactiveSedReplace->currentMatch());
1239 updateInteractiveSedReplaceLabelText();
1240 moveCursorTo(interactiveSedReplace->currentMatch().start());
1245 QChar barTypeIndicator = QChar::Null;
1249 barTypeIndicator =
'/';
1252 barTypeIndicator =
'?';
1255 barTypeIndicator =
':';
1258 Q_ASSERT(
false &&
"Unknown mode!");
1260 m_barTypeIndicator->setText(barTypeIndicator);
1261 m_barTypeIndicator->show();
1264 QString KateViEmulatedCommandBar::executeCommand(
const QString& commandToExecute)
1272 Q_ASSERT(kateCommandLineEdit);
1273 const QString commandResponseMessage = kateCommandLineEdit->text();
1274 return commandResponseMessage;
1277 void KateViEmulatedCommandBar::switchToCommandResponseDisplay(
const QString& commandResponseMessage)
1282 m_interactiveSedReplaceLabel->hide();
1283 m_barTypeIndicator->hide();
1284 m_commandResponseMessageDisplay->show();
1285 m_commandResponseMessageDisplay->setText(commandResponseMessage);
1286 m_commandResponseMessageDisplayHide->start(m_commandResponseMessageTimeOutMS);
1289 void KateViEmulatedCommandBar::updateInteractiveSedReplaceLabelText()
1291 m_interactiveSedReplaceLabel->setText(m_interactiveSedReplacer->currentMatchReplacementConfirmationMessage() +
" (y/n/a/q/l)");
1294 void KateViEmulatedCommandBar::finishInteractiveSedReplace()
1296 switchToCommandResponseDisplay(m_interactiveSedReplacer->finalStatusReportMessage());
1297 m_interactiveSedReplacer.clear();
1300 void KateViEmulatedCommandBar::moveCursorTo(
const Cursor& cursorPos)
1309 void KateViEmulatedCommandBar::editTextChanged(
const QString& newText)
1311 Q_ASSERT(!m_interactiveSedReplaceActive);
1312 qDebug() <<
"New text: " << newText;
1313 if (!m_isNextTextChangeDueToCompletionChange)
1315 m_textToRevertToIfCompletionAborted = newText;
1316 m_cursorPosToRevertToIfCompletionAborted = m_edit->cursorPosition();
1320 QString qtRegexPattern = newText;
1322 const bool placeCursorAtEndOfMatch = shouldPlaceCursorAtEndOfMatch(qtRegexPattern, searchBackwards);
1323 if (isRepeatLastSearch(qtRegexPattern, searchBackwards))
1329 qtRegexPattern = withSearchConfigRemoved(qtRegexPattern, searchBackwards);
1330 qtRegexPattern = vimRegexToQtRegexPattern(qtRegexPattern);
1335 bool caseSensitive =
true;
1336 if (qtRegexPattern.toLower() == qtRegexPattern)
1338 caseSensitive =
false;
1341 qtRegexPattern = withCaseSensitivityMarkersStripped(qtRegexPattern);
1343 qDebug() <<
"Final regex: " << qtRegexPattern;
1345 m_currentSearchPattern = qtRegexPattern;
1346 m_currentSearchIsCaseSensitive = caseSensitive;
1347 m_currentSearchIsBackwards = searchBackwards;
1348 m_currentSearchPlacesCursorAtEndOfMatch = placeCursorAtEndOfMatch;
1358 if (realMatchEnd.
column() == -1)
1362 moveCursorTo(placeCursorAtEndOfMatch ? realMatchEnd : match.
start());
1363 setBarBackground(MatchFound);
1367 moveCursorTo(m_startingCursorPos);
1368 if (!m_edit->text().isEmpty())
1370 setBarBackground(NoMatchFound);
1374 setBarBackground(Normal);
1378 updateMatchHighlight(match);
1382 if (m_mode ==
Command && m_currentCompletionType == None && !withoutRangeExpression().isEmpty())
1384 activateCommandCompletion();
1390 const bool commandBeforeCursorIsLeading = (m_edit->cursorPosition() - commandBeforeCursor().length() == rangeExpression().length());
1391 if (m_mode ==
Command && !commandBeforeCursorIsLeading && m_currentCompletionType == Commands && !m_isNextTextChangeDueToCompletionChange)
1393 deactivateCompletion();
1398 if (!m_isNextTextChangeDueToCompletionChange && m_completer->popup()->currentIndex().row() != -1)
1400 deactivateCompletion();
1403 if (m_currentCompletionType != None && !m_isNextTextChangeDueToCompletionChange)
1405 updateCompletionPrefix();
1409 void KateViEmulatedCommandBar::startHideCommandResponseTimer()
1411 if (m_commandResponseMessageDisplay->isVisible() && !m_commandResponseMessageDisplayHide->isActive())
1413 m_commandResponseMessageDisplayHide->start(m_commandResponseMessageTimeOutMS);
void startInteractiveSearchAndReplace(QSharedPointer< KateCommands::SedReplace::InteractiveSedReplacer > interactiveSedReplace)
virtual KTextEditor::MovingRange * newMovingRange(const KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors=KTextEditor::MovingRange::DoNotExpand, KTextEditor::MovingRange::EmptyBehavior emptyBehavior=KTextEditor::MovingRange::AllowEmpty)
Create a new moving range for this document.
KateRenderer * renderer()
KTextEditor::Document * document() const
virtual bool isValid() const
virtual int lineLength(int line) const
void setText(const QString &text, bool selected=true)
static KateGlobal * self()
Kate Part Internal stuff ;)
bool isSendingSyntheticSearchCompletedKeypress()
const QChar KeyEventToQChar(const QKeyEvent &keyEvent)
bool setCursorPosition(KTextEditor::Cursor position)
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KateViInputModeManager * getViInputModeManager()
static KTextEditor::Range parseRangeExpression(const QString &command, KateView *view, QString &destRangeExpression, QString &destTransformedCommand)
Attempt to parse any leading range expression (e.g.
virtual void setAttributeOnlyForViews(bool onlyForViews)=0
void goToPos(const Cursor &c)
virtual bool isValid() const
KateRendererConfig * config() const
Configuration.
void setCommandResponseMessageTimeout(long commandResponseMessageTimeOutMS)
KateCommandLineBar * cmdLineBar()
void init(Mode mode, const QString &initialText=QString())
virtual void setAttribute(Attribute::Ptr attribute)=0
Range findPattern(const QString &pattern, bool backwards, bool caseSensitive, const Cursor &startFrom, int count=-1) const
virtual void setRange(const KTextEditor::Range &range)=0
virtual void setView(View *view)=0
KTextEditor::Cursor cursorPosition() const
virtual QString line(int line) const =0
KateViGlobal * viInputModeGlobal()
vi input mode global
bool handleKeyPress(const QKeyEvent *keyEvent)
QString getWord(const KTextEditor::Cursor &cursor)
static void adjustBackground(QPalette &, BackgroundRole newRole=NormalBackground, QPalette::ColorRole color=QPalette::Base, ColorSet set=View, KSharedConfigPtr=KSharedConfigPtr())
ViMode getCurrentViMode() const
KateViEmulatedCommandBar(KateView *view, QWidget *parent=0)
virtual void setZDepth(qreal zDepth)=0
const QColor & searchHighlightColor() const
void appendReplaceHistoryItem(const QString &replaceHistoryItem)
void appendCommandHistoryItem(const QString &commandHistoryItem)
KateDocument * doc()
accessor to katedocument pointer
void appendSearchHistoryItem(const QString &searchHistoryItem)
static KateViKeyParser * self()
QString getRegisterContent(const QChar ®) const
virtual ~KateViEmulatedCommandBar()
void execute(const QString &text)
static bool parse(const QString &sedReplaceString, QString &destDelim, int &destFindBeginPos, int &destFindEndPos, int &destReplaceBeginPos, int &destReplaceEndPos)
Parses sedReplaceString to see if it is a valid sed replace expression (e.g.
virtual int lines() const =0