1 | /* |
2 | SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com> |
3 | |
4 | SPDX-License-Identifier: LGPL-2.0-or-later |
5 | */ |
6 | |
7 | #include "codecompletionmodelcontrollerinterface.h" |
8 | |
9 | #include <QModelIndex> |
10 | #include <QRegularExpression> |
11 | |
12 | #include <kateconfig.h> |
13 | #include <ktexteditor/document.h> |
14 | #include <ktexteditor/view.h> |
15 | |
16 | namespace KTextEditor |
17 | { |
18 | CodeCompletionModelControllerInterface::CodeCompletionModelControllerInterface() |
19 | { |
20 | } |
21 | |
22 | CodeCompletionModelControllerInterface::~CodeCompletionModelControllerInterface() = default; |
23 | |
24 | bool CodeCompletionModelControllerInterface::shouldStartCompletion(View *view, const QString &insertedText, bool userInsertion, const Cursor &position) |
25 | { |
26 | Q_UNUSED(view); |
27 | Q_UNUSED(position); |
28 | if (insertedText.isEmpty()) { |
29 | return false; |
30 | } |
31 | |
32 | QChar lastChar = insertedText.at(i: insertedText.size() - 1); |
33 | if ((userInsertion && (lastChar.isLetter() || lastChar.isNumber() || lastChar == QLatin1Char('_'))) || lastChar == QLatin1Char('.') |
34 | || insertedText.endsWith(s: QLatin1String("->" ))) { |
35 | return true; |
36 | } |
37 | return false; |
38 | } |
39 | |
40 | Range CodeCompletionModelControllerInterface::completionRange(View *view, const Cursor &position) |
41 | { |
42 | Cursor end = position; |
43 | const int line = end.line(); |
44 | |
45 | const QString lineText = view->document()->line(line); |
46 | QStringView text = lineText; |
47 | |
48 | static constexpr auto options = QRegularExpression::UseUnicodePropertiesOption | QRegularExpression::DontCaptureOption; |
49 | static const QRegularExpression findWordStart(QStringLiteral("\\b[_\\w]+$" ), options); |
50 | static const QRegularExpression findWordEnd(QStringLiteral("^[_\\w]*\\b" ), options); |
51 | |
52 | Cursor start = end; |
53 | |
54 | int pos = text.left(n: end.column()).lastIndexOf(re: findWordStart); |
55 | if (pos >= 0) { |
56 | start.setColumn(pos); |
57 | } |
58 | |
59 | if (!KateViewConfig::global()->wordCompletionRemoveTail()) { |
60 | // We are not removing tail, range only contains the word left of the cursor |
61 | return Range(start, position); |
62 | } else { |
63 | // Removing tail, find the word end |
64 | QRegularExpressionMatch match; |
65 | pos = text.mid(pos: end.column()).indexOf(re: findWordEnd, from: 0, rmatch: &match); |
66 | if (pos >= 0) { |
67 | end.setColumn(end.column() + match.capturedLength()); |
68 | } |
69 | |
70 | return Range(start, end); |
71 | } |
72 | } |
73 | |
74 | Range CodeCompletionModelControllerInterface::updateCompletionRange(View *view, const Range &range) |
75 | { |
76 | QStringList text = view->document()->textLines(range, block: false); |
77 | if (!text.isEmpty() && text.count() == 1 && text.first().trimmed().isEmpty()) |
78 | // When inserting a newline behind an empty completion-range,, move the range forward to its end |
79 | { |
80 | return Range(range.end(), range.end()); |
81 | } |
82 | |
83 | return range; |
84 | } |
85 | |
86 | QString CodeCompletionModelControllerInterface::filterString(View *view, const Range &range, const Cursor &position) |
87 | { |
88 | return view->document()->text(range: KTextEditor::Range(range.start(), position)); |
89 | } |
90 | |
91 | bool CodeCompletionModelControllerInterface::shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) |
92 | { |
93 | if (view->cursorPosition() < range.start() || view->cursorPosition() > range.end()) { |
94 | return true; // Always abort when the completion-range has been left |
95 | } |
96 | // Do not abort completions when the text has been empty already before and a newline has been entered |
97 | |
98 | static const QRegularExpression allowedText(QStringLiteral("^\\w*$" ), QRegularExpression::UseUnicodePropertiesOption); |
99 | return !allowedText.match(subject: currentCompletion).hasMatch(); |
100 | } |
101 | |
102 | void CodeCompletionModelControllerInterface::aborted(KTextEditor::View *view) |
103 | { |
104 | Q_UNUSED(view); |
105 | } |
106 | |
107 | bool CodeCompletionModelControllerInterface::shouldExecute(const QModelIndex &index, QChar inserted) |
108 | { |
109 | Q_UNUSED(index); |
110 | Q_UNUSED(inserted); |
111 | return false; |
112 | } |
113 | |
114 | KTextEditor::CodeCompletionModelControllerInterface::MatchReaction CodeCompletionModelControllerInterface::matchingItem(const QModelIndex &selected) |
115 | { |
116 | Q_UNUSED(selected) |
117 | return HideListIfAutomaticInvocation; |
118 | } |
119 | |
120 | bool CodeCompletionModelControllerInterface::shouldHideItemsWithEqualNames() const |
121 | { |
122 | return false; |
123 | } |
124 | |
125 | } |
126 | |