void UndoManagerTest::testSelectionUndo() { TestDocument doc; KateView *view = static_cast<KateView*>(doc.createView(0)); doc.setText("aaaa bbbb cccc\n" "dddd eeee ffff"); view->setCursorPosition(KTextEditor::Cursor(1, 9)); KTextEditor::Range selectionRange(KTextEditor::Cursor(0, 5), KTextEditor::Cursor(1, 9)); view->setSelection(selectionRange); doc.typeChars(view, "eeee"); // cursor position: "aaaa eeee| ffff", no selection anymore QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(0, 9)); QCOMPARE(view->selection(), false); // undo to remove "eeee" and add selection and text again doc.undo(); QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(1, 9)); QCOMPARE(view->selection(), true); QCOMPARE(view->selectionRange(), selectionRange); // redo to insert "eeee" again and remove selection // cursor position: "aaaa eeee| ffff", no selection anymore doc.redo(); QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(0, 9)); QCOMPARE(view->selection(), false); delete view; }
// // when text is folded, and you set the text selection from top to bottom and // type a character, the resulting text is borked. // // See https://bugs.kde.org/show_bug.cgi?id=295632 // void KateFoldedSelectionTest::foldedSelectionTest() { KateDocument doc(false, false, false); QString text = "oooossssssss\n" "{\n" "\n" "}\n" "ssssss----------"; doc.setText(text); doc.setHighlightingMode("C++"); doc.buffer().ensureHighlighted (doc.lines()); // view must be visible... KateView* view = static_cast<KateView*>(doc.createView(0)); view->show(); view->resize(400, 300); QTest::qWait(500); doc.foldingTree()->collapseOne(1, 1); QTest::qWait(500); view->setSelection(Range(Cursor(0,4), Cursor(4, 6))); view->setCursorPosition(Cursor(4, 6)); QTest::qWait(500); doc.typeChars(view, "x"); QTest::qWait(500); QString line = doc.line(0); QCOMPARE(line, QString("oooox----------")); }
void KateFoldingTest::testFolding_py_lang() { KTemporaryFile file; file.setSuffix(".py"); file.open(); QTextStream stream(&file); stream << "if customerName == x\n" << " print x\n" << "elif customerName == y\n" << " print y\n" << "else print z\n"; stream << flush; file.close(); KateDocument doc(false, false, false); QVERIFY(doc.openUrl(KUrl(file.fileName()))); KateView* view = new KateView(&doc, 0); // is set to allow kate's hl to be called view->config()->setDynWordWrap(true); QCOMPARE(doc.visibleLines(), 6u); QAction* action = view->action("folding_toplevel"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 4u); action = view->action("folding_expandtoplevel"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 6u); }
void KateFoldingTest::testFolding_collapse_dsComments_XML() { KTemporaryFile file; file.setSuffix(".xml"); file.open(); QTextStream stream(&file); stream << "<test1>\n" << "</test1>\n" << "<!--\n" << "<test2>\n" << "</test2>\n" << "-->\n" << "<!--\n" << "-->\n"; stream << flush; file.close(); KateDocument doc(false, false, false); QVERIFY(doc.openUrl(KUrl(file.fileName()))); KateView* view = new KateView(&doc, 0); // is set to allow kate's hl to be called view->config()->setDynWordWrap(true); QCOMPARE(doc.visibleLines(), 9u); QAction* action = view->action("folding_collapse_dsComment"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 5u); }
bool TinyKate::checkSave() { if (currentView==0) return true; KateView *kv = (KateView*) currentView; if(kv->isModified()) { KateDocument *kd = (KateDocument*) kv->document(); switch( QMessageBox::information( 0, (tr("TinyKATE")), (tr("Do you want to save\n" "changes to the document\n" "%1?\n").arg(kd->docName())), (tr("Save")), (tr("Don't Save")), (tr("&Cancel")), 2, 2 ) ) { case 0: { return saveDocument(); } break; case 1: { return true; } break; default: { return false; } break; }; } else { return true; } }
// This test makes sure that, // - if you have selected text // - that spans a folded range, // - and the cursor is at the end of the text selection, // - and you type a char, e.g. 'x', // then the resulting text is correct, and changing region // visibility does not mess around with the text cursor. // // See https://bugs.kde.org/show_bug.cgi?id=295632 void KateFoldingTest::testBug295632() { KateDocument doc(false, false, false); QString text = "oooossssssss\n" "{\n" "\n" "}\n" "ssssss----------"; doc.setText(text); // view must be visible... KateView* view = static_cast<KateView*>(doc.createView(0)); view->show(); view->resize(400, 300); qint64 foldId = view->textFolding().newFoldingRange (KTextEditor::Range(1, 0, 3, 1)); view->textFolding().foldRange(foldId); QVERIFY(view->textFolding().isLineVisible(0)); QVERIFY(view->textFolding().isLineVisible(1)); QVERIFY(!view->textFolding().isLineVisible(2)); QVERIFY(!view->textFolding().isLineVisible(3)); QVERIFY(view->textFolding().isLineVisible(4)); view->setSelection(Range(Cursor(0,4), Cursor(4, 6))); view->setCursorPosition(Cursor(4, 6)); QTest::qWait(100); doc.typeChars(view, "x"); QTest::qWait(100); QString line = doc.line(0); QCOMPARE(line, QString("oooox----------")); }
bool KateWordCompletionModel::shouldAbortCompletion(KTextEditor::View* view, const KTextEditor::Range &range, const QString ¤tCompletion) { if (m_automatic) { KateView *v = qobject_cast<KateView*> (view); if (currentCompletion.length()<v->config()->wordCompletionMinimalWordLength()) return true; } return CodeCompletionModelControllerInterface4::shouldAbortCompletion(view,range,currentCompletion); }
void BugTest::tryCrash() { KateDocument doc(false, false, false); QString url = KDESRCDIR + QString("folding-crash.py"); doc.openUrl(url); doc.discardDataRecovery(); doc.setHighlightingMode("Python"); doc.buffer().ensureHighlighted (doc.lines()); // view must be visible... KateView* view = static_cast<KateView*>(doc.createView(0)); view->show(); view->resize(400, 300); // fold all doc.foldingTree()->collapseToplevelNodes(); QTest::qWait(1000); view->down(); view->down(); view->end(); view->cursorRight(); view->down(); view->down(); view->end(); QTest::qWait(1000); qDebug() << "!!! The next line usually crashes in the code folding code"; view->backspace(); doc.buffer().ensureHighlighted (doc.lines()); QTest::qWait(1000); }
KCompletion *KateCommands::CoreCommands::completionObject( const QString &cmd, Kate::View *view ) { if ( cmd == "set-highlight" ) { KateView *v = (KateView*)view; QStringList l; for ( uint i = 0; i < v->doc()->hlModeCount(); i++ ) l << v->doc()->hlModeName( i ); KateCmdShellCompletion *co = new KateCmdShellCompletion(); co->setItems( l ); co->setIgnoreCase( true ); return co; } return 0L; }
void SearchCommand::processText( Kate::View *view, const TQString &cmd ) { static TQRegExp re_ifind("ifind(?::([bcrs]*))?\\s(.*)"); if ( re_ifind.search( cmd ) > -1 ) { TQString flags = re_ifind.cap( 1 ); TQString pattern = re_ifind.cap( 2 ); // if there is no setup, or the text length is 0, set up the properties if ( ! m_ifindFlags || pattern.isEmpty() ) ifindInit( flags ); // if there is no fromCursor, add it if this is not the first character else if ( ! ( m_ifindFlags & KFindDialog::FromCursor ) && ! pattern.isEmpty() ) m_ifindFlags |= KFindDialog::FromCursor; // search.. if ( ! pattern.isEmpty() ) { KateView *v = (KateView*)view; // If it *looks like* we are continuing, place the cursor // at the beginning of the selection, so that the search continues. // ### check more carefully, like is the cursor currently at the end // of the selection. if ( pattern.startsWith( v->selection() ) && v->selection().length() + 1 == pattern.length() ) v->setCursorPositionInternal( v->selStartLine(), v->selStartCol() ); v->find( pattern, m_ifindFlags, false ); } } }
void KateFoldingTest::testFolding() { QFETCH(QString, text); QFETCH(QString, fileExt); QFETCH(QString, firstActionName); QFETCH(QString, secondActionName); QFETCH(unsigned int, initValue); QFETCH(unsigned int, firstResult); QFETCH(unsigned int, secondResult); KTemporaryFile file; file.setSuffix("." + fileExt); file.open(); QTextStream stream(&file); stream << text; stream << flush; file.close(); KateDocument doc(false, false, false); QVERIFY(doc.openUrl(KUrl(file.fileName()))); KateView* view = new KateView(&doc, 0); QAction* firstAction = view->action(qPrintable(firstActionName)); QVERIFY(firstAction); QAction* secondAction = view->action(qPrintable(secondActionName)); QVERIFY(secondAction); // is set to allow kate's hl to be called view->config()->setDynWordWrap(true); QCOMPARE(doc.visibleLines(), initValue); firstAction->trigger(); QCOMPARE(doc.visibleLines(), firstResult); secondAction->trigger(); QCOMPARE(doc.visibleLines(), secondResult); }
void KateFoldingTest::testFolding_collapse_expand_local() { KTemporaryFile file; file.setSuffix(".c"); file.open(); QTextStream stream(&file); stream << "if () {\n" << " if () {\n" << " if () {\n" << " if () {\n" << " }\n" << " }\n" << " }\n" << " if () {\n" << " foo()\n" << " }\n" << " }\n"; stream << flush; file.close(); KateDocument doc(false, false, false); QVERIFY(doc.openUrl(KUrl(file.fileName()))); KateView* view = new KateView(&doc, 0); // is set to allow kate's hl to be called view->config()->setDynWordWrap(true); QCOMPARE(doc.visibleLines(), 12u); view->setCursorPosition(KTextEditor::Cursor(2,12)); QAction* action = view->action("folding_collapselocal"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 9u); view->setCursorPosition(KTextEditor::Cursor(2,11)); action = view->action("folding_collapselocal"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 7u); view->setCursorPosition(KTextEditor::Cursor(1,9)); action = view->action("folding_expandlocal"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 9u); }
void KateFoldingTest::testFoldingReload() { KTemporaryFile file; file.setSuffix(".cpp"); file.open(); QTextStream stream(&file); stream << "int main() {\n" << " asdf;\n" << "}\n"; stream << flush; file.close(); KateDocument doc(false, false, false); QVERIFY(doc.openUrl(KUrl(file.fileName()))); KateView* view = new KateView(&doc, 0); // is set to allow kate's hl to be called view->config()->setDynWordWrap(true); QCOMPARE(doc.visibleLines(), 4u); QAction* action = view->action("folding_toplevel"); QVERIFY(action); action->trigger(); doc.foldingTree()->saveFoldingState(); QList<int> hiddenLines(doc.foldingTree()->m_hiddenLines); QList<int> hiddenColumns(doc.foldingTree()->m_hiddenColumns); QCOMPARE(doc.visibleLines(), 2u); action = view->action("file_reload"); QVERIFY(action); action->trigger(); QCOMPARE(doc.visibleLines(), 2u); QCOMPARE(hiddenLines,doc.foldingTree()->m_hiddenLines); QCOMPARE(hiddenColumns,doc.foldingTree()->m_hiddenColumns); }
bool KateWordCompletionModel::shouldStartCompletion(KTextEditor::View* view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) { if (!userInsertion) return false; if(insertedText.isEmpty()) return false; KateView *v = qobject_cast<KateView*> (view); QString text = view->document()->line(position.line()).left(position.column()); uint check=v->config()->wordCompletionMinimalWordLength(); if (check<=0) return true; int start=text.length(); int end=text.length()-check; if (end<0) return false; for (int i=start-1;i>=end;i--) { QChar c=text.at(i); if (! (c.isLetter() || (c.isNumber()) || c=='_') ) return false; } return true; }
void KateWordCompletionModel::completionInvoked(KTextEditor::View* view, const KTextEditor::Range& range, InvocationType it) { /** * auto invoke... */ m_automatic=false; if (it==AutomaticInvocation) { m_automatic=true; KateView *v = qobject_cast<KateView*> (view); if (range.columnWidth() >= v->config()->wordCompletionMinimalWordLength()) saveMatches( view, range ); else m_matches.clear(); // done here... return; } // normal case ;) saveMatches( view, range ); }
void UndoManagerTest::testCursorPosition() { TestDocument doc; KateView *view = static_cast<KateView*>(doc.createView(0)); doc.setText("aaaa bbbb cccc\n" "dddd ffff"); view->setCursorPosition(KTextEditor::Cursor(1, 5)); doc.typeChars(view, "eeee"); // cursor position: "dddd eeee| ffff" QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(1, 9)); // undo once to remove "eeee", cursor position: "dddd | ffff" doc.undo(); QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(1, 5)); // redo once to insert "eeee" again. cursor position: "dddd eeee| ffff" doc.redo(); QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(1, 9)); delete view; }
// tests: // - RangeFeedback::mouseEnteredRange // - RangeFeedback::mouseExitedRange void MovingRangeTest::testFeedbackMouse() { KateDocument doc (false, false, false); // the range created below will span the 'x' characters QString text("..xxxx\n" "xxxx.."); doc.setText(text); KateView* view = static_cast<KateView*>(doc.createView(0)); view->setCursorPosition(Cursor(1, 6)); view->show(); view->resize(200, 100); // create range feedback RangeFeedback rf; QVERIFY(!rf.mouseEnteredRangeCalled()); QVERIFY(!rf.mouseExitedRangeCalled()); // allow empty MovingRange* range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)), KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight, KTextEditor::MovingRange::InvalidateIfEmpty); range->setFeedback(&rf); rf.verifyReset(); // left (nothing) QTest::mouseMove(view, view->cursorToCoordinate(Cursor(0, 0)) + QPoint(0, 5)); QTest::qWait(200); // process mouse events. do not move mouse manually QVERIFY(!rf.mouseEnteredRangeCalled()); QVERIFY(!rf.mouseExitedRangeCalled()); // middle (enter) rf.reset(); QTest::mouseMove(view, view->cursorToCoordinate(Cursor(0, 3)) + QPoint(0, 5)); QTest::qWait(200); // process mouse events. do not move mouse manually QVERIFY(rf.mouseEnteredRangeCalled()); QVERIFY(!rf.mouseExitedRangeCalled()); // right (exit) rf.reset(); QTest::mouseMove(view, view->cursorToCoordinate(Cursor(1, 6)) + QPoint(10, 5)); QTest::qWait(200); // process mouse events. do not move mouse manually QVERIFY(!rf.mouseEnteredRangeCalled()); QVERIFY(rf.mouseExitedRangeCalled()); }
// This is a unit test for bug 311866 (http://bugs.kde.org/show_bug.cgi?id=311866) // It loads 5 lines of C++ code, places the cursor in line 4, and then folds // the code. // Expected behavior: the cursor should be moved so it stays visible // Buggy behavior: the cursor is hidden, and moving the hidden cursor crashes kate void KateFoldingTest::testCrash311866() { KateDocument doc(false, false, false); QString url = KDESRCDIR + QString("data/bug311866.cpp"); doc.openUrl(url); doc.setHighlightingMode("C++"); doc.buffer().ensureHighlighted (6); KateView* view = static_cast<KateView*>(doc.createView(0)); view->show(); view->resize(400, 300); view->setCursorPosition(Cursor(3, 0)); QTest::qWait(100); view->slotFoldToplevelNodes(); doc.buffer().ensureHighlighted (6); qDebug() << "!!! Does the next line crash?"; view->up(); }
bool KateCommands::CoreCommands::exec(Kate::View *view, const QString &_cmd, QString &errorMsg) { #define KCC_ERR(s) { errorMsg=s; return false; } // cast it hardcore, we know that it is really a kateview :) KateView *v = (KateView*) view; if ( ! v ) KCC_ERR( i18n("Could not access view") ); //create a list of args QStringList args( QStringList::split( QRegExp("\\s+"), _cmd ) ); QString cmd ( args.first() ); args.remove( args.first() ); // ALL commands that takes no arguments. if ( cmd == "indent" ) { v->indent(); return true; } else if ( cmd == "run-myself" ) { #ifndef Q_WS_WIN //todo return KateFactory::self()->jscript()->execute(v, v->doc()->text(), errorMsg); #else return 0; #endif } else if ( cmd == "unindent" ) { v->unIndent(); return true; } else if ( cmd == "cleanindent" ) { v->cleanIndent(); return true; } else if ( cmd == "comment" ) { v->comment(); return true; } else if ( cmd == "uncomment" ) { v->uncomment(); return true; } else if ( cmd == "kill-line" ) { v->killLine(); return true; } else if ( cmd == "set-indent-mode" ) { bool ok(false); int val ( args.first().toInt( &ok ) ); if ( ok ) { if ( val < 0 ) KCC_ERR( i18n("Mode must be at least 0.") ); v->doc()->config()->setIndentationMode( val ); } else v->doc()->config()->setIndentationMode( KateAutoIndent::modeNumber( args.first() ) ); return true; } else if ( cmd == "set-highlight" ) { QString val = _cmd.section( ' ', 1 ).lower(); for ( uint i=0; i < v->doc()->hlModeCount(); i++ ) { if ( v->doc()->hlModeName( i ).lower() == val ) { v->doc()->setHlMode( i ); return true; } } KCC_ERR( i18n("No such highlight '%1'").arg( args.first() ) ); } // ALL commands that takes exactly one integer argument. else if ( cmd == "set-tab-width" || cmd == "set-indent-width" || cmd == "set-word-wrap-column" || cmd == "goto" ) { // find a integer value > 0 if ( ! args.count() ) KCC_ERR( i18n("Missing argument. Usage: %1 <value>").arg( cmd ) ); bool ok; int val ( args.first().toInt( &ok ) ); if ( !ok ) KCC_ERR( i18n("Failed to convert argument '%1' to integer.") .arg( args.first() ) ); if ( cmd == "set-tab-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->setTabWidth( val ); } else if ( cmd == "set-indent-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->doc()->config()->setIndentationWidth( val ); } else if ( cmd == "set-word-wrap-column" ) { if ( val < 2 ) KCC_ERR( i18n("Column must be at least 1.") ); v->doc()->setWordWrapAt( val ); } else if ( cmd == "goto" ) { if ( val < 1 ) KCC_ERR( i18n("Line must be at least 1") ); if ( (uint)val > v->doc()->numLines() ) KCC_ERR( i18n("There is not that many lines in this document") ); v->gotoLineNumber( val - 1 ); } return true; } // ALL commands that takes 1 boolean argument. else if ( cmd == "set-icon-border" || cmd == "set-folding-markers" || cmd == "set-line-numbers" || cmd == "set-replace-tabs" || cmd == "set-remove-trailing-space" || cmd == "set-show-tabs" || cmd == "set-indent-spaces" || cmd == "set-mixed-indent" || cmd == "set-word-wrap" || cmd == "set-wrap-cursor" || cmd == "set-replace-tabs-save" || cmd == "set-remove-trailing-space-save" || cmd == "set-show-indent" ) { if ( ! args.count() ) KCC_ERR( i18n("Usage: %1 on|off|1|0|true|false").arg( cmd ) ); bool enable; if ( getBoolArg( args.first(), &enable ) ) { if ( cmd == "set-icon-border" ) v->setIconBorder( enable ); else if (cmd == "set-folding-markers") v->setFoldingMarkersOn( enable ); else if ( cmd == "set-line-numbers" ) v->setLineNumbersOn( enable ); else if ( cmd == "set-show-indent" ) v->renderer()->setShowIndentLines( enable ); else if ( cmd == "set-replace-tabs" ) setDocFlag( KateDocumentConfig::cfReplaceTabsDyn, enable, v->doc() ); else if ( cmd == "set-remove-trailing-space" ) setDocFlag( KateDocumentConfig::cfRemoveTrailingDyn, enable, v->doc() ); else if ( cmd == "set-show-tabs" ) setDocFlag( KateDocumentConfig::cfShowTabs, enable, v->doc() ); else if ( cmd == "set-indent-spaces" ) setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() ); else if ( cmd == "set-mixed-indent" ) { // this is special, in that everything is set up -- space-indent is enabled, // and a indent-width is set if it is 0 (to tabwidth/2) setDocFlag( KateDocumentConfig::cfMixedIndent, enable, v->doc() ); if ( enable ) { setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() ); if ( ! v->doc()->config()->indentationWidth() ) v->doc()->config()->setIndentationWidth( v->tabWidth()/2 ); } } else if ( cmd == "set-word-wrap" ) v->doc()->setWordWrap( enable ); else if ( cmd == "set-remove-trailing-space-save" ) setDocFlag( KateDocumentConfig::cfRemoveSpaces, enable, v->doc() ); else if ( cmd == "set-wrap-cursor" ) setDocFlag( KateDocumentConfig::cfWrapCursor, enable, v->doc() ); return true; } else KCC_ERR( i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false") .arg( args.first() ).arg( cmd ) ); } // unlikely.. KCC_ERR( i18n("Unknown command '%1'").arg(cmd) ); }
// tests: // - RangeFeedback::caretEnteredRange // - RangeFeedback::caretExitedRange void MovingRangeTest::testFeedbackCaret() { KateDocument doc (false, false, false); // the range created below will span the 'x' characters QString text("..xxxx\n" "xxxx.."); doc.setText(text); KateView* view = static_cast<KateView*>(doc.createView(0)); // create range feedback RangeFeedback rf; // first test: with ExpandLeft | ExpandRight { view->setCursorPosition(Cursor(1, 6)); MovingRange* range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)), KTextEditor::MovingRange::ExpandLeft | KTextEditor::MovingRange::ExpandRight, KTextEditor::MovingRange::InvalidateIfEmpty); rf.reset(); range->setFeedback(&rf); rf.verifyReset(); // left view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 5)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 4)); QVERIFY(rf.caretEnteredRangeCalled()); // ExpandRight: include cursor already now QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 3)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->up(); QCOMPARE(view->cursorPosition(), Cursor(0, 3)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(0, 2)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(0, 1)); // ExpandLeft: now we left it, not before QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(rf.caretExitedRangeCalled()); delete range; } // second test: with DoNotExpand { view->setCursorPosition(Cursor(1, 6)); MovingRange* range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)), KTextEditor::MovingRange::DoNotExpand, KTextEditor::MovingRange::InvalidateIfEmpty); rf.reset(); range->setFeedback(&rf); rf.verifyReset(); // left view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 5)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 4)); QVERIFY(!rf.caretEnteredRangeCalled()); // DoNotExpand: does not include cursor QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(1, 3)); QVERIFY(rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->up(); QCOMPARE(view->cursorPosition(), Cursor(0, 3)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(0, 2)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(rf.caretExitedRangeCalled()); // DoNotExpand: that's why we leave already now rf.reset(); view->cursorLeft(); QCOMPARE(view->cursorPosition(), Cursor(0, 1)); QVERIFY(!rf.caretEnteredRangeCalled()); QVERIFY(!rf.caretExitedRangeCalled()); delete range; } }
bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg, const KTextEditor::Range& range) { #define KCC_ERR(s) { errorMsg=s; return false; } // cast it hardcore, we know that it is really a kateview :) KateView *v = static_cast<KateView*>(view); if ( ! v ) KCC_ERR( i18n("Could not access view") ); //create a list of args QStringList args(_cmd.split( QRegExp("\\s+"), QString::SkipEmptyParts)) ; QString cmd ( args.takeFirst() ); // ALL commands that takes no arguments. if ( cmd == "indent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), 1 ); } v->doc()->editEnd(); } else { v->indent(); } return true; } else if ( cmd == "unindent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), -1 ); } v->doc()->editEnd(); } else { v->unIndent(); } return true; } else if ( cmd == "cleanindent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), 0 ); } v->doc()->editEnd(); } else { v->cleanIndent(); } return true; } else if ( cmd == "comment" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->comment( v, line, 0, 1 ); } v->doc()->editEnd(); } else { v->comment(); } return true; } else if ( cmd == "uncomment" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->comment( v, line, 0, -1 ); } v->doc()->editEnd(); } else { v->uncomment(); } return true; } else if ( cmd == "kill-line" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->removeLine( range.start().line() ); } v->doc()->editEnd(); } else { v->killLine(); } return true; } else if ( cmd == "print" ) { v->doc()->printDialog(); return true; } // ALL commands that take a string argument else if ( cmd == "set-indent-mode" || cmd == "set-highlight" || cmd == "set-mode" ) { // need at least one item, otherwise args.first() crashes if ( ! args.count() ) KCC_ERR( i18n("Missing argument. Usage: %1 <value>", cmd ) ); if ( cmd == "set-indent-mode" ) { v->doc()->config()->setIndentationMode( args.join(" ") ); v->doc()->rememberUserDidSetIndentationMode (); return true; } else if ( cmd == "set-highlight" ) { if ( v->doc()->setHighlightingMode( args.first()) ) { static_cast<KateDocument*>(v->doc())->setDontChangeHlOnSave (); return true; } KCC_ERR( i18n("No such highlighting '%1'", args.first() ) ); } else if ( cmd == "set-mode" ) { if ( v->doc()->setMode( args.first()) ) return true; KCC_ERR( i18n("No such mode '%1'", args.first() ) ); } } // ALL commands that takes exactly one integer argument. else if ( cmd == "set-tab-width" || cmd == "set-indent-width" || cmd == "set-word-wrap-column" || cmd == "goto" ) { // find a integer value > 0 if ( ! args.count() ) KCC_ERR( i18n("Missing argument. Usage: %1 <value>", cmd ) ); bool ok; int val ( args.first().toInt( &ok, 10 ) ); // use base 10 even if the string starts with '0' if ( !ok ) KCC_ERR( i18n("Failed to convert argument '%1' to integer.", args.first() ) ); if ( cmd == "set-tab-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->doc()->config()->setTabWidth( val ); } else if ( cmd == "set-indent-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->doc()->config()->setIndentationWidth( val ); } else if ( cmd == "set-word-wrap-column" ) { if ( val < 2 ) KCC_ERR( i18n("Column must be at least 1.") ); v->doc()->setWordWrapAt( val ); } else if ( cmd == "goto" ) { if ( args.first().at(0) == '-' || args.first().at(0) == '+' ) { // if the number starts with a minus or plus sign, add/subract the number val = v->cursorPosition().line() + val; } else { val--; // convert given line number to the internal representation of line numbers } // constrain cursor to the range [0, number of lines] if ( val < 0 ) { val = 0; } else if ( val > v->doc()->lines()-1 ) { val = v->doc()->lines()-1; } v->setCursorPosition( KTextEditor::Cursor( val, 0 ) ); return true; } return true; } // ALL commands that takes 1 boolean argument. else if ( cmd == "set-icon-border" || cmd == "set-folding-markers" || cmd == "set-line-numbers" || cmd == "set-replace-tabs" || cmd == "set-show-tabs" || cmd == "set-word-wrap" || cmd == "set-wrap-cursor" || cmd == "set-replace-tabs-save" || cmd == "set-show-indent" ) { if ( ! args.count() ) KCC_ERR( i18n("Usage: %1 on|off|1|0|true|false", cmd ) ); bool enable = false; KateDocumentConfig * const config = v->doc()->config(); if ( getBoolArg( args.first(), &enable ) ) { if ( cmd == "set-icon-border" ) v->setIconBorder( enable ); else if (cmd == "set-folding-markers") v->setFoldingMarkersOn( enable ); else if ( cmd == "set-line-numbers" ) v->setLineNumbersOn( enable ); else if ( cmd == "set-show-indent" ) v->renderer()->setShowIndentLines( enable ); else if ( cmd == "set-replace-tabs" ) config->setReplaceTabsDyn( enable ); else if ( cmd == "set-show-tabs" ) config->setShowTabs( enable ); else if ( cmd == "set-show-trailing-spaces" ) config->setShowSpaces( enable ); else if ( cmd == "set-word-wrap" ) v->doc()->setWordWrap( enable ); return true; } else KCC_ERR( i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false", args.first() , cmd ) ); } else if ( cmd == "set-remove-trailing-spaces" ) { // need at least one item, otherwise args.first() crashes if ( args.count() != 1 ) KCC_ERR( i18n("Usage: set-remove-trailing-spaces 0|-|none or 1|+|mod|modified or 2|*|all") ); QString tmp = args.first().toLower().trimmed(); if (tmp == "1" || tmp == "modified" || tmp == "mod" || tmp == "+") { v->doc()->config()->setRemoveSpaces(1); } else if (tmp == "2" || tmp == "all" || tmp == "*") { v->doc()->config()->setRemoveSpaces(2); } else { v->doc()->config()->setRemoveSpaces(0); } } // unlikely.. KCC_ERR( i18n("Unknown command '%1'", cmd) ); }