File indexing completed on 2024-05-12 04:37:45

0001 /*
0002     SPDX-FileCopyrightText: 2006-2008 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "codecompletionworker.h"
0009 
0010 #include <KTextEditor/View>
0011 #include <KTextEditor/Document>
0012 #include <KLocalizedString>
0013 
0014 #include "../duchain/ducontext.h"
0015 #include "../duchain/duchainlock.h"
0016 #include "../duchain/duchain.h"
0017 #include <debug.h>
0018 #include "codecompletion.h"
0019 #include "codecompletionitem.h"
0020 #include "codecompletionmodel.h"
0021 #include "codecompletionitemgrouper.h"
0022 #include <util/foregroundlock.h>
0023 
0024 using namespace KTextEditor;
0025 using namespace KDevelop;
0026 
0027 CodeCompletionWorker::CodeCompletionWorker(KDevelop::CodeCompletionModel* model) :
0028     m_hasFoundDeclarations(false)
0029     , m_mutex(new QMutex())
0030     , m_abort(false)
0031     , m_fullCompletion(true)
0032     , m_model(model)
0033 {
0034 }
0035 
0036 CodeCompletionWorker::~CodeCompletionWorker()
0037 {
0038     delete m_mutex;
0039 }
0040 
0041 void CodeCompletionWorker::setFullCompletion(bool full)
0042 {
0043     m_fullCompletion = full;
0044 }
0045 
0046 bool CodeCompletionWorker::fullCompletion() const
0047 {
0048     return m_fullCompletion;
0049 }
0050 
0051 void CodeCompletionWorker::failed()
0052 {
0053     foundDeclarations({}, {});
0054 }
0055 
0056 void CodeCompletionWorker::foundDeclarations(const QList<CompletionTreeElementPointer>& items,
0057                                              const CodeCompletionContext::Ptr& completionContext)
0058 {
0059     m_hasFoundDeclarations = true;
0060     emit foundDeclarationsReal(items, completionContext);
0061 }
0062 
0063 void CodeCompletionWorker::computeCompletions(const KDevelop::DUContextPointer& context,
0064                                               const KTextEditor::Cursor& position, KTextEditor::View* view)
0065 {
0066     {
0067         QMutexLocker lock(m_mutex);
0068         m_abort = false;
0069     }
0070 
0071     ///@todo It's not entirely safe to pass KTextEditor::View* through a queued connection
0072     // We access the view/document which is not thread-safe, so we need the foreground lock
0073     ForegroundLock foreground;
0074 
0075     //Compute the text we should complete on
0076     KTextEditor::Document* doc = view->document();
0077     if (!doc) {
0078         qCDebug(LANGUAGE) << "No document for completion";
0079         failed();
0080         return;
0081     }
0082 
0083     KTextEditor::Range range;
0084     QString text;
0085     {
0086         QMutexLocker lock(m_mutex);
0087         DUChainReadLocker lockDUChain;
0088 
0089         if (context) {
0090             qCDebug(LANGUAGE) << context->localScopeIdentifier().toString();
0091             range = KTextEditor::Range(context->rangeInCurrentRevision().start(), position);
0092         } else
0093             range = KTextEditor::Range(KTextEditor::Cursor(position.line(), 0), position);
0094 
0095         updateContextRange(range, view, context);
0096 
0097         text = doc->text(range);
0098     }
0099 
0100     if (position.column() == 0) //Seems like when the cursor is a the beginning of a line, kate does not give the \n
0101         text += QLatin1Char('\n');
0102 
0103     if (aborting()) {
0104         failed();
0105         return;
0106     }
0107     m_hasFoundDeclarations = false;
0108 
0109     KTextEditor::Cursor cursorPosition = view->cursorPosition();
0110     QString followingText; //followingText may contain additional text that stands for the current item. For example in the case "QString|", QString is in addedText.
0111     if (position < cursorPosition)
0112         followingText = view->document()->text(KTextEditor::Range(position, cursorPosition));
0113 
0114     foreground.unlock();
0115 
0116     computeCompletions(context, position, followingText, range, text);
0117 
0118     if (!m_hasFoundDeclarations)
0119         failed();
0120 }
0121 
0122 void KDevelop::CodeCompletionWorker::doSpecialProcessing(uint)
0123 {
0124 }
0125 
0126 CodeCompletionContext* CodeCompletionWorker::createCompletionContext(const KDevelop::DUContextPointer& context,
0127                                                                      const QString& contextText,
0128                                                                      const QString& followingText,
0129                                                                      const KDevelop::CursorInRevision& position) const
0130 {
0131     Q_UNUSED(context);
0132     Q_UNUSED(contextText);
0133     Q_UNUSED(followingText);
0134     Q_UNUSED(position);
0135     return nullptr;
0136 }
0137 
0138 void CodeCompletionWorker::computeCompletions(const KDevelop::DUContextPointer& context,
0139                                               const KTextEditor::Cursor& position, const QString& followingText,
0140                                               const KTextEditor::Range& contextRange, const QString& contextText)
0141 {
0142     Q_UNUSED(contextRange);
0143 
0144     qCDebug(LANGUAGE) << "added text:" << followingText;
0145 
0146     CodeCompletionContext::Ptr completionContext(createCompletionContext(context, contextText, followingText, CursorInRevision::castFromSimpleCursor(KTextEditor::Cursor(
0147                                                                                                                                                          position))));
0148     if (KDevelop::CodeCompletionModel* m = model())
0149         m->setCompletionContext(completionContext);
0150 
0151     if (completionContext && completionContext->isValid()) {
0152         {
0153             DUChainReadLocker lock(DUChain::lock());
0154 
0155             if (!context) {
0156                 failed();
0157                 qCDebug(LANGUAGE) << "Completion context disappeared before completions could be calculated";
0158                 return;
0159             }
0160         }
0161         QList<CompletionTreeItemPointer> items = completionContext->completionItems(aborting(), fullCompletion());
0162 
0163         if (aborting()) {
0164             failed();
0165             return;
0166         }
0167 
0168         QList<QExplicitlySharedDataPointer<CompletionTreeElement>> tree = computeGroups(items, completionContext);
0169 
0170         if (aborting()) {
0171             failed();
0172             return;
0173         }
0174 
0175         tree += completionContext->ungroupedElements();
0176 
0177         foundDeclarations(tree, completionContext);
0178     } else {
0179         qCDebug(LANGUAGE) << "setContext: Invalid code-completion context";
0180     }
0181 }
0182 
0183 QList<QExplicitlySharedDataPointer<CompletionTreeElement>> CodeCompletionWorker::computeGroups(
0184     const QList<CompletionTreeItemPointer>& items,
0185     const QExplicitlySharedDataPointer<CodeCompletionContext>& completionContext)
0186 {
0187     Q_UNUSED(completionContext);
0188     QList<QExplicitlySharedDataPointer<CompletionTreeElement>> tree;
0189     /**
0190      * 1. Group by argument-hint depth
0191      * 2. Group by inheritance depth
0192      * 3. Group by simplified attributes
0193      * */
0194     CodeCompletionItemGrouper<ArgumentHintDepthExtractor, CodeCompletionItemGrouper<InheritanceDepthExtractor,
0195             CodeCompletionItemGrouper<SimplifiedAttributesExtractor>>> argumentHintDepthGrouper(tree, nullptr, std::move(
0196             items));
0197     return tree;
0198 }
0199 
0200 void CodeCompletionWorker::abortCurrentCompletion()
0201 {
0202     QMutexLocker lock(m_mutex);
0203     m_abort = true;
0204 }
0205 
0206 bool& CodeCompletionWorker::aborting()
0207 {
0208     return m_abort;
0209 }
0210 
0211 KDevelop::CodeCompletionModel* CodeCompletionWorker::model() const
0212 {
0213     return m_model;
0214 }
0215 
0216 void CodeCompletionWorker::updateContextRange(Range& contextRange, View* view, const DUContextPointer& context) const
0217 {
0218     Q_UNUSED(contextRange);
0219     Q_UNUSED(view);
0220     Q_UNUSED(context);
0221 }
0222 
0223 #include "moc_codecompletionworker.cpp"