File indexing completed on 2024-04-21 03:57:45

0001 /*
0002     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "codecompletionmodelcontrollerinterface.h"
0008 
0009 #include <QModelIndex>
0010 #include <QRegularExpression>
0011 
0012 #include <kateconfig.h>
0013 #include <ktexteditor/document.h>
0014 #include <ktexteditor/view.h>
0015 
0016 namespace KTextEditor
0017 {
0018 CodeCompletionModelControllerInterface::CodeCompletionModelControllerInterface()
0019 {
0020 }
0021 
0022 CodeCompletionModelControllerInterface::~CodeCompletionModelControllerInterface() = default;
0023 
0024 bool CodeCompletionModelControllerInterface::shouldStartCompletion(View *view, const QString &insertedText, bool userInsertion, const Cursor &position)
0025 {
0026     Q_UNUSED(view);
0027     Q_UNUSED(position);
0028     if (insertedText.isEmpty()) {
0029         return false;
0030     }
0031 
0032     QChar lastChar = insertedText.at(insertedText.size() - 1);
0033     if ((userInsertion && (lastChar.isLetter() || lastChar.isNumber() || lastChar == QLatin1Char('_'))) || lastChar == QLatin1Char('.')
0034         || insertedText.endsWith(QLatin1String("->"))) {
0035         return true;
0036     }
0037     return false;
0038 }
0039 
0040 Range CodeCompletionModelControllerInterface::completionRange(View *view, const Cursor &position)
0041 {
0042     Cursor end = position;
0043     const int line = end.line();
0044 
0045     const QString lineText = view->document()->line(line);
0046     QStringView text = lineText;
0047 
0048     static constexpr auto options = QRegularExpression::UseUnicodePropertiesOption | QRegularExpression::DontCaptureOption;
0049     static const QRegularExpression findWordStart(QStringLiteral("\\b[_\\w]+$"), options);
0050     static const QRegularExpression findWordEnd(QStringLiteral("^[_\\w]*\\b"), options);
0051 
0052     Cursor start = end;
0053 
0054     int pos = text.left(end.column()).lastIndexOf(findWordStart);
0055     if (pos >= 0) {
0056         start.setColumn(pos);
0057     }
0058 
0059     if (!KateViewConfig::global()->wordCompletionRemoveTail()) {
0060         // We are not removing tail, range only contains the word left of the cursor
0061         return Range(start, position);
0062     } else {
0063         // Removing tail, find the word end
0064         QRegularExpressionMatch match;
0065         pos = text.mid(end.column()).indexOf(findWordEnd, 0, &match);
0066         if (pos >= 0) {
0067             end.setColumn(end.column() + match.capturedLength());
0068         }
0069 
0070         return Range(start, end);
0071     }
0072 }
0073 
0074 Range CodeCompletionModelControllerInterface::updateCompletionRange(View *view, const Range &range)
0075 {
0076     QStringList text = view->document()->textLines(range, false);
0077     if (!text.isEmpty() && text.count() == 1 && text.first().trimmed().isEmpty())
0078     // When inserting a newline behind an empty completion-range,, move the range forward to its end
0079     {
0080         return Range(range.end(), range.end());
0081     }
0082 
0083     return range;
0084 }
0085 
0086 QString CodeCompletionModelControllerInterface::filterString(View *view, const Range &range, const Cursor &position)
0087 {
0088     return view->document()->text(KTextEditor::Range(range.start(), position));
0089 }
0090 
0091 bool CodeCompletionModelControllerInterface::shouldAbortCompletion(View *view, const Range &range, const QString &currentCompletion)
0092 {
0093     if (view->cursorPosition() < range.start() || view->cursorPosition() > range.end()) {
0094         return true; // Always abort when the completion-range has been left
0095     }
0096     // Do not abort completions when the text has been empty already before and a newline has been entered
0097 
0098     static const QRegularExpression allowedText(QStringLiteral("^\\w*$"), QRegularExpression::UseUnicodePropertiesOption);
0099     return !allowedText.match(currentCompletion).hasMatch();
0100 }
0101 
0102 void CodeCompletionModelControllerInterface::aborted(KTextEditor::View *view)
0103 {
0104     Q_UNUSED(view);
0105 }
0106 
0107 bool CodeCompletionModelControllerInterface::shouldExecute(const QModelIndex &index, QChar inserted)
0108 {
0109     Q_UNUSED(index);
0110     Q_UNUSED(inserted);
0111     return false;
0112 }
0113 
0114 KTextEditor::CodeCompletionModelControllerInterface::MatchReaction CodeCompletionModelControllerInterface::matchingItem(const QModelIndex &selected)
0115 {
0116     Q_UNUSED(selected)
0117     return HideListIfAutomaticInvocation;
0118 }
0119 
0120 bool CodeCompletionModelControllerInterface::shouldHideItemsWithEqualNames() const
0121 {
0122     return false;
0123 }
0124 
0125 }