bool KateAutoIndent::changeIndent (const KTextEditor::Range &range, int change) { QList<int> skippedLines; // loop over all lines given... for (int line = range.start().line () < 0 ? 0 : range.start().line (); line <= qMin (range.end().line (), doc->lines()-1); ++line) { // don't indent empty lines if (doc->line(line).isEmpty()) { skippedLines.append (line); continue; } // don't indent the last line when the cursor is on the first column if (line == range.end().line() && range.end().column() == 0) { skippedLines.append (line); continue; } doIndentRelative(line, change * indentWidth); } if (skippedLines.count() > range.numberOfLines()) { // all lines were empty, so indent them nevertheless foreach (int line, skippedLines) doIndentRelative(line, change * indentWidth); }
/** Conversion function from QtScript range to KTextEditor::Range */ static QScriptValue rangeToScriptValue(QScriptEngine *engine, const KTextEditor::Range &range) { QString code = QString("new Range(%1, %2, %3, %4);").arg(range.start().line()) .arg(range.start().column()) .arg(range.end().line()) .arg(range.end().column()); return engine->evaluate(code); }
void SwapFile::removeText (const KTextEditor::Range &range) { // skip if not open if (!m_swapfile.isOpen ()) return; // format: qint8, int, int, int Q_ASSERT (range.start().line() == range.end().line()); m_stream << EA_RemoveText << range.start().line() << range.start().column() << range.end().column(); m_needSync = true; }
QString CodeRepresentation::rangeText(const KTextEditor::Range& range) const { Q_ASSERT(range.end().line() < lines()); //Easier for single line ranges which should happen most of the time if(range.onSingleLine()) return QString( line( range.start().line() ).mid( range.start().column(), range.columnWidth() ) ); //Add up al the requested lines QString rangedText = line(range.start().line()).mid(range.start().column()); for(int i = range.start().line() + 1; i <= range.end().line(); ++i) rangedText += '\n' + ((i == range.end().line()) ? line(i).left(range.end().column()) : line(i)); return rangedText; }
QRect KTextEditorHelpers::getItemBoundingRect(const KTextEditor::View* view, const KTextEditor::Range& itemRange) { QPoint startPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.start())); QPoint endPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.end())); endPoint.ry() += getLineHeight(view, itemRange.start().line()); return QRect(startPoint, endPoint); }
/** Conversion function from QtScript range to KTextEditor::Range */ static void rangeFromScriptValue(const QScriptValue &obj, KTextEditor::Range &range) { range.start().setPosition(obj.property("start").property("line").toInt32(), obj.property("start").property("column").toInt32()); range.end().setPosition(obj.property("end").property("line").toInt32(), obj.property("end").property("column").toInt32()); }
void KateViInsertMode::textInserted(KTextEditor::Document* document, KTextEditor::Range range) { if (m_isExecutingCompletion) { m_textInsertedByCompletion += document->text(range); m_textInsertedByCompletionEndPos = range.end(); } }
void FunctionDeclarationCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word) { qCDebug(KDEV_PYTHON_CODECOMPLETION) << "FunctionDeclarationCompletionItem executed"; KTextEditor::Document* document = view->document(); auto resolvedDecl = Helper::resolveAliasDeclaration(declaration().data()); DUChainReadLocker lock; auto functionDecl = Helper::functionForCalled(resolvedDecl).declaration; lock.unlock(); if ( ! functionDecl && (! resolvedDecl || ! resolvedDecl->abstractType() || resolvedDecl->abstractType()->whichType() != AbstractType::TypeStructure) ) { qCritical(KDEV_PYTHON_CODECOMPLETION) << "ERROR: could not get declaration data, not executing completion item!"; return; } QString suffix = "()"; KTextEditor::Range checkPrefix(word.start().line(), 0, word.start().line(), word.start().column()); KTextEditor::Range checkSuffix(word.end().line(), word.end().column(), word.end().line(), document->lineLength(word.end().line())); if ( m_doNotCall || document->text(checkSuffix).trimmed().startsWith('(') || document->text(checkPrefix).trimmed().endsWith('@') || (functionDecl && Helper::findDecoratorByName(functionDecl, QLatin1String("property"))) ) { // don't insert brackets if they're already there, // the item is a decorator, or if it's an import item. suffix.clear(); } // place cursor behind bracktes by default int skip = 2; if ( functionDecl ) { bool needsArguments = false; int argumentCount = functionDecl->type<FunctionType>()->arguments().length(); if ( functionDecl->context()->type() == KDevelop::DUContext::Class ) { // it's a member function, so it has the implicit self // TODO static methods needsArguments = argumentCount > 1; } else { // it's a free function needsArguments = argumentCount > 0; } if ( needsArguments ) { // place cursor in brackets if there's parameters skip = 1; } } document->replaceText(word, declaration()->identifier().toString() + suffix); view->setCursorPosition( Cursor(word.end().line(), word.end().column() + skip) ); }
void PreprocessorCompletionModel::completionInvoked( KTextEditor::View* const view , const KTextEditor::Range& word , InvocationType /*itype*/ ) { // Reuse shouldStartCompletion to disable/enable completion m_should_complete = shouldStartCompletion(view, QString{}, false, word.end()); }
void ClangCodeCompletionModel::executeCompletionItem2( KTextEditor::Document* const doc , const KTextEditor::Range& word , const QModelIndex& index ) const { assert("Active view expected to be equal to the stored one" && doc->activeView() == m_current_view); assert("Invalid index is not expected here!" && index.isValid()); assert("Parent index is not valid" && index.parent().isValid()); assert("Parent index must be GROUP" && index.parent().internalId() == Level::GROUP); assert( "Parent index points to invalid group" && 0 <= index.internalId() && unsigned(index.internalId()) < m_groups.size() ); assert( "Index points to invalid item" && 0 <= index.row() && unsigned(index.row()) < m_groups[index.internalId()].second.m_completions.size() ); auto* const template_iface = qobject_cast<KTextEditor::TemplateInterface2*>(m_current_view); if (template_iface) { kDebug(DEBUG_AREA) << "TemplateInterface available for a view" << m_current_view; const auto result = m_groups[index.internalId()] .second.m_completions[index.row()] .getCompletionTemplate(); kDebug(DEBUG_AREA) << "Template:" << result.m_tpl; kDebug(DEBUG_AREA) << "Values:" << result.m_values; // Check if current template is a function and there is a '()' right after cursor auto range = word; if (result.m_is_function) { const auto next_word_range = DocumentProxy(doc).firstWordAfterCursor(word.end()); kDebug(DEBUG_AREA) << "OK THIS IS FUNCTION TEMPLATE: next word range" << next_word_range; kDebug(DEBUG_AREA) << "replace range before:" << range; if (next_word_range.isValid() && doc->text(next_word_range).startsWith(QLatin1String("()"))) { range.end().setColumn(next_word_range.start().column() + 2); kDebug(DEBUG_AREA) << "replace range after:" << range; } } doc->removeText(range); template_iface->insertTemplateText(range.start(), result.m_tpl, result.m_values, nullptr); } else { kDebug(DEBUG_AREA) << "No TemplateInterface for a view" << m_current_view; const auto p = m_groups[index.internalId()].second.m_completions[index.row()].executeCompletion(); doc->replaceText(word, p.first); // Try to reposition a cursor inside a current (hope it still is) view auto pos = word.start(); pos.setColumn(pos.column() + p.second); m_current_view->setCursorPosition(pos); } }
void execute(KTextEditor::View* view, const KTextEditor::Range& word) override { auto document = view->document(); auto range = word; const int lineNumber = word.end().line(); const QString line = document->line(lineNumber); const auto properties = includePathProperties(line, word.end().column()); if (!properties.valid) { return; } QString newText = includeItem.isDirectory ? (includeItem.name + QLatin1Char('/')) : includeItem.name; if (properties.inputFrom == -1) { newText.prepend(QLatin1Char('<')); } else { range.setStart({lineNumber, properties.inputFrom}); } if (properties.inputTo == -1) { // Add suffix if (properties.local) { newText += QLatin1Char('"'); } else { newText += QLatin1Char('>'); } // replace the whole line range.setEnd({lineNumber, line.size()}); } else { range.setEnd({lineNumber, properties.inputTo}); } document->replaceText(range, newText); if (includeItem.isDirectory) { // ensure we can continue to add files/paths when we just added a directory int offset = (properties.inputTo == -1) ? 1 : 0; view->setCursorPosition(range.start() + KTextEditor::Cursor(0, newText.length() - offset)); } else { // place cursor at end of line view->setCursorPosition({lineNumber, document->lineLength(lineNumber)}); } }
void ImplementFunctionCompletionItem::execute(KTextEditor::Document* document, const KTextEditor::Range& word) { const QString finalText = m_name + "(" + m_arguments.join(", ") + "):"; document->replaceText(word, finalText); // 4 spaces is indentation for python. everyone does it like this. you must, too. // TODO use kate settings document->insertLine(word.start().line() + 1, m_previousIndent + " "); if ( View* view = document->activeView() ) { view->setCursorPosition(Cursor(word.end().line() + 1, m_previousIndent.length() + 4)); } }
void TextHistory::removeText(const KTextEditor::Range &range, int oldLineLength) { // create and add new entry Entry entry; entry.type = Entry::RemoveText; entry.line = range.start().line(); entry.column = range.start().column(); entry.length = range.end().column() - range.start().column(); entry.oldLineLength = oldLineLength; addEntry(entry); }
QSize GrepOutputDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { const GrepOutputModel *model = dynamic_cast<const GrepOutputModel *>(index.model()); const GrepOutputItem *item = model ? dynamic_cast<const GrepOutputItem *>(model->itemFromIndex(index)) : nullptr; QSize ret = QStyledItemDelegate::sizeHint(option, index); //take account of additional width required for highlighting (bold text) //and line numbers. These are not included in the default Qt size calculation. if(item && item->isText()) { QFont font = option.font; QFontMetrics metrics(font); font.setBold(true); QFontMetrics bMetrics(font); const KTextEditor::Range rng = item->change()->m_range; int width = metrics.width(item->text().left(rng.start().column())) + metrics.width(item->text().right(item->text().length() - rng.end().column())) + bMetrics.width(item->text().mid(rng.start().column(), rng.end().column() - rng.start().column())) + option.fontMetrics.width(i18n("Line %1: ",item->lineNumber())) + std::max(option.decorationSize.width(), 0); ret.setWidth(width); }else{ // This is only used for titles, so not very performance critical QString text; if(item) text = item->text(); else text = index.data().toString(); QTextDocument doc; doc.setDocumentMargin(0); doc.setHtml(text); QSize newSize = doc.size().toSize(); if(newSize.height() > ret.height()) ret.setHeight(newSize.height()); } return ret; }
/** * We have to stop \c #include completion when current line would parsed well * (i.e. contains complete \c #include expression) or have no \c #include at all. */ bool IncludeHelperCompletionModel::shouldAbortCompletion( KTextEditor::View* view , const KTextEditor::Range& range , const QString& current_completion ) { kDebug(DEBUG_AREA) << "range=" << range << ", current_completion=" << current_completion; kDebug(DEBUG_AREA) << "m_should_complete=" << m_should_complete << ", closer=" << m_closer; // Get current line const auto line = view->document()->line(range.end().line()); // Try to parse it... auto r = parseIncludeDirective(line, false); // nothing to complete for lines w/o #include const auto need_abort = !r.m_range.isValid() || range.end().column() < r.m_range.start().column() || range.end().column() > (r.m_range.end().column() + 1) ; kDebug(DEBUG_AREA) << "result=" << need_abort; return need_abort; }
void RangeTest::rangeCheck(KTextEditor::Range &valid) { QVERIFY(valid.isValid() && valid.start() <= valid.end()); KTextEditor::Cursor before(0, 1), start(0, 2), end(1, 4), after(1, 10); KTextEditor::Range result(start, end); QVERIFY(valid.isValid() && valid.start() <= valid.end()); valid.setRange(start, end); QVERIFY(valid.isValid() && valid.start() <= valid.end()); QCOMPARE(valid, result); valid.setRange(end, start); QVERIFY(valid.isValid() && valid.start() <= valid.end()); QCOMPARE(valid, result); valid.setStart(after); QVERIFY(valid.isValid() && valid.start() <= valid.end()); QCOMPARE(valid, KTextEditor::Range(after, after)); valid = result; QCOMPARE(valid, result); valid.setEnd(before); QVERIFY(valid.isValid() && valid.start() <= valid.end()); QCOMPARE(valid, KTextEditor::Range(before, before)); }
// Contributed by <*****@*****.**> void KateWordCompletionView::shellComplete() { KTextEditor::Range r = range(); QStringList matches = m_dWCompletionModel->allMatches( m_view, r ); if (matches.size() == 0) return; QString partial = findLongestUnique( matches, r.columnWidth() ); if ( ! partial.length() ) popupCompletionList(); else { m_view->document()->insertText( r.end(), partial.mid( r.columnWidth() ) ); d->liRange->setView(m_view); d->liRange->setRange( KTextEditor::Range( r.end(), partial.length() - r.columnWidth() ) ); connect( m_view, SIGNAL(cursorPositionChanged(KTextEditor::View*,KTextEditor::Cursor)), this, SLOT(slotCursorMoved()) ); } }
void TextBuffer::removeText (const KTextEditor::Range &range) { // only allowed if editing transaction running Q_ASSERT (m_editingTransactions > 0); // only ranges on one line are supported Q_ASSERT (range.start().line() == range.end().line()); // start colum <= end column and >= 0 Q_ASSERT (range.start().column() <= range.end().column()); Q_ASSERT (range.start().column() >= 0); // skip work, if no text to remove if (range.isEmpty()) return; // get block, this will assert on invalid line int blockIndex = blockForLine (range.start().line()); // let the block handle the removeText, retrieve removed text QString text; m_blocks.at(blockIndex)->removeText (range, text); // remember changes ++m_revision; // update changed line interval if (range.start().line() < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1) m_editingMinimalLineChanged = range.start().line(); if (range.start().line() > m_editingMaximalLineChanged) m_editingMaximalLineChanged = range.start().line(); // emit signal about done change emit textRemoved (range, text); }
TextRange::TextRange (TextBuffer &buffer, const KTextEditor::Range &range, InsertBehaviors insertBehavior, EmptyBehavior emptyBehavior) : m_buffer (buffer) , m_start (buffer, this, range.start(), (insertBehavior & ExpandLeft) ? Kate::TextCursor::StayOnInsert : Kate::TextCursor::MoveOnInsert) , m_end (buffer, this, range.end(), (insertBehavior & ExpandRight) ? Kate::TextCursor::MoveOnInsert : Kate::TextCursor::StayOnInsert) , m_view (0) , m_feedback (0) , m_zDepth (0.0) , m_attributeOnlyForViews (false) , m_invalidateIfEmpty (emptyBehavior == InvalidateIfEmpty) { // remember this range in buffer m_buffer.m_ranges.insert (this); // check if range now invalid, there can happen no feedback, as m_feedback == 0 checkValidity (); }
void TextRange::setRange (const KTextEditor::Range &range) { // avoid work if nothing changed! if (range == toRange()) return; // remember old line range int oldStartLine = m_start.line(); int oldEndLine = m_end.line(); // change start and end cursor m_start.setPosition (range.start ()); m_end.setPosition (range.end ()); // check if range now invalid, don't emit feedback here, will be handled below // otherwise you can't delete ranges in feedback! checkValidity (oldStartLine, oldEndLine, false); // no attribute or feedback set, be done if (!m_attribute && !m_feedback) return; // get full range int startLineMin = oldStartLine; if (oldStartLine == -1 || (m_start.line() != -1 && m_start.line() < oldStartLine)) startLineMin = m_start.line(); int endLineMax = oldEndLine; if (oldEndLine == -1 || m_end.line() > oldEndLine) endLineMax = m_end.line(); /** * notify buffer about attribute change, it will propagate the changes * notify right view */ m_buffer.notifyAboutRangeChange (m_view, startLineMin, endLineMax, m_attribute); // perhaps need to notify stuff! if (m_feedback) { // do this last: may delete this range if (!toRange().isValid()) m_feedback->rangeInvalid (this); else if (toRange().isEmpty()) m_feedback->rangeEmpty (this); } }
void RangeTest::testRangeStringConversion() { using KTextEditor::Cursor; using KTextEditor::Range; KTextEditor::Range r; QCOMPARE(r.start(), Cursor(0, 0)); QCOMPARE(r.end(), Cursor(0, 0)); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0,0),(0,0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (0, 0)]")); r = Range::fromString(QStringLiteral("[(-1, -1), (-1, -1)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); r = Range::fromString(QStringLiteral("[(-1, -1), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (-1, -1)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (0, 0)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(0, 0), (12, 42)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); r = Range::fromString(QStringLiteral("[(12, 42), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(12,42),(0,0)]")); QCOMPARE(r.toString(), QStringLiteral("[(0, 0), (12, 42)]")); // start > end -> swap r = Range::fromString(QStringLiteral("[(-12, -42), (0, 0)]")); QCOMPARE(r.toString(), QStringLiteral("[(-12, -42), (0, 0)]")); r = Range::fromString(QStringLiteral("[(0, 0), (-12, -42)]")); QCOMPARE(r.toString(), QStringLiteral("[(-12, -42), (0, 0)]")); // start > end -> swap // invalid input r = Range::fromString(QStringLiteral("[(0:0)(-12:-42)]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); r = Range::fromString(QStringLiteral("[0,1]")); QCOMPARE(r.toString(), QStringLiteral("[(-1, -1), (-1, -1)]")); }
void NormalDeclarationCompletionItem::execute(KTextEditor::View* view, const KTextEditor::Range& word) { if( m_completionContext && m_completionContext->depth() != 0 ) return; //Do not replace any text when it is an argument-hint KTextEditor::Document* document = view->document(); QString newText; { KDevelop::DUChainReadLocker lock(KDevelop::DUChain::lock()); if(m_declaration) { newText = declarationName(); } else { qCDebug(LANGUAGE) << "Declaration disappeared"; return; } } document->replaceText(word, newText); KTextEditor::Range newRange = word; newRange.setEnd(KTextEditor::Cursor(newRange.end().line(), newRange.start().column() + newText.length())); executed(view, newRange); }
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) ); }
void GrepOutputDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { // there is no function in QString to left-trim. A call to remove this this regexp does the job static const QRegExp leftspaces("^\\s*", Qt::CaseSensitive, QRegExp::RegExp); // rich text component const GrepOutputModel *model = dynamic_cast<const GrepOutputModel *>(index.model()); const GrepOutputItem *item = dynamic_cast<const GrepOutputItem *>(model->itemFromIndex(index)); QStyleOptionViewItem options = option; initStyleOption(&options, index); // building item representation QTextDocument doc; QTextCursor cur(&doc); QPalette::ColorGroup cg = options.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; QPalette::ColorRole cr = options.state & QStyle::State_Selected ? QPalette::HighlightedText : QPalette::Text; QTextCharFormat fmt = cur.charFormat(); fmt.setFont(options.font); if(item && item->isText()) { // Use custom manual highlighting const KTextEditor::Range rng = item->change()->m_range; // the line number appears grayed fmt.setForeground(options.palette.brush(QPalette::Disabled, cr)); cur.insertText(i18n("Line %1: ",item->lineNumber()), fmt); // switch to normal color fmt.setForeground(options.palette.brush(cg, cr)); cur.insertText(item->text().left(rng.start().column()).remove(leftspaces), fmt); fmt.setFontWeight(QFont::Bold); if ( !(options.state & QStyle::State_Selected) ) { QColor bgHighlight = option.palette.color(QPalette::AlternateBase); fmt.setBackground(bgHighlight); } cur.insertText(item->text().mid(rng.start().column(), rng.end().column() - rng.start().column()), fmt); fmt.clearBackground(); fmt.setFontWeight(QFont::Normal); cur.insertText(item->text().right(item->text().length() - rng.end().column()), fmt); }else{ QString text; if(item) text = item->text(); else text = index.data().toString(); // Simply insert the text as html. We use this for the titles. doc.setHtml(text); } painter->save(); options.text = QString(); // text will be drawn separately options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget); // set correct draw area QRect clip = options.widget->style()->subElementRect(QStyle::SE_ItemViewItemText, &options); QFontMetrics metrics(options.font); painter->translate(clip.topLeft() - QPoint(0, metrics.descent())); // We disable the clipping for now, as it leads to strange clipping errors // clip.setTopLeft(QPoint(0,0)); // painter->setClipRect(clip); QAbstractTextDocumentLayout::PaintContext ctx; // ctx.clip = clip; painter->setBackground(Qt::transparent); doc.documentLayout()->draw(painter, ctx); painter->restore(); }
// Scan throughout the entire document for possible completions, // ignoring any dublets const QStringList KateNewCompletionModel::allMatches( KTextEditor::View *view, const KTextEditor::Range &range ) const { KTextEditor::Document *doc = view->document(); QString match_str = doc->text(range); QString s, m; QSet<QString> seen; QStringList l; int i( 0 ); int pos( 0 ); QRegExp class_rek("([A-Z]\\w*<( |\\w|,|<|>)+>)"); if (match_str.startsWith("new ")) { QString class_name = match_str.mid(4); for (i = 0; i < doc->lines(); ++i) { QString s = doc->line(i); QString m; pos = 0; while (pos >= 0) { pos = class_rek.indexIn(s, pos); if ( pos >= 0 ) { // typing in the middle of a word if ( ! ( i == range.start().line() && pos >= range.start().column() && pos <= range.end().column()) ) { m = class_rek.cap( 1 ); if ( ! seen.contains( m ) && m.startsWith(class_name)) { seen.insert( m ); m = "new " + m; l << m; } } pos += class_rek.matchedLength(); } } } } // convert yieldXXX and Ent::load('XXX') to genXXX and getXXX if (match_str.startsWith("gen") || match_str.startsWith("get")) { QString x = match_str.mid(3); class_rek = QRegExp("(yield|Ent::load\\(\\\'|Ent::load\\(\\\")([A-Z]\\w*)"); for (i = 0; i < doc->lines(); ++i) { QString s = doc->line(i); QString m; pos = 0; while (pos >= 0) { pos = class_rek.indexIn(s, pos); if ( pos >= 0 ) { // typing in the middle of a word if ( ! ( i == range.start().line() && pos >= range.start().column() && pos <= range.end().column()) ) { m = class_rek.cap( 2 ); if ( ! seen.contains( m ) && m.startsWith(x)) { seen.insert( m ); l << ("gen" + m); l << ("get" + m); } } pos += class_rek.matchedLength(); } } } } return l; }
bool KatePrinter::print (KateDocument *doc) { QPrinter printer; readSettings(printer); // docname is now always there, including the right Untitled name printer.setDocName(doc->documentName()); KatePrintTextSettings *kpts = new KatePrintTextSettings; KatePrintHeaderFooter *kphf = new KatePrintHeaderFooter; KatePrintLayout *kpl = new KatePrintLayout; QList<QWidget*> tabs; tabs << kpts; tabs << kphf; tabs << kpl; QWidget *parentWidget=doc->widget(); if ( !parentWidget ) parentWidget=QApplication::activeWindow(); QScopedPointer<QPrintDialog> printDialog(KdePrint::createPrintDialog(&printer, KdePrint::SystemSelectsPages, tabs, parentWidget)); if ( doc->activeView()->selection() ) { printer.setPrintRange(QPrinter::Selection); printDialog->setOption(QAbstractPrintDialog::PrintSelection, true); } if ( printDialog->exec() ) { writeSettings(printer); KateRenderer renderer(doc, doc->activeKateView()); renderer.config()->setSchema (kpl->colorScheme()); renderer.setPrinterFriendly(true); QPainter paint( &printer ); /* * We work in tree cycles: * 1) initialize variables and retrieve print settings * 2) prepare data according to those settings * 3) draw to the printer */ uint pdmWidth = printer.width(); uint pdmHeight = printer.height(); int y = 0; uint xstart = 0; // beginning point for painting lines uint lineCount = 0; uint maxWidth = pdmWidth; int headerWidth = pdmWidth; int startCol = 0; int endCol = 0; bool pageStarted = true; int remainder = 0; // remaining sublines from a wrapped line (for the top of a new page) // Text Settings Page bool selectionOnly = (printDialog->printRange() == QAbstractPrintDialog::Selection); bool useGuide = kpts->printGuide(); bool printLineNumbers = kpts->printLineNumbers(); uint lineNumberWidth( 0 ); // Header/Footer Page QFont headerFont(kphf->font()); // used for header/footer bool useHeader = kphf->useHeader(); QColor headerBgColor(kphf->headerBackground()); QColor headerFgColor(kphf->headerForeground()); uint headerHeight( 0 ); // further init only if needed QStringList headerTagList; // do bool headerDrawBg = false; // do bool useFooter = kphf->useFooter(); QColor footerBgColor(kphf->footerBackground()); QColor footerFgColor(kphf->footerForeground()); uint footerHeight( 0 ); // further init only if needed QStringList footerTagList; // do bool footerDrawBg = false; // do // Layout Page renderer.config()->setSchema( kpl->colorScheme() ); bool useBackground = kpl->useBackground(); bool useBox = kpl->useBox(); int boxWidth(kpl->boxWidth()); QColor boxColor(kpl->boxColor()); int innerMargin = useBox ? kpl->boxMargin() : 6; // Post initialization int maxHeight = (useBox ? pdmHeight-innerMargin : pdmHeight); uint currentPage( 1 ); uint lastline = doc->lastLine(); // necessary to print selection only uint firstline( 0 ); const int fontHeight = renderer.fontHeight(); KTextEditor::Range selectionRange; /* * Now on for preparations... * during preparations, variable names starting with a "_" means * those variables are local to the enclosing block. */ { if ( selectionOnly ) { // set a line range from the first selected line to the last selectionRange = doc->activeView()->selectionRange(); firstline = selectionRange.start().line(); lastline = selectionRange.end().line(); lineCount = firstline; } if ( printLineNumbers ) { // figure out the horiizontal space required QString s( QString("%1 ").arg( doc->lines() ) ); s.fill('5', -1); // some non-fixed fonts haven't equally wide numbers // FIXME calculate which is actually the widest... lineNumberWidth = renderer.currentFontMetrics().width( s ); // a small space between the line numbers and the text int _adj = renderer.currentFontMetrics().width( "5" ); // adjust available width and set horizontal start point for data maxWidth -= (lineNumberWidth + _adj); xstart += lineNumberWidth + _adj; } if ( useHeader || useFooter ) { // Set up a tag map // This retrieves all tags, ued or not, but // none of theese operations should be expensive, // and searcing each tag in the format strings is avoided. QDateTime dt = QDateTime::currentDateTime(); QMap<QString,QString> tags; KUser u (KUser::UseRealUserID); tags["u"] = u.loginName(); tags["d"] = KGlobal::locale()->formatDateTime(dt, KLocale::ShortDate); tags["D"] = KGlobal::locale()->formatDateTime(dt, KLocale::LongDate); tags["h"] = KGlobal::locale()->formatTime(dt.time(), false); tags["y"] = KGlobal::locale()->formatDate(dt.date(), KLocale::ShortDate); tags["Y"] = KGlobal::locale()->formatDate(dt.date(), KLocale::LongDate); tags["f"] = doc->url().fileName(); tags["U"] = doc->url().prettyUrl(); if ( selectionOnly ) { QString s( i18n("(Selection of) ") ); tags["f"].prepend( s ); tags["U"].prepend( s ); } QRegExp reTags( "%([dDfUhuyY])" ); // TODO tjeck for "%%<TAG>" if (useHeader) { headerDrawBg = kphf->useHeaderBackground(); headerHeight = QFontMetrics( headerFont ).height(); if ( useBox || headerDrawBg ) headerHeight += innerMargin * 2; else headerHeight += 1 + QFontMetrics( headerFont ).leading(); headerTagList = kphf->headerFormat(); QMutableStringListIterator it(headerTagList); while ( it.hasNext() ) { QString tag = it.next(); int pos = reTags.indexIn( tag ); QString rep; while ( pos > -1 ) { rep = tags[reTags.cap( 1 )]; tag.replace( (uint)pos, 2, rep ); pos += rep.length(); pos = reTags.indexIn( tag, pos ); } it.setValue( tag ); } if (!headerBgColor.isValid()) headerBgColor = Qt::lightGray; if (!headerFgColor.isValid()) headerFgColor = Qt::black; } if (useFooter) { footerDrawBg = kphf->useFooterBackground(); footerHeight = QFontMetrics( headerFont ).height(); if ( useBox || footerDrawBg ) footerHeight += 2*innerMargin; else footerHeight += 1; // line only footerTagList = kphf->footerFormat(); QMutableStringListIterator it(footerTagList); while ( it.hasNext() ) { QString tag = it.next(); int pos = reTags.indexIn( tag ); QString rep; while ( pos > -1 ) { rep = tags[reTags.cap( 1 )]; tag.replace( (uint)pos, 2, rep ); pos += rep.length(); pos = reTags.indexIn( tag, pos ); } it.setValue( tag ); } if (!footerBgColor.isValid()) footerBgColor = Qt::lightGray; if (!footerFgColor.isValid()) footerFgColor = Qt::black; // adjust maxheight, so we can know when/where to print footer maxHeight -= footerHeight; } } // if ( useHeader || useFooter ) if ( useBackground ) { if ( ! useBox ) { xstart += innerMargin; maxWidth -= innerMargin * 2; } } if ( useBox ) { if (!boxColor.isValid()) boxColor = Qt::black; if (boxWidth < 1) // shouldn't be pssible no more! boxWidth = 1; // set maxwidth to something sensible maxWidth -= ( ( boxWidth + innerMargin ) * 2 ); xstart += boxWidth + innerMargin; // maxheight too.. maxHeight -= boxWidth; } else boxWidth = 0; // now that we know the vertical amount of space needed, // it is possible to calculate the total number of pages // if needed, that is if any header/footer tag contains "%P". if ( !headerTagList.filter("%P").isEmpty() || !footerTagList.filter("%P").isEmpty() ) { kDebug(13020)<<"'%P' found! calculating number of pages..."; int pageHeight = maxHeight; if ( useHeader ) pageHeight -= ( headerHeight + innerMargin ); if ( useFooter ) pageHeight -= innerMargin; const int linesPerPage = pageHeight / fontHeight; // kDebug() << "Lines per page:" << linesPerPage; // calculate total layouted lines in the document int totalLines = 0; // TODO: right now ignores selection printing for (int i = firstline; i <= lastline; ++i) { KateLineLayoutPtr rangeptr(new KateLineLayout(doc)); rangeptr->setLine(i); renderer.layoutLine(rangeptr, (int)maxWidth, false); totalLines += rangeptr->viewLineCount(); } int totalPages = (totalLines / linesPerPage) + ((totalLines % linesPerPage) > 0 ? 1 : 0); // kDebug() << "_______ pages:" << (totalLines / linesPerPage); // kDebug() << "________ rest:" << (totalLines % linesPerPage); // TODO: add space for guide if required // if ( useGuide ) // _lt += (guideHeight + (fontHeight /2)) / fontHeight; // substitute both tag lists QString re("%P"); QStringList::Iterator it; for ( it=headerTagList.begin(); it!=headerTagList.end(); ++it ) (*it).replace( re, QString( "%1" ).arg( totalPages ) ); for ( it=footerTagList.begin(); it!=footerTagList.end(); ++it ) (*it).replace( re, QString( "%1" ).arg( totalPages ) ); } } // end prepare block /* On to draw something :-) */ while ( lineCount <= lastline ) { startCol = 0; endCol = 0; if ( y + fontHeight > maxHeight ) { kDebug(13020)<<"Starting new page,"<<lineCount<<"lines up to now."; printer.newPage(); paint.resetTransform(); currentPage++; pageStarted = true; y=0; } if ( pageStarted ) { if ( useHeader ) { paint.setPen(headerFgColor); paint.setFont(headerFont); if ( headerDrawBg ) paint.fillRect(0, 0, headerWidth, headerHeight, headerBgColor); if (headerTagList.count() == 3) { int valign = ( (useBox||headerDrawBg||useBackground) ? Qt::AlignVCenter : Qt::AlignTop ); int align = valign|Qt::AlignLeft; int marg = ( useBox || headerDrawBg ) ? innerMargin : 0; if ( useBox ) marg += boxWidth; QString s; for (int i=0; i<3; i++) { s = headerTagList[i]; if (s.indexOf("%p") != -1) s.replace("%p", QString::number(currentPage)); paint.drawText(marg, 0, headerWidth-(marg*2), headerHeight, align, s); align = valign|(i == 0 ? Qt::AlignHCenter : Qt::AlignRight); } } if ( ! ( headerDrawBg || useBox || useBackground ) ) // draw a 1 px (!?) line to separate header from contents { paint.drawLine( 0, headerHeight-1, headerWidth, headerHeight-1 ); //y += 1; now included in headerHeight } y += headerHeight + innerMargin; } if ( useFooter ) { paint.setPen(footerFgColor); if ( ! ( footerDrawBg || useBox || useBackground ) ) // draw a 1 px (!?) line to separate footer from contents paint.drawLine( 0, maxHeight + innerMargin - 1, headerWidth, maxHeight + innerMargin - 1 ); if ( footerDrawBg ) paint.fillRect(0, maxHeight+innerMargin+boxWidth, headerWidth, footerHeight, footerBgColor); if (footerTagList.count() == 3) { int align = Qt::AlignVCenter|Qt::AlignLeft; int marg = ( useBox || footerDrawBg ) ? innerMargin : 0; if ( useBox ) marg += boxWidth; QString s; for (int i=0; i<3; i++) { s = footerTagList[i]; if (s.indexOf("%p") != -1) s.replace("%p", QString::number(currentPage)); paint.drawText(marg, maxHeight+innerMargin, headerWidth-(marg*2), footerHeight, align, s); align = Qt::AlignVCenter|(i == 0 ? Qt::AlignHCenter : Qt::AlignRight); } } } // done footer if ( useBackground ) { // If we have a box, or the header/footer has backgrounds, we want to paint // to the border of those. Otherwise just the contents area. int _y = y, _h = maxHeight - y; if ( useBox ) { _y -= innerMargin; _h += 2 * innerMargin; } else { if ( headerDrawBg ) { _y -= innerMargin; _h += innerMargin; } if ( footerDrawBg ) { _h += innerMargin; } } paint.fillRect( 0, _y, pdmWidth, _h, renderer.config()->backgroundColor()); } if ( useBox ) { paint.setPen(QPen(boxColor, boxWidth)); paint.drawRect(0, 0, pdmWidth, pdmHeight); if (useHeader) paint.drawLine(0, headerHeight, headerWidth, headerHeight); else y += innerMargin; if ( useFooter ) // drawline is not trustable, grr. paint.fillRect( 0, maxHeight+innerMargin, headerWidth, boxWidth, boxColor ); } if ( useGuide && currentPage == 1 ) { // FIXME - this may span more pages... // draw a box unless we have boxes, in which case we end with a box line int _ystart = y; QString _hlName = doc->highlight()->name(); QList<KateExtendedAttribute::Ptr> _attributes; // list of highlight attributes for the legend doc->highlight()->getKateExtendedAttributeList(kpl->colorScheme(), _attributes); KateAttributeList _defaultAttributes; KateHlManager::self()->getDefaults ( renderer.config()->schema(), _defaultAttributes ); QColor _defaultPen = _defaultAttributes.at(0)->foreground().color(); paint.setPen(_defaultPen); int _marg = 0; if ( useBox ) _marg += (2*boxWidth) + (2*innerMargin); else { if ( useBackground ) _marg += 2*innerMargin; _marg += 1; y += 1 + innerMargin; } // draw a title string QFont _titleFont = renderer.config()->font(); _titleFont.setBold(true); paint.setFont( _titleFont ); QRect _r; paint.drawText( QRect(_marg, y, pdmWidth-(2*_marg), maxHeight - y), Qt::AlignTop|Qt::AlignHCenter, i18n("Typographical Conventions for %1", _hlName ), &_r ); int _w = pdmWidth - (_marg*2) - (innerMargin*2); int _x = _marg + innerMargin; y += _r.height() + innerMargin; paint.drawLine( _x, y, _x + _w, y ); y += 1 + innerMargin; int _widest( 0 ); foreach (const KateExtendedAttribute::Ptr &attribute, _attributes) _widest = qMax(QFontMetrics(attribute->font()).width(attribute->name().section(':',1,1)), _widest); int _guideCols = _w/( _widest + innerMargin ); // draw attrib names using their styles int _cw = _w/_guideCols; int _i(0); _titleFont.setUnderline(true); QString _currentHlName; foreach (const KateExtendedAttribute::Ptr &attribute, _attributes) { QString _hl = attribute->name().section(':',0,0); QString _name = attribute->name().section(':',1,1); if ( _hl != _hlName && _hl != _currentHlName ) { _currentHlName = _hl; if ( _i%_guideCols ) y += fontHeight; y += innerMargin; paint.setFont(_titleFont); paint.setPen(_defaultPen); paint.drawText( _x, y, _w, fontHeight, Qt::AlignTop, _hl + ' ' + i18n("text") ); y += fontHeight; _i = 0; } KTextEditor::Attribute _attr = *_defaultAttributes[attribute->defaultStyleIndex()]; _attr += *attribute; paint.setPen( _attr.foreground().color() ); paint.setFont( _attr.font() ); if (_attr.hasProperty(QTextFormat::BackgroundBrush) ) { QRect _rect = QFontMetrics(_attr.font()).boundingRect(_name); _rect.moveTo(_x + ((_i%_guideCols)*_cw), y); paint.fillRect(_rect, _attr.background() ); } paint.drawText(( _x + ((_i%_guideCols)*_cw)), y, _cw, fontHeight, Qt::AlignTop, _name ); _i++; if ( _i && ! ( _i%_guideCols ) ) y += fontHeight; } if ( _i%_guideCols ) y += fontHeight;// last row not full // draw a box around the legend paint.setPen ( _defaultPen ); if ( useBox ) paint.fillRect( 0, y+innerMargin, headerWidth, boxWidth, boxColor ); else { _marg -=1; paint.drawRect( _marg, _ystart, pdmWidth-(2*_marg), y-_ystart+innerMargin ); } y += ( useBox ? boxWidth : 1 ) + (innerMargin*2); } // useGuide paint.translate(xstart,y); pageStarted = false; } // pageStarted; move on to contents:)
bool Commands::exec(KTextEditor::View *view, const QString &_cmd, QString &msg, const KTextEditor::Range &range) { Q_UNUSED(range) // cast it hardcore, we know that it is really a kateview :) KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view); if (!v) { msg = i18n("Could not access view"); return false; } //create a list of args QStringList args(_cmd.split(QRegExp(QLatin1String("\\s+")), QString::SkipEmptyParts)); QString cmd(args.takeFirst()); // ALL commands that takes no arguments. if (mappingCommands().contains(cmd)) { if (cmd.endsWith(QLatin1String("unmap"))) { if (args.count() == 1) { m_viGlobal->mappings()->remove(modeForMapCommand(cmd), args.at(0)); return true; } else { msg = i18n("Missing argument. Usage: %1 <from>", cmd); return false; } } if (args.count() == 1) { msg = m_viGlobal->mappings()->get(modeForMapCommand(cmd), args.at(0), true); if (msg.isEmpty()) { msg = i18n("No mapping found for \"%1\"", args.at(0)); return false; } else { msg = i18n("\"%1\" is mapped to \"%2\"", args.at(0), msg); } } else if (args.count() == 2) { Mappings::MappingRecursion mappingRecursion = (isMapCommandRecursive(cmd)) ? Mappings::Recursive : Mappings::NonRecursive; m_viGlobal->mappings()->add(modeForMapCommand(cmd), args.at(0), args.at(1), mappingRecursion); } else { msg = i18n("Missing argument(s). Usage: %1 <from> [<to>]", cmd); return false; } return true; } NormalViMode *nm = m_viInputModeManager->getViNormalMode(); if (cmd == QLatin1String("d") || cmd == QLatin1String("delete") || cmd == QLatin1String("j") || cmd == QLatin1String("c") || cmd == QLatin1String("change") || cmd == QLatin1String("<") || cmd == QLatin1String(">") || cmd == QLatin1String("y") || cmd == QLatin1String("yank")) { KTextEditor::Cursor start_cursor_position = v->cursorPosition(); int count = 1; if (range.isValid()) { count = qAbs(range.end().line() - range.start().line()) + 1; v->setCursorPosition(KTextEditor::Cursor(qMin(range.start().line(), range.end().line()), 0)); } QRegExp number(QLatin1String("^(\\d+)$")); for (int i = 0; i < args.count(); i++) { if (number.indexIn(args.at(i)) != -1) { count += number.cap().toInt() - 1; } QChar r = args.at(i).at(0); if (args.at(i).size() == 1 && ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('+') || r == QLatin1Char('*'))) { nm->setRegister(r); } } nm->setCount(count); if (cmd == QLatin1String("d") || cmd == QLatin1String("delete")) { nm->commandDeleteLine(); } if (cmd == QLatin1String("j")) { nm->commandJoinLines(); } if (cmd == QLatin1String("c") || cmd == QLatin1String("change")) { nm->commandChangeLine(); } if (cmd == QLatin1String("<")) { nm->commandUnindentLine(); } if (cmd == QLatin1String(">")) { nm->commandIndentLine(); } if (cmd == QLatin1String("y") || cmd == QLatin1String("yank")) { nm->commandYankLine(); v->setCursorPosition(start_cursor_position); } // TODO - should we resetParser, here? We'd have to make it public, if so. // Or maybe synthesise a KateViCommand to execute instead ... ? nm->setCount(0); return true; } if (cmd == QLatin1String("mark") || cmd == QLatin1String("ma") || cmd == QLatin1String("k")) { if (args.count() == 0) { if (cmd == QLatin1String("mark")) { // TODO: show up mark list; } else { msg = i18n("Wrong arguments"); return false; } } else if (args.count() == 1) { QChar r = args.at(0).at(0); int line; if ((r >= QLatin1Char('a') && r <= QLatin1Char('z')) || r == QLatin1Char('_') || r == QLatin1Char('+') || r == QLatin1Char('*')) { if (range.isValid()) { line = qMax(range.end().line(), range.start().line()); } else { line = v->cursorPosition().line(); } m_viInputModeManager->marks()->setUserMark(r, KTextEditor::Cursor(line, 0)); } } else { msg = i18n("Wrong arguments"); return false; } return true; } // should not happen :) msg = i18n("Unknown command '%1'", cmd); return false; }
void ExporterPluginView::exportData(const bool useSelection, QTextStream &output) { const KTextEditor::Range range = useSelection ? m_view->selectionRange() : m_view->document()->documentRange(); const bool blockwise = useSelection ? m_view->blockSelection() : false; if ( (blockwise || range.onSingleLine()) && (range.start().column() > range.end().column() ) ) { return; } //outputStream.setEncoding(QTextStream::UnicodeUTF8); output.setCodec(QTextCodec::codecForName("UTF-8")); ///TODO: add more exporters AbstractExporter* exporter; exporter = new HTMLExporter(m_view, output, !useSelection); KTextEditor::HighlightInterface* hiface = qobject_cast<KTextEditor::HighlightInterface*>(m_view->document()); const KTextEditor::Attribute::Ptr noAttrib(0); for (int i = range.start().line(); (i <= range.end().line()) && (i < m_view->document()->lines()); ++i) { const QString &line = m_view->document()->line(i); QList<KTextEditor::HighlightInterface::AttributeBlock> attribs; if ( hiface ) { attribs = hiface->lineAttributes(i); } int lineStart = 0; int remainingChars = line.length(); if ( blockwise || range.onSingleLine() ) { lineStart = range.start().column(); remainingChars = range.columnWidth(); } else if ( i == range.start().line() ) { lineStart = range.start().column(); } else if ( i == range.end().line() ) { remainingChars = range.end().column(); } int handledUntil = lineStart; foreach ( const KTextEditor::HighlightInterface::AttributeBlock& block, attribs ) { // honor (block-) selections if ( block.start + block.length <= lineStart ) { continue; } else if ( block.start >= lineStart + remainingChars ) { break; } int start = qMax(block.start, lineStart); if ( start > handledUntil ) { exporter->exportText( line.mid( handledUntil, start - handledUntil ), noAttrib ); } int length = qMin(block.length, remainingChars); exporter->exportText( line.mid( start, length ), block.attribute); handledUntil = start + length; } if ( handledUntil < lineStart + remainingChars ) { exporter->exportText( line.mid( handledUntil, remainingChars ), noAttrib ); } exporter->closeLine(i == range.end().line()); } delete exporter; output.flush(); }
QList<QTextLayout::FormatRange> KateRenderer::decorationsForLine( const Kate::TextLine& textLine, int line, bool selectionsOnly, KateRenderRange* completionHighlight, bool completionSelected ) const { QList<QTextLayout::FormatRange> newHighlight; // Don't compute the highlighting if there isn't going to be any highlighting QList<Kate::TextRange *> rangesWithAttributes = m_doc->buffer().rangesForLine (line, m_printerFriendly ? 0 : m_view, true); if (selectionsOnly || textLine->attributesList().count() || rangesWithAttributes.count()) { RenderRangeList renderRanges; // Add the inbuilt highlighting to the list NormalRenderRange* inbuiltHighlight = new NormalRenderRange(); const QVector<Kate::TextLineData::Attribute> &al = textLine->attributesList(); for (int i = 0; i < al.count(); ++i) if (al[i].length > 0 && al[i].attributeValue > 0) inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i].offset), al[i].length), specificAttribute(al[i].attributeValue)); renderRanges.append(inbuiltHighlight); if (!completionHighlight) { // check for dynamic hl stuff const QSet<Kate::TextRange *> *rangesMouseIn = m_view ? m_view->rangesMouseIn () : 0; const QSet<Kate::TextRange *> *rangesCaretIn = m_view ? m_view->rangesCaretIn () : 0; bool anyDynamicHlsActive = m_view && (!rangesMouseIn->empty() || !rangesCaretIn->empty()); // sort all ranges, we want that the most specific ranges win during rendering, multiple equal ranges are kind of random, still better than old smart rangs behavior ;) qSort (rangesWithAttributes.begin(), rangesWithAttributes.end(), rangeLessThanForRenderer); // loop over all ranges for (int i = 0; i < rangesWithAttributes.size(); ++i) { // real range Kate::TextRange *kateRange = rangesWithAttributes[i]; // calculate attribute, default: normal attribute KTextEditor::Attribute::Ptr attribute = kateRange->attribute(); if (anyDynamicHlsActive) { // check mouse in if (KTextEditor::Attribute::Ptr attributeMouseIn = attribute->dynamicAttribute (KTextEditor::Attribute::ActivateMouseIn)) { if (rangesMouseIn->contains (kateRange)) attribute = attributeMouseIn; } // check caret in if (KTextEditor::Attribute::Ptr attributeCaretIn = attribute->dynamicAttribute (KTextEditor::Attribute::ActivateCaretIn)) { if (rangesCaretIn->contains (kateRange)) attribute = attributeCaretIn; } } // span range NormalRenderRange *additionaHl = new NormalRenderRange(); additionaHl->addRange(new KTextEditor::Range (*kateRange), attribute); renderRanges.append(additionaHl); } } else { // Add the code completion arbitrary highlight to the list renderRanges.append(completionHighlight); } // Add selection highlighting if we're creating the selection decorations if ((selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || m_view->blockSelection()) { NormalRenderRange* selectionHighlight = new NormalRenderRange(); // Set up the selection background attribute TODO: move this elsewhere, eg. into the config? static KTextEditor::Attribute::Ptr backgroundAttribute; if (!backgroundAttribute) backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute()); backgroundAttribute->setBackground(config()->selectionColor()); backgroundAttribute->setForeground(attribute(KTextEditor::HighlightInterface::dsNormal)->selectedForeground().color()); // Create a range for the current selection if (completionHighlight && completionSelected) selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute); else if(m_view->blockSelection() && m_view->selectionRange().overlapsLine(line)) selectionHighlight->addRange(new KTextEditor::Range(m_doc->rangeOnLine(m_view->selectionRange(), line)), backgroundAttribute); else { selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute); } renderRanges.append(selectionHighlight); // highlighting for the vi visual modes } KTextEditor::Cursor currentPosition, endPosition; // Calculate the range which we need to iterate in order to get the highlighting for just this line if (selectionsOnly) { if(m_view->blockSelection()) { KTextEditor::Range subRange = m_doc->rangeOnLine(m_view->selectionRange(), line); currentPosition = subRange.start(); endPosition = subRange.end(); } else { KTextEditor::Range rangeNeeded = m_view->selectionRange() & KTextEditor::Range(line, 0, line + 1, 0); currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start()); endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end()); } } else { currentPosition = KTextEditor::Cursor(line, 0); endPosition = KTextEditor::Cursor(line + 1, 0); } // Main iterative loop. This walks through each set of highlighting ranges, and stops each // time the highlighting changes. It then creates the corresponding QTextLayout::FormatRanges. while (currentPosition < endPosition) { renderRanges.advanceTo(currentPosition); if (!renderRanges.hasAttribute()) { // No attribute, don't need to create a FormatRange for this text range currentPosition = renderRanges.nextBoundary(); continue; } KTextEditor::Cursor nextPosition = renderRanges.nextBoundary(); // Create the format range and populate with the correct start, length and format info QTextLayout::FormatRange fr; fr.start = currentPosition.column(); if (nextPosition < endPosition || endPosition.line() <= line) { fr.length = nextPosition.column() - currentPosition.column(); } else { // +1 to force background drawing at the end of the line when it's warranted fr.length = textLine->length() - currentPosition.column() + 1; } KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute(); if (a) { fr.format = *a; if(selectionsOnly) { assignSelectionBrushesFromAttribute(fr, *a); } } newHighlight.append(fr); currentPosition = nextPosition; } if (completionHighlight) // Don't delete external completion render range renderRanges.removeAll(completionHighlight); qDeleteAll(renderRanges); } return newHighlight; }
QString HighlighterByKate::exportDocument(KTextEditor::Document* note) { QString ret(""); KTextEditor::Range range; range = note->documentRange(); KTextEditor::HighlightInterface* hiface = qobject_cast<KTextEditor::HighlightInterface*>(note); const KTextEditor::Attribute::Ptr noAttrib(0); for (int i = 0; i < note->lines(); ++i) { QString content(""); const QString &line = note->line(i); QList<KTextEditor::HighlightInterface::AttributeBlock> attribs; if ( hiface ) { attribs = hiface->lineAttributes(i); } int lineStart = 0; int remainingChars = line.length(); if ( range.onSingleLine() ) { lineStart = range.start().column(); remainingChars = range.columnWidth(); } else if ( i == range.start().line() ) { lineStart = range.start().column(); } else if ( i == range.end().line() ) { remainingChars = range.end().column(); } int handledUntil = lineStart; foreach ( const KTextEditor::HighlightInterface::AttributeBlock& block, attribs ) { // honor (block-) selections if ( block.start + block.length <= lineStart ) { continue; } else if ( block.start >= lineStart + remainingChars ) { break; } int start = qMax(block.start, lineStart); if ( start > handledUntil ) { exportText(content, line.mid( handledUntil, start - handledUntil ), noAttrib ); } int length = qMin(block.length, remainingChars); exportText(content, line.mid( start, length ), block.attribute); handledUntil = start + length; } if ( handledUntil < lineStart + remainingChars ) { exportText(content, line.mid( handledUntil, remainingChars ), noAttrib ); } if (i != range.end().line()) { ret.append(content.isEmpty() ? "\n" : content); ret.append("\n"); } } return ret; }