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); }
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); }
void AdaptSignatureAssistant::textChanged(KTextEditor::View* view, const KTextEditor::Range& invocationRange, const QString& removedText) { reset(); m_view = view; //FIXME: update signature assistant to play well with the rename assistant KTextEditor::Range sigAssistRange = invocationRange; if (!removedText.isEmpty()) { sigAssistRange.setRange(sigAssistRange.start(), sigAssistRange.start()); } m_document = view->document()->url(); DUChainReadLocker lock(DUChain::lock(), 300); if(!lock.locked()) { qCDebug(CPP) << "failed to lock duchain in time"; return; } KTextEditor::Range simpleInvocationRange = KTextEditor::Range(sigAssistRange); Declaration* funDecl = getDeclarationAtCursor(simpleInvocationRange.start(), m_document); if(!funDecl || !funDecl->type<FunctionType>()) return; if(QtFunctionDeclaration* classFun = dynamic_cast<QtFunctionDeclaration*>(funDecl)) { if (classFun->isSignal()) { // do not offer to change signature of a signal, as the implementation will be generated by moc return; } } Declaration* otherSide = 0; FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(funDecl); if (definition) { m_editingDefinition = true; otherSide = definition->declaration(); } else if ((definition = FunctionDefinition::definition(funDecl))) { m_editingDefinition = false; otherSide = definition; } if (!otherSide) return; m_otherSideContext = DUContextPointer(DUChainUtils::getFunctionContext(otherSide)); if (!m_otherSideContext) return; m_declarationName = funDecl->identifier(); m_otherSideId = otherSide->id(); m_otherSideTopContext = ReferencedTopDUContext(otherSide->topContext()); m_oldSignature = getDeclarationSignature(otherSide, m_otherSideContext.data(), true); //Schedule an update, to make sure the ranges match DUChain::self()->updateContextForUrl(m_otherSideTopContext->url(), TopDUContext::AllDeclarationsAndContexts); }
/** 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 CodeCompletionWorker::updateContextRange(KTextEditor::Range& contextRange, KTextEditor::View* /*view*/, DUContextPointer context) const { if(context && context->owner() && context->owner()->type<FunctionType>()) { if(!context->owner()->type<FunctionType>()->returnType()) { //For constructor completion, we need some more context contextRange.start().setLine(contextRange.start().line() > 30 ? contextRange.start().line()-30 : 0); contextRange.start().setColumn(0); } } }
// Scan throughout the entire document for possible completions, // ignoring any dublets const QStringList KateWordCompletionModel::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 re( "\\b(" + match_str + "\\w{1,})" ); while( i < doc->lines() ) { s = doc->line( i ); pos = 0; while ( pos >= 0 ) { pos = re.indexIn( s, pos ); if ( pos >= 0 ) { // typing in the middle of a word if ( ! ( i == range.start().line() && pos == range.start().column() ) ) { m = re.cap( 1 ); if ( ! seen.contains( m ) ) { seen.insert( m ); l << m; } } pos += re.matchedLength(); } } i++; } // Global completion // int db_area = KDebug::registerArea("ktuan-debug"); QMap<QString, QStringList>::const_iterator ci = doc_word_list.constBegin(); while (ci != doc_word_list.constEnd()) { if (ci.key() != doc->url().prettyUrl()) { QStringList list = ci.value(); foreach (QString word, list) { // kDebug(db_area) << "complete word " << word; if (word.startsWith(match_str) && !seen.contains(word)) { // kDebug(db_area) << "Global completion"; seen.insert(word); l << word; } } } ++ci; }
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); }
void KeywordItem::execute(KTextEditor::View* view, const KTextEditor::Range& word) { KTextEditor::Document *document = view->document(); if ( !m_replacement.isEmpty() ) { QString replacement = m_replacement; replacement = replacement.replace('\n', '\n' + getIndendation(document->line(word.start().line()))); replacement = replacement.replace(QLatin1String("%INDENT%"), indentString(document)); int cursorPos = replacement.indexOf(QStringLiteral("%CURSOR%")); int selectionEnd = -1; if ( cursorPos != -1 ) { replacement.remove(QStringLiteral("%CURSOR%")); } else { cursorPos = replacement.indexOf(QStringLiteral("%SELECT%")); if ( cursorPos != -1 ) { replacement.remove(QStringLiteral("%SELECT%")); selectionEnd = replacement.indexOf(QStringLiteral("%ENDSELECT%"), cursorPos + 1); if ( selectionEnd == -1 ) { selectionEnd = replacement.length(); } replacement.remove(QStringLiteral("%ENDSELECT%")); } } document->replaceText(word, replacement); if ( cursorPos != -1 ) { if (view) { replacement = replacement.left(cursorPos); KTextEditor::Cursor newPos( word.start().line() + replacement.count('\n'), word.start().column() + replacement.length() - replacement.lastIndexOf('\n') - 1 ); view->setCursorPosition(newPos); if ( selectionEnd != -1 ) { ///TODO: maybe we want to support multi-line selections in the future? view->setSelection( KTextEditor::Range( newPos, KTextEditor::Cursor( newPos.line(), newPos.column() + selectionEnd - cursorPos ) ) ); } } } } else { document->replaceText(word, m_keyword + ' '); } }
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; }
void PreprocessorCompletionModel::executeCompletionItem2( KTextEditor::Document* const doc , const KTextEditor::Range& word , const QModelIndex& index ) const { 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("Index points to invalid item" && unsigned(index.row()) < COMPLETIONS.size()); auto text = COMPLETIONS[index.row()].text; const auto column = text.indexOf('|'); if (column != -1) text.remove(column, 1); doc->replaceText(word, text); // Try to reposition a cursor inside a current view if (column != -1) { auto pos = word.start(); pos.setColumn(pos.column() + column); doc->activeView()->setCursorPosition(pos); } }
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; }
void KDocumentTextBuffer::localTextRemoved( KTextEditor::Document *document, const KTextEditor::Range &range, const QString& oldText ) { if ( m_aboutToClose ) return; kDebug() << "local text removed:" << kDocument() << range; emit localChangedText(range, user(), true); Q_UNUSED(document) textOpPerformed(); if( !m_user.isNull() ) { unsigned int offset = cursorToOffset_kte( range.start() ); unsigned int len = countUnicodeCharacters(oldText); blockRemoteRemove = true; kDebug() << "ERASING TEXT" << oldText << "with len" << len << "offset" << offset << "range" << range; kDebug() << offset << len << length(); if( len > 0 ) eraseText( offset, len, m_user ); else kDebug() << "0 legth delete operation. Skipping."; checkConsistency(); } else kDebug() << "Could not remove text: No local user set."; }
void SnippetCompletionItem::execute( KTextEditor::View* view, const KTextEditor::Range& word ) { QMap< QString, QString > values = QMap<QString, QString>(); KTextEditor::TemplateInterface2* templateIface2 = qobject_cast<KTextEditor::TemplateInterface2*>(view); if (templateIface2) templateIface2->insertTemplateText(word.start(), m_snippet, values, m_repo->registeredScript()); }
/** 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 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 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 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)); } }
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; }
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)); }
void IncludeHelperCompletionModel::completionInvoked( KTextEditor::View* view , const KTextEditor::Range& range , InvocationType ) { auto* doc = view->document(); kDebug(DEBUG_AREA) << range << ", " << doc->text(range); const auto& t = doc->line(range.start().line()).left(range.start().column()); kDebug(DEBUG_AREA) << "text to parse: " << t; auto r = parseIncludeDirective(t, false); if (r.m_range.isValid()) { m_should_complete = range.start().column() >= r.m_range.start().column() && range.start().column() <= r.m_range.end().column(); if (m_should_complete) { r.m_range.setBothLines(range.start().line()); kDebug(DEBUG_AREA) << "parsed range: " << r.m_range; m_closer = r.close_char(); updateCompletionList(doc->text(r.m_range), r.m_type == IncludeStyle::local); } } }
// Scan throughout the entire document for possible completions, // ignoring any dublets const QStringList KateWordCompletionModel::allMatches( KTextEditor::View *view, const KTextEditor::Range &range ) const { QStringList l; int i( 0 ); int pos( 0 ); KTextEditor::Document *doc = view->document(); QRegExp re( "\\b(" + doc->text( range ) + "\\w{1,})" ); QString s, m; QSet<QString> seen; while( i < doc->lines() ) { s = doc->line( i ); pos = 0; while ( pos >= 0 ) { pos = re.indexIn( s, pos ); if ( pos >= 0 ) { // typing in the middle of a word if ( ! ( i == range.start().line() && pos == range.start().column() ) ) { m = re.cap( 1 ); if ( ! seen.contains( m ) ) { seen.insert( m ); l << m; } } pos += re.matchedLength(); } } i++; } return l; }
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 KDocumentTextBuffer::localTextInserted( KTextEditor::Document *document, const KTextEditor::Range &range ) { if ( m_aboutToClose ) return; emit localChangedText(range, user(), false); Q_UNUSED(document) textOpPerformed(); if( m_user.isNull() ) { kDebug() << "Could not insert text: No local user set."; return; } unsigned int offset = cursorToOffset_kte(range.start()); kDebug() << "local text inserted" << kDocument() << "( range" << range << ")" << m_user << "offset:" << offset; QInfinity::TextChunk chunk(encoding()); QString text = kDocument()->text(range); #ifdef ENABLE_TAB_HACK if ( text.contains('\t') ) { text = text.replace('\t', " "); kDocument()->blockSignals(true); kDocument()->replaceText(range, text); kDocument()->blockSignals(false); } #endif Q_ASSERT(encoder()); if ( text.isEmpty() ) { kDebug() << "Skipping empty insert."; return; } QByteArray encodedText = codec()->fromUnicode( text ); if ( encodedText.size() == 0 ) { kDebug() << "Got empty encoded text from non empty string " "Skipping insertion"; } else { chunk.insertText( 0, encodedText, countUnicodeCharacters(text), m_user->id() ); blockRemoteInsert = true; kDebug() << "inserting chunk of size" << chunk.length() << "into local buffer" << kDocument()->url(); insertChunk( offset, chunk, m_user ); kDebug() << "done inserting chunk"; checkConsistency(); } }
void IncludeHelperCompletionModel::executeCompletionItem2( KTextEditor::Document* document , const KTextEditor::Range& word , const QModelIndex& index ) const { kDebug(DEBUG_AREA) << "rword=" << word; auto p = index.row() < m_dir_completions.size() ? m_dir_completions[index.row()] : m_file_completions[index.row() - m_dir_completions.size()] ; kDebug(DEBUG_AREA) << "dict=" << p; if (!p.endsWith("/")) // Is that dir or file completion? { // Get line to be replaced and check if #include hase close char... auto line = document->line(word.start().line()); auto r = parseIncludeDirective(line, false); if (r.m_range.isValid() && !r.m_is_complete) p += r.close_char(); } document->replaceText(word, p); }
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); }
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); }
void ClangCodeCompletionModel::completionInvoked( KTextEditor::View* const view , const KTextEditor::Range& range , const InvocationType /*invocationType*/ ) { m_current_view = view; auto* const doc = view->document(); const auto& url = doc->url(); if (!url.isValid() || url.isEmpty()) { /// \todo Turn into a popup kWarning() << "U have to have a document on a disk before use code completion"; return; } kDebug(DEBUG_AREA) << "Comletion requested at " << range << "for" << doc->text(range); // Remove everything collected before m_groups.clear(); try { auto& unit = m_plugin->getTranslationUnitByDocument(doc); // Show some SPAM in a tool view m_diagnostic_model.append( clang::diagnostic_message{ clang::location{doc->url(), range.start().line() + 1, range.start().column() + 1} , "Completion point" , clang::diagnostic_message::type::debug } ); // Obtain diagnostic if any { auto diag = unit.getLastDiagnostic(); if (!diag.empty()) m_diagnostic_model.append( std::make_move_iterator(begin(diag)) , std::make_move_iterator(end(diag)) ); } // Try to make a completion auto completions = unit.completeAt( unsigned(range.start().line() + 1) // NOTE Kate count lines starting from 0 , unsigned(range.start().column() + 1) // NOTE Kate count columns starting from 0 , m_plugin->config().completionFlags() , m_plugin->unsavedFiles() , m_plugin->config().sanitizeCompletions() ? m_plugin->config().sanitizeRules() : PluginConfiguration::sanitize_rules_list_type() ); // Obtain diagnostic if any { auto diag = unit.getLastDiagnostic(); if (!diag.empty()) m_diagnostic_model.append( std::make_move_iterator(begin(diag)) , std::make_move_iterator(end(diag)) ); } // Transform a plain list into hierarchy grouped by a parent context std::map<QString, GroupInfo> grouped_completions; for (auto&& comp : completions) { // Find a group for current item auto it = grouped_completions.find(comp.parentText()); if (it == end(grouped_completions)) { // No group yet, let create a new one it = grouped_completions.insert(std::make_pair(comp.parentText(), GroupInfo())).first; } // Add a current item to the list of completions in the current group it->second.m_completions.emplace_back(std::move(comp)); } // Convert the collected map to a vector m_groups.reserve(grouped_completions.size()); std::transform( std::make_move_iterator(begin(grouped_completions)) , std::make_move_iterator(end(grouped_completions)) , std::back_inserter(m_groups) , [](std::pair<const QString, GroupInfo>&& p) { return std::move(p); } ); } catch (const TranslationUnit::Exception& e) { m_diagnostic_model.append( clang::diagnostic_message( QString("Fail to make a code completion: %1").arg(e.what()) , clang::diagnostic_message::type::error ) ); } }
// 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; }