1 // Scintilla source code edit control
2 /** @file AutoComplete.cxx
3 ** Defines the auto completion list box.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #include <string_view>
22 #include "ScintillaTypes.h"
23 #include "ScintillaMessages.h"
25 #include "Debugging.h"
29 #include "CharacterType.h"
31 #include "AutoComplete.h"
33 using namespace Scintilla
;
34 using namespace Scintilla::Internal
;
36 AutoComplete::AutoComplete() :
42 options(AutoCompleteOption::Normal
),
45 cancelAtStartPos(true),
47 dropRestOfWord(false),
48 ignoreCaseBehaviour(CaseInsensitiveBehaviour::RespectCase
),
51 autoSort(Ordering::PreSorted
) {
52 lb
= ListBox::Allocate();
55 AutoComplete::~AutoComplete() {
61 bool AutoComplete::Active() const noexcept
{
65 void AutoComplete::Start(Window
&parent
, int ctrlID
,
66 Sci::Position position
, Point location
, Sci::Position startLen_
,
67 int lineHeight
, bool unicodeMode
, Technology technology
, ListOptions listOptions
) {
71 lb
->SetOptions(listOptions
);
72 lb
->Create(parent
, ctrlID
, location
, lineHeight
, unicodeMode
, technology
);
79 void AutoComplete::SetStopChars(const char *stopChars_
) {
80 stopChars
= stopChars_
;
83 bool AutoComplete::IsStopChar(char ch
) const noexcept
{
84 return ch
&& (stopChars
.find(ch
) != std::string::npos
);
87 void AutoComplete::SetFillUpChars(const char *fillUpChars_
) {
88 fillUpChars
= fillUpChars_
;
91 bool AutoComplete::IsFillUpChar(char ch
) const noexcept
{
92 return ch
&& (fillUpChars
.find(ch
) != std::string::npos
);
95 void AutoComplete::SetSeparator(char separator_
) {
96 separator
= separator_
;
99 char AutoComplete::GetSeparator() const noexcept
{
103 void AutoComplete::SetTypesep(char separator_
) {
104 typesep
= separator_
;
107 char AutoComplete::GetTypesep() const noexcept
{
114 std::vector
<int> indices
;
116 Sorter(AutoComplete
*ac_
, const char *list_
) : ac(ac_
), list(list_
) {
119 // Empty list has a single empty member
120 indices
.push_back(i
); // word start
121 indices
.push_back(i
); // word end
124 indices
.push_back(i
); // word start
125 while (list
[i
] != ac
->GetTypesep() && list
[i
] != ac
->GetSeparator() && list
[i
])
127 indices
.push_back(i
); // word end
128 if (list
[i
] == ac
->GetTypesep()) {
129 while (list
[i
] != ac
->GetSeparator() && list
[i
])
132 if (list
[i
] == ac
->GetSeparator()) {
134 // preserve trailing separator as blank entry
136 indices
.push_back(i
);
137 indices
.push_back(i
);
141 indices
.push_back(i
); // index of last position
144 bool operator()(int a
, int b
) noexcept
{
145 const int lenA
= indices
[a
* 2 + 1] - indices
[a
* 2];
146 const int lenB
= indices
[b
* 2 + 1] - indices
[b
* 2];
147 const int len
= std::min(lenA
, lenB
);
150 cmp
= CompareNCaseInsensitive(list
+ indices
[a
* 2], list
+ indices
[b
* 2], len
);
152 cmp
= strncmp(list
+ indices
[a
* 2], list
+ indices
[b
* 2], len
);
159 void AutoComplete::SetList(const char *list
) {
160 if (autoSort
== Ordering::PreSorted
) {
161 lb
->SetList(list
, separator
, typesep
);
163 for (int i
= 0; i
< lb
->Length(); ++i
)
164 sortMatrix
.push_back(i
);
168 Sorter
IndexSort(this, list
);
170 for (int i
= 0; i
< static_cast<int>(IndexSort
.indices
.size()) / 2; ++i
)
171 sortMatrix
.push_back(i
);
172 std::sort(sortMatrix
.begin(), sortMatrix
.end(), IndexSort
);
173 if (autoSort
== Ordering::Custom
|| sortMatrix
.size() < 2) {
174 lb
->SetList(list
, separator
, typesep
);
175 PLATFORM_ASSERT(lb
->Length() == static_cast<int>(sortMatrix
.size()));
179 std::string sortedList
;
180 char item
[maxItemLen
];
181 for (size_t i
= 0; i
< sortMatrix
.size(); ++i
) {
182 int wordLen
= IndexSort
.indices
[sortMatrix
[i
] * 2 + 2] - IndexSort
.indices
[sortMatrix
[i
] * 2];
183 if (wordLen
> maxItemLen
-2)
184 wordLen
= maxItemLen
- 2;
185 memcpy(item
, list
+ IndexSort
.indices
[sortMatrix
[i
] * 2], wordLen
);
186 if ((i
+1) == sortMatrix
.size()) {
187 // Last item so remove separator if present
188 if ((wordLen
> 0) && (item
[wordLen
-1] == separator
))
191 // Item before last needs a separator
192 if ((wordLen
== 0) || (item
[wordLen
-1] != separator
)) {
193 item
[wordLen
] = separator
;
197 item
[wordLen
] = '\0';
200 for (int i
= 0; i
< static_cast<int>(sortMatrix
.size()); ++i
)
202 lb
->SetList(sortedList
.c_str(), separator
, typesep
);
205 int AutoComplete::GetSelection() const {
206 return lb
->GetSelection();
209 std::string
AutoComplete::GetValue(int item
) const {
210 return lb
->GetValue(item
);
213 void AutoComplete::Show(bool show
) {
219 void AutoComplete::Cancel() noexcept
{
228 void AutoComplete::Move(int delta
) {
229 const int count
= lb
->Length();
230 int current
= lb
->GetSelection();
232 if (current
>= count
)
239 void AutoComplete::Select(const char *word
) {
240 const size_t lenWord
= strlen(word
);
242 int start
= 0; // lower bound of the api array block to search
243 int end
= lb
->Length() - 1; // upper bound of the api array block to search
244 while ((start
<= end
) && (location
== -1)) { // Binary searching loop
245 int pivot
= (start
+ end
) / 2;
246 std::string item
= GetValue(sortMatrix
[pivot
]);
249 cond
= CompareNCaseInsensitive(word
, item
.c_str(), lenWord
);
251 cond
= strncmp(word
, item
.c_str(), lenWord
);
254 while (pivot
> start
) {
255 item
= lb
->GetValue(sortMatrix
[pivot
-1]);
257 cond
= CompareNCaseInsensitive(word
, item
.c_str(), lenWord
);
259 cond
= strncmp(word
, item
.c_str(), lenWord
);
266 && ignoreCaseBehaviour
== CaseInsensitiveBehaviour::RespectCase
) {
267 // Check for exact-case match
268 for (; pivot
<= end
; pivot
++) {
269 item
= lb
->GetValue(sortMatrix
[pivot
]);
270 if (!strncmp(word
, item
.c_str(), lenWord
)) {
274 if (CompareNCaseInsensitive(word
, item
.c_str(), lenWord
))
278 } else if (cond
< 0) {
284 if (location
== -1) {
290 if (autoSort
== Ordering::Custom
) {
291 // Check for a logically earlier match
292 for (int i
= location
+ 1; i
<= end
; ++i
) {
293 std::string item
= lb
->GetValue(sortMatrix
[i
]);
294 if (CompareNCaseInsensitive(word
, item
.c_str(), lenWord
))
296 if (sortMatrix
[i
] < sortMatrix
[location
] && !strncmp(word
, item
.c_str(), lenWord
))
300 lb
->Select(sortMatrix
[location
]);