• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • vimode
kateviemulatedcommandbar.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries and the Kate part.
2  *
3  * Copyright (C) 2013 Simon St James <kdedevel@etotheipiplusone.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 #include "kateviemulatedcommandbar.h"
21 #include "katevikeyparser.h"
22 #include "kateview.h"
23 #include "kateviglobal.h"
24 #include "katevinormalmode.h"
25 #include "katevivisualmode.h"
26 #include "katevicommandrangeexpressionparser.h"
27 #include "kateglobal.h"
28 #include "kateconfig.h"
29 #include "katecmd.h"
30 #include <katecmds.h>
31 
32 #include <QtGui/QLineEdit>
33 #include <QtGui/QVBoxLayout>
34 #include <QtGui/QLabel>
35 #include <QtGui/QCompleter>
36 #include <QtGui/QApplication>
37 #include <KDE/KColorScheme>
38 #include <algorithm>
39 
40 namespace
41 {
42  bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
43  {
44  return s1.toLower() < s2.toLower();
45  }
46 
47  bool isCharEscaped(const QString& string, int charPos)
48  {
49  if (charPos == 0)
50  {
51  return false;
52  }
53  int numContiguousBackslashesToLeft = 0;
54  charPos--;
55  while (charPos >= 0 && string[charPos] == '\\')
56  {
57  numContiguousBackslashesToLeft++;
58  charPos--;
59  }
60  return ((numContiguousBackslashesToLeft % 2) == 1);
61  }
62 
63  QString toggledEscaped(const QString& originalString, QChar escapeChar)
64  {
65  int searchFrom = 0;
66  QString toggledEscapedString = originalString;
67  do
68  {
69  const int indexOfEscapeChar = toggledEscapedString.indexOf(escapeChar , searchFrom);
70  if (indexOfEscapeChar == -1)
71  {
72  break;
73  }
74  if (!isCharEscaped(toggledEscapedString, indexOfEscapeChar))
75  {
76  // Escape.
77  toggledEscapedString.replace(indexOfEscapeChar, 1, QString("\\") + escapeChar);
78  searchFrom = indexOfEscapeChar + 2;
79  }
80  else
81  {
82  // Unescape.
83  toggledEscapedString.remove(indexOfEscapeChar - 1, 1);
84  searchFrom = indexOfEscapeChar;
85  }
86  } while (true);
87 
88  return toggledEscapedString;
89  }
90 
91  QString ensuredCharEscaped(const QString& originalString, QChar charToEscape)
92  {
93  QString escapedString = originalString;
94  for (int i = 0; i < escapedString.length(); i++)
95  {
96  if (escapedString[i] == charToEscape && !isCharEscaped(escapedString, i))
97  {
98  escapedString.replace(i, 1, QString("\\") + charToEscape);
99  }
100  }
101  return escapedString;
102  }
103 
104  QString vimRegexToQtRegexPattern(const QString& vimRegexPattern)
105  {
106  QString qtRegexPattern = vimRegexPattern;
107  qtRegexPattern = toggledEscaped(qtRegexPattern, '(');
108  qtRegexPattern = toggledEscaped(qtRegexPattern, ')');
109  qtRegexPattern = toggledEscaped(qtRegexPattern, '+');
110  qtRegexPattern = toggledEscaped(qtRegexPattern, '|');
111  qtRegexPattern = ensuredCharEscaped(qtRegexPattern, '?');
112  {
113  // All curly brackets, except the closing curly bracket of a matching pair where the opening bracket is escaped,
114  // must have their escaping toggled.
115  bool lookingForMatchingCloseBracket = false;
116  QList<int> matchingClosedCurlyBracketPositions;
117  for (int i = 0; i < qtRegexPattern.length(); i++)
118  {
119  if (qtRegexPattern[i] == '{' && isCharEscaped(qtRegexPattern, i))
120  {
121  lookingForMatchingCloseBracket = true;
122  }
123  if (qtRegexPattern[i] == '}' && lookingForMatchingCloseBracket && qtRegexPattern[i - 1] != '\\')
124  {
125  matchingClosedCurlyBracketPositions.append(i);
126  }
127  }
128  if (matchingClosedCurlyBracketPositions.isEmpty())
129  {
130  // Escape all {'s and }'s - there are no matching pairs.
131  qtRegexPattern = toggledEscaped(qtRegexPattern, '{');
132  qtRegexPattern = toggledEscaped(qtRegexPattern, '}');
133  }
134  else
135  {
136  // Ensure that every chunk of qtRegexPattern that does *not* contain a curly closing bracket
137  // that is matched have their { and } escaping toggled.
138  QString qtRegexPatternNonMatchingCurliesToggled;
139  int previousNonMatchingClosedCurlyPos = 0; // i.e. the position of the last character which is either
140  // not a curly closing bracket, or is a curly closing bracket
141  // that is not matched.
142  foreach (int matchingClosedCurlyPos, matchingClosedCurlyBracketPositions)
143  {
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;
150  }
151  QString chunkAfterLastMatchingClosedCurly = qtRegexPattern.mid(matchingClosedCurlyBracketPositions.last() + 1);
152  chunkAfterLastMatchingClosedCurly = toggledEscaped(chunkAfterLastMatchingClosedCurly, '{');
153  chunkAfterLastMatchingClosedCurly = toggledEscaped(chunkAfterLastMatchingClosedCurly, '}');
154  qtRegexPatternNonMatchingCurliesToggled += chunkAfterLastMatchingClosedCurly;
155 
156  qtRegexPattern = qtRegexPatternNonMatchingCurliesToggled;
157  }
158 
159  }
160 
161  // All square brackets, *except* for those that are a) unescaped; and b) form a matching pair, must be
162  // escaped.
163  bool lookingForMatchingCloseBracket = false;
164  int openingBracketPos = -1;
165  QList<int> matchingSquareBracketPositions;
166  for (int i = 0; i < qtRegexPattern.length(); i++)
167  {
168  if (qtRegexPattern[i] == '[' && !isCharEscaped(qtRegexPattern, i) && !lookingForMatchingCloseBracket)
169  {
170  lookingForMatchingCloseBracket = true;
171  openingBracketPos = i;
172  }
173  if (qtRegexPattern[i] == ']' && lookingForMatchingCloseBracket && !isCharEscaped(qtRegexPattern, i))
174  {
175  lookingForMatchingCloseBracket = false;
176  matchingSquareBracketPositions.append(openingBracketPos);
177  matchingSquareBracketPositions.append(i);
178  }
179  }
180 
181  if (matchingSquareBracketPositions.isEmpty())
182  {
183  // Escape all ['s and ]'s - there are no matching pairs.
184  qtRegexPattern = ensuredCharEscaped(qtRegexPattern, '[');
185  qtRegexPattern = ensuredCharEscaped(qtRegexPattern, ']');
186  }
187  else
188  {
189  // Ensure that every chunk of qtRegexPattern that does *not* contain one of the matching pairs of
190  // square brackets have their square brackets escaped.
191  QString qtRegexPatternNonMatchingSquaresMadeLiteral;
192  int previousNonMatchingSquareBracketPos = 0; // i.e. the position of the last character which is
193  // either not a square bracket, or is a square bracket but
194  // which is not matched.
195  foreach (int matchingSquareBracketPos, matchingSquareBracketPositions)
196  {
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;
202  }
203  QString chunkAfterLastMatchingSquareBracket = qtRegexPattern.mid(matchingSquareBracketPositions.last() + 1);
204  chunkAfterLastMatchingSquareBracket = ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, '[');
205  chunkAfterLastMatchingSquareBracket = ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, ']');
206  qtRegexPatternNonMatchingSquaresMadeLiteral += chunkAfterLastMatchingSquareBracket;
207 
208  qtRegexPattern = qtRegexPatternNonMatchingSquaresMadeLiteral;
209  }
210 
211 
212  qtRegexPattern = qtRegexPattern.replace("\\>", "\\b");
213  qtRegexPattern = qtRegexPattern.replace("\\<", "\\b");
214 
215  return qtRegexPattern;
216  }
217 
222  QString escapedForSearchingAsLiteral(const QString& originalQtRegex)
223  {
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;
235  }
236 
237  QStringList reversed(const QStringList& originalList)
238  {
239  QStringList reversedList = originalList;
240  std::reverse(reversedList.begin(), reversedList.end());
241  return reversedList;
242  }
243 
244 
245  QString withCaseSensitivityMarkersStripped(const QString& originalSearchTerm)
246  {
247  // Only \C is handled, for now - I'll implement \c if someone asks for it.
248  int pos = 0;
249  QString caseSensitivityMarkersStripped = originalSearchTerm;
250  while (pos < caseSensitivityMarkersStripped.length())
251  {
252  if (caseSensitivityMarkersStripped.at(pos) == 'C' && isCharEscaped(caseSensitivityMarkersStripped, pos))
253  {
254  caseSensitivityMarkersStripped.replace(pos - 1, 2, "");
255  pos--;
256  }
257  pos++;
258  }
259  return caseSensitivityMarkersStripped;
260  }
261 
262  int findPosOfSearchConfigMarker(const QString& searchText, const bool isSearchBackwards)
263  {
264  const QChar searchConfigMarkerChar = (isSearchBackwards ? '?' : '/');
265  for (int pos = 0; pos < searchText.length(); pos++)
266  {
267  if (searchText.at(pos) == searchConfigMarkerChar)
268  {
269  if (!isCharEscaped(searchText, pos))
270  {
271  return pos;
272  }
273  }
274  }
275  return -1;
276  }
277 
278  bool isRepeatLastSearch(const QString& searchText, const bool isSearchBackwards)
279  {
280  const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, isSearchBackwards);
281  if (posOfSearchConfigMarker != -1)
282  {
283  if (searchText.left(posOfSearchConfigMarker).isEmpty())
284  {
285  return true;
286  }
287  }
288  return false;
289  }
290 
291  bool shouldPlaceCursorAtEndOfMatch(const QString& searchText, const bool isSearchBackwards)
292  {
293  const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, isSearchBackwards);
294  if (posOfSearchConfigMarker != -1)
295  {
296  if (searchText.length() > posOfSearchConfigMarker + 1 && searchText.at(posOfSearchConfigMarker + 1) == 'e')
297  {
298  return true;
299  }
300  }
301  return false;
302  }
303 
304  QString withSearchConfigRemoved(const QString& originalSearchText, const bool isSearchBackwards)
305  {
306  const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(originalSearchText, isSearchBackwards);
307  if (posOfSearchConfigMarker == -1)
308  {
309  return originalSearchText;
310  }
311  else
312  {
313  return originalSearchText.left(posOfSearchConfigMarker);
314  }
315  }
316 }
317 
318 KateViEmulatedCommandBar::KateViEmulatedCommandBar(KateView* view, QWidget* parent)
319  : KateViewBarWidget(false, parent),
320  m_isActive(false),
321  m_mode(NoMode),
322  m_view(view),
323  m_wasAborted(true),
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)
334 {
335  QHBoxLayout * layout = new QHBoxLayout();
336  centralWidget()->setLayout(layout);
337  m_barTypeIndicator = new QLabel(this);
338  m_barTypeIndicator->setObjectName("bartypeindicator");
339  layout->addWidget(m_barTypeIndicator);
340 
341  m_edit = new QLineEdit(this);
342  m_edit->setObjectName("commandtext");
343  layout->addWidget(m_edit);
344 
345  m_commandResponseMessageDisplay = new QLabel(this);
346  m_commandResponseMessageDisplay->setObjectName("commandresponsemessage");
347  m_commandResponseMessageDisplay->setAlignment(Qt::AlignLeft);
348  layout->addWidget(m_commandResponseMessageDisplay);
349 
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);
355 
356  m_interactiveSedReplaceLabel = new QLabel(this);
357  m_interactiveSedReplaceLabel->setObjectName("interactivesedreplace");
358  m_interactiveSedReplaceActive = false;
359  layout->addWidget(m_interactiveSedReplaceLabel);
360 
361  updateMatchHighlightAttrib();
362  m_highlightedMatch = m_view->doc()->newMovingRange(Range::invalid(), Kate::TextRange::DoNotExpand);
363  m_highlightedMatch->setView(m_view); // Show only in this view.
364  m_highlightedMatch->setAttributeOnlyForViews(true);
365  // Use z depth defined in moving ranges interface.
366  m_highlightedMatch->setZDepth (-10000.0);
367  m_highlightedMatch->setAttribute(m_highlightMatchAttribute);
368  connect(m_view, SIGNAL(configChanged()),
369  this, SLOT(updateMatchHighlightAttrib()));
370 
371  m_edit->installEventFilter(this);
372  connect(m_edit, SIGNAL(textChanged(QString)), this, SLOT(editTextChanged(QString)));
373 
374  m_completer = new QCompleter(QStringList(), m_edit);
375  // Can't find a way to stop the QCompleter from auto-completing when attached to a QLineEdit,
376  // so don't actually set it as the QLineEdit's completer.
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);
383 
384  m_commandResponseMessageDisplayHide = new QTimer(this);
385  m_commandResponseMessageDisplayHide->setSingleShot(true);
386  connect(m_commandResponseMessageDisplayHide, SIGNAL(timeout()),
387  this, SIGNAL(hideMe()));
388  // Make sure the timer is stopped when the user switches views. If not, focus will be given to the
389  // wrong view when KateViewBar::hideCurrentBarWidget() is called as a result of m_commandResponseMessageDisplayHide
390  // timing out.
391  connect(m_view, SIGNAL(focusOut(KTextEditor::View*)), m_commandResponseMessageDisplayHide, SLOT(stop()));
392  // We can restart the timer once the view has focus again, though.
393  connect(m_view, SIGNAL(focusIn(KTextEditor::View*)), this, SLOT(startHideCommandResponseTimer()));
394 }
395 
396 KateViEmulatedCommandBar::~KateViEmulatedCommandBar()
397 {
398  delete m_highlightedMatch;
399 }
400 
401 void KateViEmulatedCommandBar::init(KateViEmulatedCommandBar::Mode mode, const QString& initialText)
402 {
403  m_currentCompletionType = None;
404  m_mode = mode;
405  m_isActive = true;
406  m_wasAborted = true;
407 
408  showBarTypeIndicator(mode);
409 
410  setBarBackground(Normal);
411 
412  m_startingCursorPos = m_view->cursorPosition();
413 
414  m_interactiveSedReplaceActive = false;
415  m_interactiveSedReplaceLabel->hide();
416 
417  m_edit->setFocus();
418  m_edit->setText(initialText);
419  m_edit->show();
420 
421  m_commandResponseMessageDisplay->hide();
422  m_commandResponseMessageDisplayHide->stop();
423 
424  // A change in focus will have occurred: make sure we process it now, instead of having it
425  // occur later and stop() m_commandResponseMessageDisplayHide.
426  // This is generally only a problem when feeding a sequence of keys without human intervention,
427  // as when we execute a mapping, macro, or test case.
428  while(QApplication::hasPendingEvents())
429  {
430  QApplication::processEvents();
431  }
432 }
433 
434 bool KateViEmulatedCommandBar::isActive()
435 {
436  return m_isActive;
437 }
438 
439 void KateViEmulatedCommandBar::setCommandResponseMessageTimeout(long int commandResponseMessageTimeOutMS)
440 {
441  m_commandResponseMessageTimeOutMS = commandResponseMessageTimeOutMS;
442 }
443 
444 void KateViEmulatedCommandBar::closed()
445 {
446  // Close can be called multiple times between init()'s, so only reset the cursor once!
447  if (m_startingCursorPos.isValid())
448  {
449  if (m_wasAborted)
450  {
451  moveCursorTo(m_startingCursorPos);
452  }
453  }
454  m_startingCursorPos = KTextEditor::Cursor::invalid();
455  updateMatchHighlight(Range::invalid());
456  m_completer->popup()->hide();
457  m_isActive = false;
458 
459  if (m_mode == SearchForward || m_mode == SearchBackward)
460  {
461  // Send a synthetic keypress through the system that signals whether the search was aborted or
462  // not. If not, the keypress will "complete" the search motion, thus triggering it.
463  // We send to KateViewInternal as it updates the status bar and removes the "?".
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;
469  if (!m_wasAborted)
470  {
471  m_view->getViInputModeManager()->setLastSearchPattern(m_currentSearchPattern);
472  m_view->getViInputModeManager()->setLastSearchCaseSensitive(m_currentSearchIsCaseSensitive);
473  m_view->getViInputModeManager()->setLastSearchBackwards(m_currentSearchIsBackwards);
474  m_view->getViInputModeManager()->setLastSearchPlacesCursorAtEndOfMatch(m_currentSearchPlacesCursorAtEndOfMatch);
475  }
476  KateGlobal::self()->viInputModeGlobal()->appendSearchHistoryItem(m_edit->text());
477  }
478  else
479  {
480  if (m_wasAborted)
481  {
482  // Appending the command to the history when it is executed is handled elsewhere; we can't
483  // do it inside closed() as we may still be showing the command response display.
484  KateGlobal::self()->viInputModeGlobal()->appendCommandHistoryItem(m_edit->text());
485  // With Vim, aborting a command returns us to Normal mode, even if we were in Visual Mode.
486  // If we switch from Visual to Normal mode, we need to clear the selection.
487  m_view->clearSelection();
488  }
489  }
490 }
491 
492 void KateViEmulatedCommandBar::updateMatchHighlightAttrib()
493 {
494  const QColor& matchColour = m_view->renderer()->config()->searchHighlightColor();
495  if (!m_highlightMatchAttribute)
496  {
497  m_highlightMatchAttribute = new KTextEditor::Attribute;
498  }
499  m_highlightMatchAttribute->setBackground(matchColour);
500  KTextEditor::Attribute::Ptr mouseInAttribute(new KTextEditor::Attribute());
501  m_highlightMatchAttribute->setDynamicAttribute (KTextEditor::Attribute::ActivateMouseIn, mouseInAttribute);
502  m_highlightMatchAttribute->dynamicAttribute (KTextEditor::Attribute::ActivateMouseIn)->setBackground(matchColour);
503 }
504 
505 void KateViEmulatedCommandBar::updateMatchHighlight(const Range& matchRange)
506 {
507  // Note that if matchRange is invalid, the highlight will not be shown, so we
508  // don't need to check for that explicitly.
509  m_highlightedMatch->setRange(matchRange);
510 }
511 
512 void KateViEmulatedCommandBar::setBarBackground(KateViEmulatedCommandBar::BarBackgroundStatus status)
513 {
514  QPalette barBackground(m_edit->palette());
515  switch (status)
516  {
517  case MatchFound:
518  {
519  KColorScheme::adjustBackground(barBackground, KColorScheme::PositiveBackground);
520  break;
521  }
522  case NoMatchFound:
523  {
524  KColorScheme::adjustBackground(barBackground, KColorScheme::NegativeBackground);
525  break;
526  }
527  case Normal:
528  {
529  barBackground = QPalette();
530  break;
531  }
532  }
533  m_edit->setPalette(barBackground);
534 }
535 
536 bool KateViEmulatedCommandBar::eventFilter(QObject* object, QEvent* event)
537 {
538  Q_ASSERT(object == m_edit || object == m_completer->popup());
539  if (m_suspendEditEventFiltering)
540  {
541  return false;
542  }
543  Q_UNUSED(object);
544  if (event->type() == QEvent::KeyPress)
545  {
546  // Re-route this keypress through Vim's central keypress handling area, so that we can use the keypress in e.g.
547  // mappings and macros.
548  return m_view->getViInputModeManager()->handleKeypress(static_cast<QKeyEvent*>(event));
549  }
550  return false;
551 }
552 
553 void KateViEmulatedCommandBar::deleteSpacesToLeftOfCursor()
554 {
555  while (m_edit->cursorPosition() != 0 && m_edit->text()[m_edit->cursorPosition() - 1] == ' ')
556  {
557  m_edit->backspace();
558  }
559 }
560 
561 void KateViEmulatedCommandBar::deleteWordCharsToLeftOfCursor()
562 {
563  while (m_edit->cursorPosition() != 0)
564  {
565  const QChar charToTheLeftOfCursor = m_edit->text()[m_edit->cursorPosition() - 1];
566  if (!charToTheLeftOfCursor.isLetterOrNumber() && charToTheLeftOfCursor != '_')
567  {
568  break;
569  }
570 
571  m_edit->backspace();
572  }
573 }
574 
575 bool KateViEmulatedCommandBar::deleteNonWordCharsToLeftOfCursor()
576 {
577  bool deletionsMade = false;
578  while (m_edit->cursorPosition() != 0)
579  {
580  const QChar charToTheLeftOfCursor = m_edit->text()[m_edit->cursorPosition() - 1];
581  if (charToTheLeftOfCursor.isLetterOrNumber() || charToTheLeftOfCursor == '_' || charToTheLeftOfCursor == ' ')
582  {
583  break;
584  }
585 
586  m_edit->backspace();
587  deletionsMade = true;
588  }
589  return deletionsMade;
590 }
591 
592 QString KateViEmulatedCommandBar::wordBeforeCursor()
593 {
594  int wordBeforeCursorBegin = m_edit->cursorPosition() - 1;
595  while (wordBeforeCursorBegin >= 0 && (m_edit->text()[wordBeforeCursorBegin].isLetterOrNumber() || m_edit->text()[wordBeforeCursorBegin] == '_'))
596  {
597  wordBeforeCursorBegin--;
598  }
599  wordBeforeCursorBegin++;
600  return m_edit->text().mid(wordBeforeCursorBegin, m_edit->cursorPosition() - wordBeforeCursorBegin);
601 }
602 
603 QString KateViEmulatedCommandBar::commandBeforeCursor()
604 {
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] == '-'))
609  {
610  commandBeforeCursorBegin--;
611  }
612  commandBeforeCursorBegin++;
613  return textWithoutRangeExpression.mid(commandBeforeCursorBegin, cursorPositionWithoutRangeExpression - commandBeforeCursorBegin);
614 
615 }
616 
617 void KateViEmulatedCommandBar::replaceWordBeforeCursorWith(const QString& newWord)
618 {
619  const int wordBeforeCursorStart = m_edit->cursorPosition() - wordBeforeCursor().length();
620  const QString newText = m_edit->text().left(m_edit->cursorPosition() - wordBeforeCursor().length()) +
621  newWord +
622  m_edit->text().mid(m_edit->cursorPosition());
623  m_edit->setText(newText);
624  m_edit->setCursorPosition(wordBeforeCursorStart + newWord.length());
625 }
626 
627 void KateViEmulatedCommandBar::replaceCommandBeforeCursorWith(const QString& newCommand)
628 {
629  const QString newText = m_edit->text().left(m_edit->cursorPosition() - commandBeforeCursor().length()) +
630  newCommand +
631  m_edit->text().mid(m_edit->cursorPosition());
632  m_edit->setText(newText);
633 }
634 
635 
636 void KateViEmulatedCommandBar::activateSearchHistoryCompletion()
637 {
638  m_currentCompletionType = SearchHistory;
639  m_completionModel->setStringList(reversed(KateGlobal::self()->viInputModeGlobal()->searchHistory()));
640  updateCompletionPrefix();
641  m_completer->complete();
642 }
643 
644 void KateViEmulatedCommandBar::activateWordFromDocumentCompletion()
645 {
646  m_currentCompletionType = WordFromDocument;
647  QRegExp wordRegEx("\\w{1,}");
648  QStringList foundWords;
649  // Narrow the range of lines we search around the cursor so that we don't die on huge files.
650  const int startLine = qMax(0, m_view->cursorPosition().line() - 4096);
651  const int endLine = qMin(m_view->document()->lines(), m_view->cursorPosition().line() + 4096);
652  for (int lineNum = startLine; lineNum < endLine; lineNum++)
653  {
654  const QString line = m_view->document()->line(lineNum);
655  int wordSearchBeginPos = 0;
656  while (wordRegEx.indexIn(line, wordSearchBeginPos) != -1)
657  {
658  const QString foundWord = wordRegEx.cap(0);
659  foundWords << foundWord;
660  wordSearchBeginPos = wordRegEx.indexIn(line, wordSearchBeginPos) + wordRegEx.matchedLength();
661  }
662  }
663  foundWords = QSet<QString>::fromList(foundWords).toList();
664  qSort(foundWords.begin(), foundWords.end(), caseInsensitiveLessThan);
665  m_completionModel->setStringList(foundWords);
666  updateCompletionPrefix();
667  m_completer->complete();
668 }
669 
670 void KateViEmulatedCommandBar::activateCommandCompletion()
671 {
672  m_completionModel->setStringList(KateCmd::self()->commandCompletionObject()->items());
673  m_currentCompletionType = Commands;
674 }
675 
676 void KateViEmulatedCommandBar::activateCommandHistoryCompletion()
677 {
678  m_currentCompletionType = CommandHistory;
679  m_completionModel->setStringList(reversed(KateGlobal::self()->viInputModeGlobal()->commandHistory()));
680  updateCompletionPrefix();
681  m_completer->complete();
682 }
683 
684 void KateViEmulatedCommandBar::activateSedFindHistoryCompletion()
685 {
686  if (!KateGlobal::self()->viInputModeGlobal()->searchHistory().isEmpty())
687  {
688  m_currentCompletionType = SedFindHistory;
689  m_completionModel->setStringList(reversed(KateGlobal::self()->viInputModeGlobal()->searchHistory()));
690  m_completer->setCompletionPrefix(sedFindTerm());
691  m_completer->complete();
692  }
693 }
694 
695 void KateViEmulatedCommandBar::activateSedReplaceHistoryCompletion()
696 {
697  if (!KateGlobal::self()->viInputModeGlobal()->replaceHistory().isEmpty())
698  {
699  m_currentCompletionType = SedReplaceHistory;
700  m_completionModel->setStringList(reversed(KateGlobal::self()->viInputModeGlobal()->replaceHistory()));
701  m_completer->setCompletionPrefix(sedReplaceTerm());
702  m_completer->complete();
703  }
704 }
705 
706 void KateViEmulatedCommandBar::deactivateCompletion()
707 {
708  kDebug(13070) << "Manually dismissing completions";
709  m_completer->popup()->hide();
710  m_currentCompletionType = None;
711 }
712 
713 void KateViEmulatedCommandBar::abortCompletionAndResetToPreCompletion()
714 {
715  deactivateCompletion();
716  m_isNextTextChangeDueToCompletionChange = true;
717  m_edit->setText(m_textToRevertToIfCompletionAborted);
718  m_edit->setCursorPosition(m_cursorPosToRevertToIfCompletionAborted);
719  m_isNextTextChangeDueToCompletionChange = false;
720 }
721 
722 void KateViEmulatedCommandBar::updateCompletionPrefix()
723 {
724  // TODO - switch on type is not very OO - consider making a polymorphic "completion" class.
725  if (m_currentCompletionType == WordFromDocument)
726  {
727  m_completer->setCompletionPrefix(wordBeforeCursor());
728  }
729  else if (m_currentCompletionType == SearchHistory)
730  {
731  m_completer->setCompletionPrefix(m_edit->text());
732  }
733  else if (m_currentCompletionType == CommandHistory)
734  {
735  m_completer->setCompletionPrefix(m_edit->text());
736  }
737  else if (m_currentCompletionType == Commands)
738  {
739  m_completer->setCompletionPrefix(commandBeforeCursor());
740  }
741  else
742  {
743  Q_ASSERT(false && "Unhandled completion type");
744  }
745  // Seem to need a call to complete() else the size of the popup box is not altered appropriately.
746  m_completer->complete();
747 }
748 
749 void KateViEmulatedCommandBar::currentCompletionChanged()
750 {
751  // TODO - switch on type is not very OO - consider making a polymorphic "completion" class.
752  const QString newCompletion = m_completer->currentCompletion();
753  if (newCompletion.isEmpty())
754  {
755  return;
756  }
757  m_isNextTextChangeDueToCompletionChange = true;
758  if (m_currentCompletionType == WordFromDocument)
759  {
760  replaceWordBeforeCursorWith(newCompletion);
761  }
762  else if (m_currentCompletionType == SearchHistory)
763  {
764  m_edit->setText(newCompletion);
765  }
766  else if (m_currentCompletionType == CommandHistory)
767  {
768  m_edit->setText(newCompletion);
769  }
770  else if (m_currentCompletionType == Commands)
771  {
772  const int newCursorPosition = m_edit->cursorPosition() + (newCompletion.length() - commandBeforeCursor().length());
773  replaceCommandBeforeCursorWith(newCompletion);
774  m_edit->setCursorPosition(newCursorPosition);
775  }
776  else if (m_currentCompletionType == SedFindHistory)
777  {
778  m_edit->setText(withSedFindTermReplacedWith(withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(newCompletion))));
779  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
780  m_edit->setCursorPosition(parsedSedExpression.findEndPos + 1);
781  }
782  else if (m_currentCompletionType == SedReplaceHistory)
783  {
784  m_edit->setText(withSedReplaceTermReplacedWith(withSedDelimiterEscaped(newCompletion)));
785  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
786  m_edit->setCursorPosition(parsedSedExpression.replaceEndPos + 1);
787  }
788  else
789  {
790  Q_ASSERT(false && "Something went wrong, here - completion with unrecognised completion type");
791  }
792  m_isNextTextChangeDueToCompletionChange = false;
793 }
794 
795 void KateViEmulatedCommandBar::setCompletionIndex(int index)
796 {
797  const QModelIndex modelIndex = m_completer->popup()->model()->index(index, 0);
798  // Need to set both of these, for some reason.
799  m_completer->popup()->setCurrentIndex(modelIndex);
800  m_completer->setCurrentRow(index);
801 
802  m_completer->popup()->scrollTo(modelIndex);
803 
804  currentCompletionChanged();
805 }
806 
807 KateViEmulatedCommandBar::ParsedSedExpression KateViEmulatedCommandBar::parseAsSedExpression()
808 {
809  const QString commandWithoutRangeExpression = withoutRangeExpression();
810  ParsedSedExpression parsedSedExpression;
811  QString delimiter;
812  parsedSedExpression.parsedSuccessfully = KateCommands::SedReplace::parse(commandWithoutRangeExpression, delimiter, parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos, parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos);
813  if (parsedSedExpression.parsedSuccessfully)
814  {
815  parsedSedExpression.delimiter = delimiter.at(0);
816  if (parsedSedExpression.replaceBeginPos == -1)
817  {
818  if (parsedSedExpression.findBeginPos != -1)
819  {
820  // The replace term was empty, and a quirk of the regex used is that replaceBeginPos will be -1.
821  // It's actually the position after the first occurrence of the delimiter after the end of the find pos.
822  parsedSedExpression.replaceBeginPos = commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.findEndPos) + 1;
823  parsedSedExpression.replaceEndPos = parsedSedExpression.replaceBeginPos - 1;
824  }
825  else
826  {
827  // Both find and replace terms are empty; replace term is at the third occurrence of the delimiter.
828  parsedSedExpression.replaceBeginPos = 0;
829  for (int delimiterCount = 1; delimiterCount <= 3; delimiterCount++)
830  {
831  parsedSedExpression.replaceBeginPos = commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.replaceBeginPos + 1);
832  }
833  parsedSedExpression.replaceEndPos = parsedSedExpression.replaceBeginPos - 1;
834  }
835  }
836  if (parsedSedExpression.findBeginPos == -1)
837  {
838  // The find term was empty, and a quirk of the regex used is that findBeginPos will be -1.
839  // It's actually the position after the first occurrence of the delimiter.
840  parsedSedExpression.findBeginPos = commandWithoutRangeExpression.indexOf(delimiter) + 1;
841  parsedSedExpression.findEndPos = parsedSedExpression.findBeginPos - 1;
842  }
843 
844  }
845 
846  if (parsedSedExpression.parsedSuccessfully)
847  {
848  parsedSedExpression.findBeginPos += rangeExpression().length();
849  parsedSedExpression.findEndPos += rangeExpression().length();
850  parsedSedExpression.replaceBeginPos += rangeExpression().length();
851  parsedSedExpression.replaceEndPos += rangeExpression().length();
852  }
853  return parsedSedExpression;
854 }
855 
856 QString KateViEmulatedCommandBar::withSedFindTermReplacedWith(const QString& newFindTerm)
857 {
858  const QString command = m_edit->text();
859  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
860  Q_ASSERT(parsedSedExpression.parsedSuccessfully);
861  return command.mid(0, parsedSedExpression.findBeginPos) +
862  newFindTerm +
863  command.mid(parsedSedExpression.findEndPos + 1);
864 
865 }
866 
867 QString KateViEmulatedCommandBar::withSedReplaceTermReplacedWith(const QString& newReplaceTerm)
868 {
869  const QString command = m_edit->text();
870  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
871  Q_ASSERT(parsedSedExpression.parsedSuccessfully);
872  return command.mid(0, parsedSedExpression.replaceBeginPos) +
873  newReplaceTerm +
874  command.mid(parsedSedExpression.replaceEndPos + 1);
875 }
876 
877 QString KateViEmulatedCommandBar::sedFindTerm()
878 {
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);
883 }
884 
885 QString KateViEmulatedCommandBar::sedReplaceTerm()
886 {
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);
891 }
892 
893 QString KateViEmulatedCommandBar::withSedDelimiterEscaped(const QString& text)
894 {
895  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
896  QString delimiterEscaped = ensuredCharEscaped(text, parsedSedExpression.delimiter);
897  return delimiterEscaped;
898 }
899 
900 bool KateViEmulatedCommandBar::isCursorInFindTermOfSed()
901 {
902  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
903  return parsedSedExpression.parsedSuccessfully && (m_edit->cursorPosition() >= parsedSedExpression.findBeginPos && m_edit->cursorPosition() <= parsedSedExpression.findEndPos + 1);
904 }
905 
906 bool KateViEmulatedCommandBar::isCursorInReplaceTermOfSed()
907 {
908  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
909  return parsedSedExpression.parsedSuccessfully && m_edit->cursorPosition() >= parsedSedExpression.replaceBeginPos && m_edit->cursorPosition() <= parsedSedExpression.replaceEndPos + 1;
910 }
911 
912 QString KateViEmulatedCommandBar::withoutRangeExpression()
913 {
914  const QString originalCommand = m_edit->text();
915  return originalCommand.mid(rangeExpression().length());
916 }
917 
918 QString KateViEmulatedCommandBar::rangeExpression()
919 {
920  QString rangeExpression;
921  QString unused;
922  const QString command = m_edit->text();
923  CommandRangeExpressionParser::parseRangeExpression(command, m_view, rangeExpression, unused);
924  return rangeExpression;
925 }
926 
927 bool KateViEmulatedCommandBar::handleKeyPress(const QKeyEvent* keyEvent)
928 {
929  if (keyEvent->modifiers() == Qt::ControlModifier && (keyEvent->key() == Qt::Key_C || keyEvent->key() == Qt::Key_BracketLeft) && !m_waitingForRegister)
930  {
931  if (m_currentCompletionType == None || !m_completer->popup()->isVisible())
932  {
933  emit hideMe();
934  }
935  else
936  {
937  abortCompletionAndResetToPreCompletion();
938  }
939  return true;
940  }
941  if (m_interactiveSedReplaceActive)
942  {
943  // TODO - it would be better to use e.g. keyEvent->key() == Qt::Key_Y instead of keyEvent->text() == "y",
944  // but this would require some slightly dicey changes to the "feed key press" code in order to make it work
945  // with mappings and macros.
946  if (keyEvent->text() == "y" || keyEvent->text() == "n")
947  {
948  const Cursor cursorPosIfFinalMatch = m_interactiveSedReplacer->currentMatch().start();
949  if (keyEvent->text() == "y")
950  {
951  m_interactiveSedReplacer->replaceCurrentMatch();
952  }
953  else
954  {
955  m_interactiveSedReplacer->skipCurrentMatch();
956  }
957  updateMatchHighlight(m_interactiveSedReplacer->currentMatch());
958  updateInteractiveSedReplaceLabelText();
959  moveCursorTo(m_interactiveSedReplacer->currentMatch().start());
960 
961  if (!m_interactiveSedReplacer->currentMatch().isValid())
962  {
963  moveCursorTo(cursorPosIfFinalMatch);
964  finishInteractiveSedReplace();
965  }
966  return true;
967  }
968  else if (keyEvent->text() == "l")
969  {
970  m_interactiveSedReplacer->replaceCurrentMatch();
971  finishInteractiveSedReplace();
972  return true;
973  }
974  else if (keyEvent->text() == "q")
975  {
976  finishInteractiveSedReplace();
977  return true;
978  }
979  else if (keyEvent->text() == "a")
980  {
981  m_interactiveSedReplacer->replaceAllRemaining();
982  finishInteractiveSedReplace();
983  return true;
984  }
985  return false;
986  }
987  if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_Space)
988  {
989  activateWordFromDocumentCompletion();
990  return true;
991  }
992  if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_P)
993  {
994  if (!m_completer->popup()->isVisible())
995  {
996  if (m_mode == Command)
997  {
998  if (isCursorInFindTermOfSed())
999  {
1000  activateSedFindHistoryCompletion();
1001  }
1002  else if (isCursorInReplaceTermOfSed())
1003  {
1004  activateSedReplaceHistoryCompletion();
1005  }
1006  else
1007  {
1008  activateCommandHistoryCompletion();
1009  }
1010  }
1011  else
1012  {
1013  activateSearchHistoryCompletion();
1014  }
1015  if (m_currentCompletionType != None)
1016  {
1017  setCompletionIndex(0);
1018  }
1019  }
1020  else
1021  {
1022  // Descend to next row, wrapping around if necessary.
1023  if (m_completer->currentRow() + 1 == m_completer->completionCount())
1024  {
1025  setCompletionIndex(0);
1026  }
1027  else
1028  {
1029  setCompletionIndex(m_completer->currentRow() + 1);
1030  }
1031  }
1032  return true;
1033  }
1034  if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_N)
1035  {
1036  if (!m_completer->popup()->isVisible())
1037  {
1038  if (m_mode == Command)
1039  {
1040  activateCommandHistoryCompletion();
1041  }
1042  else
1043  {
1044  activateSearchHistoryCompletion();
1045  }
1046  setCompletionIndex(m_completer->completionCount() - 1);
1047  }
1048  else
1049  {
1050  // Ascend to previous row, wrapping around if necessary.
1051  if (m_completer->currentRow() == 0)
1052  {
1053  setCompletionIndex(m_completer->completionCount() - 1);
1054  }
1055  else
1056  {
1057  setCompletionIndex(m_completer->currentRow() - 1);
1058  }
1059  }
1060  return true;
1061  }
1062  if (m_waitingForRegister)
1063  {
1064  if (keyEvent->key() != Qt::Key_Shift && keyEvent->key() != Qt::Key_Control)
1065  {
1066  const QChar key = KateViKeyParser::self()->KeyEventToQChar(*keyEvent).toLower();
1067 
1068  const int oldCursorPosition = m_edit->cursorPosition();
1069  QString textToInsert;
1070  if (keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_W)
1071  {
1072  textToInsert = m_view->doc()->getWord(m_view->cursorPosition());
1073  }
1074  else
1075  {
1076  textToInsert = KateGlobal::self()->viInputModeGlobal()->getRegisterContent( key );
1077  }
1078  if (m_insertedTextShouldBeEscapedForSearchingAsLiteral)
1079  {
1080  textToInsert = escapedForSearchingAsLiteral(textToInsert);
1081  m_insertedTextShouldBeEscapedForSearchingAsLiteral = false;
1082  }
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);
1087  }
1088  }
1089  else if ((keyEvent->modifiers() == Qt::ControlModifier && keyEvent->key() == Qt::Key_H) || keyEvent->key() == Qt::Key_Backspace)
1090  {
1091  if (m_edit->text().isEmpty())
1092  {
1093  emit hideMe();
1094  }
1095  m_edit->backspace();
1096  return true;
1097  }
1098  else if (keyEvent->modifiers() == Qt::ControlModifier)
1099  {
1100  if (keyEvent->key() == Qt::Key_B)
1101  {
1102  m_edit->setCursorPosition(0);
1103  return true;
1104  }
1105  else if (keyEvent->key() == Qt::Key_W)
1106  {
1107  deleteSpacesToLeftOfCursor();
1108  if(!deleteNonWordCharsToLeftOfCursor())
1109  {
1110  deleteWordCharsToLeftOfCursor();
1111  }
1112  return true;
1113  }
1114  else if (keyEvent->key() == Qt::Key_R || keyEvent->key() == Qt::Key_G)
1115  {
1116  m_waitingForRegister = true;
1117  m_waitingForRegisterIndicator->setVisible(true);
1118  if (keyEvent->key() == Qt::Key_G)
1119  {
1120  m_insertedTextShouldBeEscapedForSearchingAsLiteral = true;
1121  }
1122  return true;
1123  }
1124  else if (keyEvent->key() == Qt::Key_D || keyEvent->key() == Qt::Key_F)
1125  {
1126  if (m_mode == Command)
1127  {
1128  ParsedSedExpression parsedSedExpression = parseAsSedExpression();
1129  if (parsedSedExpression.parsedSuccessfully)
1130  {
1131  const bool clearFindTerm = (keyEvent->key() == Qt::Key_D);
1132  if (clearFindTerm)
1133  {
1134  m_edit->setSelection(parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + 1);
1135  m_edit->insert("");
1136  }
1137  else
1138  {
1139  // Clear replace term.
1140  m_edit->setSelection(parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos - parsedSedExpression.replaceBeginPos + 1);
1141  m_edit->insert("");
1142  }
1143  }
1144  }
1145  return true;
1146  }
1147  return false;
1148  }
1149  else if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
1150  {
1151  if (m_completer->popup()->isVisible() && m_currentCompletionType == KateViEmulatedCommandBar::WordFromDocument)
1152  {
1153  deactivateCompletion();
1154  }
1155  else
1156  {
1157  m_wasAborted = false;
1158  deactivateCompletion();
1159  if (m_mode == Command)
1160  {
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)
1166  {
1167  const QString originalFindTerm = sedFindTerm();
1168  const QString convertedFindTerm = vimRegexToQtRegexPattern(originalFindTerm);
1169  const QString commandWithSedSearchRegexConverted = withSedFindTermReplacedWith(convertedFindTerm);
1170  KateGlobal::self()->viInputModeGlobal()->appendSearchHistoryItem(originalFindTerm);
1171  const QString replaceTerm = sedReplaceTerm();
1172  KateGlobal::self()->viInputModeGlobal()->appendReplaceHistoryItem(replaceTerm);
1173  commandToExecute = commandWithSedSearchRegexConverted;
1174  kDebug(13070) << "Command to execute after replacing search term: "<< commandToExecute;
1175  }
1176 
1177  const QString commandResponseMessage = executeCommand(commandToExecute);
1178  if (!m_interactiveSedReplaceActive)
1179  {
1180  if (commandResponseMessage.isEmpty() && !m_interactiveSedReplaceActive)
1181  {
1182  emit hideMe();
1183  }
1184  else
1185  {
1186  switchToCommandResponseDisplay(commandResponseMessage);
1187  }
1188  }
1189  KateGlobal::self()->viInputModeGlobal()->appendCommandHistoryItem(m_edit->text());
1190  }
1191  else
1192  {
1193  emit hideMe();
1194  }
1195  }
1196  return true;
1197  }
1198  else
1199  {
1200  m_suspendEditEventFiltering = true;
1201  // Send the keypress back to the QLineEdit. Ideally, instead of doing this, we would simply return "false"
1202  // and let Qt re-dispatch the event itself; however, there is a corner case in that if the selection
1203  // changes (as a result of e.g. incremental searches during Visual Mode), and the keypress that causes it
1204  // is not dispatched from within KateViInputModeHandler::handleKeypress(...)
1205  // (so KateViInputModeManager::isHandlingKeypress() returns false), we lose information about whether we are
1206  // in Visual Mode, Visual Line Mode, etc. See KateViVisualMode::updateSelection( ).
1207  QKeyEvent keyEventCopy(keyEvent->type(), keyEvent->key(), keyEvent->modifiers(), keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count());
1208  if (!m_interactiveSedReplaceActive)
1209  {
1210  qApp->notify(m_edit, &keyEventCopy);
1211  }
1212  m_suspendEditEventFiltering = false;
1213  }
1214  return true;
1215 }
1216 
1217 bool KateViEmulatedCommandBar::isSendingSyntheticSearchCompletedKeypress()
1218 {
1219  return m_isSendingSyntheticSearchCompletedKeypress;
1220 }
1221 
1222 void KateViEmulatedCommandBar::startInteractiveSearchAndReplace(QSharedPointer< KateCommands::SedReplace::InteractiveSedReplacer > interactiveSedReplace)
1223 {
1224  m_interactiveSedReplaceActive = true;
1225  m_interactiveSedReplacer = interactiveSedReplace;
1226  if (!interactiveSedReplace->currentMatch().isValid())
1227  {
1228  // Bit of a hack, but we leave m_incrementalSearchAndReplaceActive true, here, else
1229  // the bar would be immediately hidden and the "0 replacements made" message not shown.
1230  finishInteractiveSedReplace();
1231  return;
1232  }
1233  kDebug(13070) << "Starting incremental search and replace";
1234  m_commandResponseMessageDisplay->hide();
1235  m_edit->hide();
1236  m_barTypeIndicator->hide();
1237  m_interactiveSedReplaceLabel->show();
1238  updateMatchHighlight(interactiveSedReplace->currentMatch());
1239  updateInteractiveSedReplaceLabelText();
1240  moveCursorTo(interactiveSedReplace->currentMatch().start());
1241 }
1242 
1243 void KateViEmulatedCommandBar::showBarTypeIndicator(KateViEmulatedCommandBar::Mode mode)
1244 {
1245  QChar barTypeIndicator = QChar::Null;
1246  switch(mode)
1247  {
1248  case SearchForward:
1249  barTypeIndicator = '/';
1250  break;
1251  case SearchBackward:
1252  barTypeIndicator = '?';
1253  break;
1254  case Command:
1255  barTypeIndicator = ':';
1256  break;
1257  default:
1258  Q_ASSERT(false && "Unknown mode!");
1259  }
1260  m_barTypeIndicator->setText(barTypeIndicator);
1261  m_barTypeIndicator->show();
1262 }
1263 
1264 QString KateViEmulatedCommandBar::executeCommand(const QString& commandToExecute)
1265 {
1266  // TODO - this is a hack-ish way of finding the response from the command; maybe
1267  // add another overload of "execute" to KateCommandLineBar that returns the
1268  // response message ... ?
1269  m_view->cmdLineBar()->setText("");
1270  m_view->cmdLineBar()->execute(commandToExecute);
1271  KateCmdLineEdit *kateCommandLineEdit = m_view->cmdLineBar()->findChild<KateCmdLineEdit*>();
1272  Q_ASSERT(kateCommandLineEdit);
1273  const QString commandResponseMessage = kateCommandLineEdit->text();
1274  return commandResponseMessage;
1275 }
1276 
1277 void KateViEmulatedCommandBar::switchToCommandResponseDisplay(const QString& commandResponseMessage)
1278 {
1279  // Display the message for a while. Become inactive, so we don't steal keys in the meantime.
1280  m_isActive = false;
1281  m_edit->hide();
1282  m_interactiveSedReplaceLabel->hide();
1283  m_barTypeIndicator->hide();
1284  m_commandResponseMessageDisplay->show();
1285  m_commandResponseMessageDisplay->setText(commandResponseMessage);
1286  m_commandResponseMessageDisplayHide->start(m_commandResponseMessageTimeOutMS);
1287 }
1288 
1289 void KateViEmulatedCommandBar::updateInteractiveSedReplaceLabelText()
1290 {
1291  m_interactiveSedReplaceLabel->setText(m_interactiveSedReplacer->currentMatchReplacementConfirmationMessage() + " (y/n/a/q/l)");
1292 }
1293 
1294 void KateViEmulatedCommandBar::finishInteractiveSedReplace()
1295 {
1296  switchToCommandResponseDisplay(m_interactiveSedReplacer->finalStatusReportMessage());
1297  m_interactiveSedReplacer.clear();
1298 }
1299 
1300 void KateViEmulatedCommandBar::moveCursorTo(const Cursor& cursorPos)
1301 {
1302  m_view->setCursorPosition(cursorPos);
1303  if (m_view->getCurrentViMode() == VisualMode || m_view->getCurrentViMode() == VisualLineMode)
1304  {
1305  m_view->getViInputModeManager()->getViVisualMode()->goToPos(cursorPos);
1306  }
1307 }
1308 
1309 void KateViEmulatedCommandBar::editTextChanged(const QString& newText)
1310 {
1311  Q_ASSERT(!m_interactiveSedReplaceActive);
1312  qDebug() << "New text: " << newText;
1313  if (!m_isNextTextChangeDueToCompletionChange)
1314  {
1315  m_textToRevertToIfCompletionAborted = newText;
1316  m_cursorPosToRevertToIfCompletionAborted = m_edit->cursorPosition();
1317  }
1318  if (m_mode == SearchForward || m_mode == SearchBackward)
1319  {
1320  QString qtRegexPattern = newText;
1321  const bool searchBackwards = (m_mode == SearchBackward);
1322  const bool placeCursorAtEndOfMatch = shouldPlaceCursorAtEndOfMatch(qtRegexPattern, searchBackwards);
1323  if (isRepeatLastSearch(qtRegexPattern, searchBackwards))
1324  {
1325  qtRegexPattern = m_view->getViInputModeManager()->getLastSearchPattern();
1326  }
1327  else
1328  {
1329  qtRegexPattern = withSearchConfigRemoved(qtRegexPattern, searchBackwards);
1330  qtRegexPattern = vimRegexToQtRegexPattern(qtRegexPattern);
1331  }
1332 
1333  // Decide case-sensitivity via SmartCase (note: if the expression contains \C, the "case-sensitive" marker, then
1334  // we will be case-sensitive "by coincidence", as it were.).
1335  bool caseSensitive = true;
1336  if (qtRegexPattern.toLower() == qtRegexPattern)
1337  {
1338  caseSensitive = false;
1339  }
1340 
1341  qtRegexPattern = withCaseSensitivityMarkersStripped(qtRegexPattern);
1342 
1343  qDebug() << "Final regex: " << qtRegexPattern;
1344 
1345  m_currentSearchPattern = qtRegexPattern;
1346  m_currentSearchIsCaseSensitive = caseSensitive;
1347  m_currentSearchIsBackwards = searchBackwards;
1348  m_currentSearchPlacesCursorAtEndOfMatch = placeCursorAtEndOfMatch;
1349 
1350  // The "count" for the current search is not shared between Visual & Normal mode, so we need to pick
1351  // the right one to handle the counted search.
1352  Range match = m_view->getViInputModeManager()->getCurrentViModeHandler()->findPattern(qtRegexPattern, searchBackwards, caseSensitive, m_startingCursorPos);
1353 
1354  if (match.isValid())
1355  {
1356  // The returned range ends one past the last character of the match, so adjust.
1357  Cursor realMatchEnd = Cursor(match.end().line(), match.end().column() - 1);
1358  if (realMatchEnd.column() == -1)
1359  {
1360  realMatchEnd = Cursor(realMatchEnd.line() - 1, m_view->doc()->lineLength(realMatchEnd.line() - 1));
1361  }
1362  moveCursorTo(placeCursorAtEndOfMatch ? realMatchEnd : match.start());
1363  setBarBackground(MatchFound);
1364  }
1365  else
1366  {
1367  moveCursorTo(m_startingCursorPos);
1368  if (!m_edit->text().isEmpty())
1369  {
1370  setBarBackground(NoMatchFound);
1371  }
1372  else
1373  {
1374  setBarBackground(Normal);
1375  }
1376  }
1377 
1378  updateMatchHighlight(match);
1379  }
1380 
1381  // Command completion doesn't need to be manually invoked.
1382  if (m_mode == Command && m_currentCompletionType == None && !withoutRangeExpression().isEmpty())
1383  {
1384  activateCommandCompletion();
1385  }
1386 
1387  // Command completion mode should be automatically invoked if we are in Command mode, but
1388  // only if this is the leading word in the text edit (it gets annoying if completion pops up
1389  // after ":s/se" etc).
1390  const bool commandBeforeCursorIsLeading = (m_edit->cursorPosition() - commandBeforeCursor().length() == rangeExpression().length());
1391  if (m_mode == Command && !commandBeforeCursorIsLeading && m_currentCompletionType == Commands && !m_isNextTextChangeDueToCompletionChange)
1392  {
1393  deactivateCompletion();
1394  }
1395 
1396  // If we edit the text after having selected a completion, this means we implicitly accept it,
1397  // and so we should dismiss it.
1398  if (!m_isNextTextChangeDueToCompletionChange && m_completer->popup()->currentIndex().row() != -1)
1399  {
1400  deactivateCompletion();
1401  }
1402 
1403  if (m_currentCompletionType != None && !m_isNextTextChangeDueToCompletionChange)
1404  {
1405  updateCompletionPrefix();
1406  }
1407 }
1408 
1409 void KateViEmulatedCommandBar::startHideCommandResponseTimer()
1410 {
1411  if (m_commandResponseMessageDisplay->isVisible() && !m_commandResponseMessageDisplayHide->isActive())
1412  {
1413  m_commandResponseMessageDisplayHide->start(m_commandResponseMessageTimeOutMS);
1414  }
1415 }
1416 
QWidget::layout
QLayout * layout() const
katevinormalmode.h
QModelIndex
KateViEmulatedCommandBar::startInteractiveSearchAndReplace
void startInteractiveSearchAndReplace(QSharedPointer< KateCommands::SedReplace::InteractiveSedReplacer > interactiveSedReplace)
Definition: kateviemulatedcommandbar.cpp:1222
QCompleter::setCaseSensitivity
void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QEvent
QWidget
QKeyEvent::modifiers
Qt::KeyboardModifiers modifiers() const
kateview.h
kateviemulatedcommandbar.h
QEvent::type
Type type() const
QWidget::palette
palette
KateViEmulatedCommandBar::isActive
bool isActive()
Definition: kateviemulatedcommandbar.cpp:434
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
KateView::clearSelection
bool clearSelection()
Definition: kateview.cpp:1991
KateDocument::newMovingRange
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.
Definition: katedocument.cpp:4741
QAbstractItemView::setCurrentIndex
void setCurrentIndex(const QModelIndex &index)
KateView::renderer
KateRenderer * renderer()
Definition: kateview.cpp:1664
KateView::document
KTextEditor::Document * document() const
Definition: kateview.cpp:2824
QCompleter::setCompletionPrefix
void setCompletionPrefix(const QString &prefix)
katevivisualmode.h
QLineEdit::setText
void setText(const QString &)
QCoreApplication::hasPendingEvents
bool hasPendingEvents()
KateViEmulatedCommandBar::Mode
Mode
Definition: kateviemulatedcommandbar.h:44
QChar
QKeyEvent::count
int count() const
KateDocument::lineLength
virtual int lineLength(int line) const
Definition: katedocument.cpp:758
KateCommandLineBar::setText
void setText(const QString &text, bool selected=true)
Definition: kateviewhelpers.cpp:839
QCompleter::setWidget
void setWidget(QWidget *widget)
katevicommandrangeexpressionparser.h
KateCmd::self
static KateCmd * self()
Definition: katecmd.cpp:112
VisualMode
Definition: kateviinputmodemanager.h:51
KateViInputModeManager::setLastSearchBackwards
void setLastSearchBackwards(bool b)
set search direction of last search.
Definition: kateviinputmodemanager.h:229
QCompleter::setModel
void setModel(QAbstractItemModel *model)
QCompleter::currentCompletion
QString currentCompletion() const
KateViEmulatedCommandBar::closed
virtual void closed()
Definition: kateviemulatedcommandbar.cpp:444
QWidget::setVisible
virtual void setVisible(bool visible)
QSharedPointer::clear
void clear()
KateViEmulatedCommandBar::Command
Definition: kateviemulatedcommandbar.h:44
QHBoxLayout
QLabel::setAlignment
void setAlignment(QFlags< Qt::AlignmentFlag >)
KateGlobal::self
static KateGlobal * self()
Kate Part Internal stuff ;)
Definition: kateglobal.cpp:465
QKeyEvent::isAutoRepeat
bool isAutoRepeat() const
KateViEmulatedCommandBar::isSendingSyntheticSearchCompletedKeypress
bool isSendingSyntheticSearchCompletedKeypress()
Definition: kateviemulatedcommandbar.cpp:1217
QString::remove
QString & remove(int position, int n)
KateViKeyParser::KeyEventToQChar
const QChar KeyEventToQChar(const QKeyEvent &keyEvent)
Definition: katevikeyparser.cpp:674
KateView::setCursorPosition
bool setCursorPosition(KTextEditor::Cursor position)
Definition: kateview.cpp:2418
KateView::getViInputModeManager
KateViInputModeManager * getViInputModeManager()
Definition: kateview.cpp:1587
CommandRangeExpressionParser::parseRangeExpression
static KTextEditor::Range parseRangeExpression(const QString &command, KateView *view, QString &destRangeExpression, QString &destTransformedCommand)
Attempt to parse any leading range expression (e.g.
Definition: katevicommandrangeexpressionparser.cpp:68
QAbstractItemView::scrollTo
virtual void scrollTo(const QModelIndex &index, ScrollHint hint)=0
KateViVisualMode::goToPos
void goToPos(const Cursor &c)
Definition: katevivisualmode.cpp:229
KateViewBarWidget
Definition: kateviewhelpers.h:294
QRegExp
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
KateViewBarWidget::centralWidget
QWidget * centralWidget()
Definition: kateviewhelpers.h:311
KateViInputModeManager::getLastSearchPattern
const QString getLastSearchPattern() const
The current search pattern.
Definition: kateviinputmodemanager.cpp:422
QCoreApplication::processEvents
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
QList::append
void append(const T &value)
QWidget::setLayout
void setLayout(QLayout *layout)
QObject::installEventFilter
void installEventFilter(QObject *filterObj)
QTimer
KateRenderer::config
KateRendererConfig * config() const
Configuration.
Definition: katerenderer.h:362
QSharedPointer< KateCommands::SedReplace::InteractiveSedReplacer >
KateViEmulatedCommandBar::setCommandResponseMessageTimeout
void setCommandResponseMessageTimeout(long commandResponseMessageTimeOutMS)
Definition: kateviemulatedcommandbar.cpp:439
QCompleter::complete
void complete(const QRect &rect)
KateViEmulatedCommandBar::SearchBackward
Definition: kateviemulatedcommandbar.h:44
QObject
QWidget::setFocus
void setFocus()
kateglobal.h
QList::isEmpty
bool isEmpty() const
QObject::setObjectName
void setObjectName(const QString &name)
QString::isEmpty
bool isEmpty() const
QModelIndex::row
int row() const
QCoreApplication::sendEvent
bool sendEvent(QObject *receiver, QEvent *event)
KateViewBarWidget::hideMe
void hideMe()
QKeyEvent::text
QString text() const
KateView::cmdLineBar
KateCommandLineBar * cmdLineBar()
Definition: kateview.cpp:3013
KateViInputModeManager::setLastSearchPlacesCursorAtEndOfMatch
void setLastSearchPlacesCursorAtEndOfMatch(bool b)
Definition: kateviinputmodemanager.h:233
KateViInputModeManager::getCurrentViModeHandler
KateViModeBase * getCurrentViModeHandler() const
Definition: kateviinputmodemanager.cpp:466
KateViEmulatedCommandBar::init
void init(Mode mode, const QString &initialText=QString())
Definition: kateviemulatedcommandbar.cpp:401
KateViModeBase::findPattern
Range findPattern(const QString &pattern, bool backwards, bool caseSensitive, const Cursor &startFrom, int count=-1) const
Definition: katevimodebase.cpp:183
katecmd.h
QLabel::setText
void setText(const QString &)
QString
QList< int >
QWidget::hide
void hide()
QColor
QLineEdit::backspace
void backspace()
QStringListModel
QStringList
KateView
Definition: kateview.h:77
QList::end
iterator end()
QString::toLower
QString toLower() const
QKeyEvent::key
int key() const
QLineEdit::insert
void insert(const QString &newText)
QTimer::stop
void stop()
QChar::toLower
QChar toLower() const
katevikeyparser.h
VisualLineMode
Definition: kateviinputmodemanager.h:52
KateView::cursorPosition
KTextEditor::Cursor cursorPosition() const
Definition: kateview.cpp:2423
QString::replace
QString & replace(int position, int n, QChar after)
QKeyEvent
KateGlobal::viInputModeGlobal
KateViGlobal * viInputModeGlobal()
vi input mode global
Definition: kateglobal.h:339
KateViEmulatedCommandBar::handleKeyPress
bool handleKeyPress(const QKeyEvent *keyEvent)
Definition: kateviemulatedcommandbar.cpp:927
KateViInputModeManager::handleKeypress
bool handleKeypress(const QKeyEvent *e)
feed key the given key press to the command parser
Definition: kateviinputmodemanager.cpp:113
QString::mid
QString mid(int position, int n) const
KateDocument::getWord
QString getWord(const KTextEditor::Cursor &cursor)
Definition: katedocument.cpp:3538
KateView::getCurrentViMode
ViMode getCurrentViMode() const
Definition: kateview.cpp:1582
KateViEmulatedCommandBar::KateViEmulatedCommandBar
KateViEmulatedCommandBar(KateView *view, QWidget *parent=0)
Definition: kateviemulatedcommandbar.cpp:318
KateCmdLineEdit
Definition: kateviewhelpers.h:432
QString::at
const QChar at(int position) const
QList::last
T & last()
KateViEmulatedCommandBar::SearchForward
Definition: kateviemulatedcommandbar.h:44
QSet::fromList
QSet< T > fromList(const QList< T > &list)
KateRendererConfig::searchHighlightColor
const QColor & searchHighlightColor() const
Definition: kateconfig.cpp:2687
KateViInputModeManager::setLastSearchPattern
void setLastSearchPattern(const QString &p)
Set the current search pattern.
Definition: kateviinputmodemanager.cpp:434
QString::length
int length() const
None
Definition: kateviinsertmode.h:39
KateViGlobal::appendReplaceHistoryItem
void appendReplaceHistoryItem(const QString &replaceHistoryItem)
Definition: kateviglobal.cpp:282
KateViGlobal::appendCommandHistoryItem
void appendCommandHistoryItem(const QString &commandHistoryItem)
Definition: kateviglobal.cpp:272
QString::left
QString left(int n) const
QTimer::start
void start(int msec)
KateView::doc
KateDocument * doc()
accessor to katedocument pointer
Definition: kateview.h:553
QWidget::show
void show()
QLineEdit
KateViInputModeManager::getViVisualMode
KateViVisualMode * getViVisualMode()
Definition: kateviinputmodemanager.cpp:556
QCompleter::currentRow
int currentRow() const
QCompleter
QAbstractItemView::model
QAbstractItemModel * model() const
QLineEdit::cursorPosition
cursorPosition
QAbstractItemView::currentIndex
QModelIndex currentIndex() const
KateViGlobal::appendSearchHistoryItem
void appendSearchHistoryItem(const QString &searchHistoryItem)
Definition: kateviglobal.cpp:257
QTimer::isActive
bool isActive() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QLabel
KateViKeyParser::self
static KateViKeyParser * self()
Definition: katevikeyparser.cpp:38
kateviglobal.h
kateconfig.h
KateViGlobal::getRegisterContent
QString getRegisterContent(const QChar &reg) const
Definition: kateviglobal.cpp:121
KateViEmulatedCommandBar::~KateViEmulatedCommandBar
virtual ~KateViEmulatedCommandBar()
Definition: kateviemulatedcommandbar.cpp:396
katecmds.h
QStringListModel::setStringList
void setStringList(const QStringList &strings)
QList::begin
iterator begin()
QCompleter::popup
QAbstractItemView * popup() const
KateCommandLineBar::execute
void execute(const QString &text)
Definition: kateviewhelpers.cpp:847
QPalette
KateCommands::SedReplace::parse
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.
Definition: katecmds.cpp:999
QCompleter::setCurrentRow
bool setCurrentRow(int row)
QChar::isLetterOrNumber
bool isLetterOrNumber() const
KateViInputModeManager::setLastSearchCaseSensitive
void setLastSearchCaseSensitive(bool caseSensitive)
Definition: kateviinputmodemanager.h:231
QCompleter::completionCount
int completionCount() const
QLineEdit::setSelection
void setSelection(int start, int length)
QTimer::setSingleShot
void setSingleShot(bool singleShot)
QObject::findChild
T findChild(const QString &name) const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:58 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal