示例#1
0
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);

}
示例#2
0
// 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----------"));
}
示例#3
0
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----------"));
}
示例#5
0
// 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());
}
示例#6
0
// 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();
}
示例#7
0
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;
}
示例#8
0
// 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;
  }
}
示例#9
0
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) );
}