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.
19 #include "Scintilla.h"
20 #include "CharacterSet.h"
21 #include "AutoComplete.h"
24 using namespace Scintilla
;
27 AutoComplete::AutoComplete() :
36 cancelAtStartPos(true),
38 dropRestOfWord(false),
39 ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE
),
42 autoSort(SC_ORDER_PRESORTED
) {
43 lb
= ListBox::Allocate();
46 AutoComplete::~AutoComplete() {
54 bool AutoComplete::Active() const {
58 void AutoComplete::Start(Window
&parent
, int ctrlID
,
59 int position
, Point location
, int startLen_
,
60 int lineHeight
, bool unicodeMode
, int technology
) {
64 lb
->Create(parent
, ctrlID
, location
, lineHeight
, unicodeMode
, technology
);
71 void AutoComplete::SetStopChars(const char *stopChars_
) {
72 stopChars
= stopChars_
;
75 bool AutoComplete::IsStopChar(char ch
) {
76 return ch
&& (stopChars
.find(ch
) != std::string::npos
);
79 void AutoComplete::SetFillUpChars(const char *fillUpChars_
) {
80 fillUpChars
= fillUpChars_
;
83 bool AutoComplete::IsFillUpChar(char ch
) {
84 return ch
&& (fillUpChars
.find(ch
) != std::string::npos
);
87 void AutoComplete::SetSeparator(char separator_
) {
88 separator
= separator_
;
91 char AutoComplete::GetSeparator() const {
95 void AutoComplete::SetTypesep(char separator_
) {
99 char AutoComplete::GetTypesep() const {
106 std::vector
<int> indices
;
108 Sorter(AutoComplete
*ac_
, const char *list_
) : ac(ac_
), list(list_
) {
111 indices
.push_back(i
); // word start
112 while (list
[i
] != ac
->GetTypesep() && list
[i
] != ac
->GetSeparator() && list
[i
])
114 indices
.push_back(i
); // word end
115 if (list
[i
] == ac
->GetTypesep()) {
116 while (list
[i
] != ac
->GetSeparator() && list
[i
])
119 if (list
[i
] == ac
->GetSeparator()) {
121 // preserve trailing separator as blank entry
123 indices
.push_back(i
);
124 indices
.push_back(i
);
128 indices
.push_back(i
); // index of last position
131 bool operator()(int a
, int b
) {
132 int lenA
= indices
[a
* 2 + 1] - indices
[a
* 2];
133 int lenB
= indices
[b
* 2 + 1] - indices
[b
* 2];
134 int len
= std::min(lenA
, lenB
);
137 cmp
= CompareNCaseInsensitive(list
+ indices
[a
* 2], list
+ indices
[b
* 2], len
);
139 cmp
= strncmp(list
+ indices
[a
* 2], list
+ indices
[b
* 2], len
);
146 void AutoComplete::SetList(const char *list
) {
147 if (autoSort
== SC_ORDER_PRESORTED
) {
148 lb
->SetList(list
, separator
, typesep
);
150 for (int i
= 0; i
< lb
->Length(); ++i
)
151 sortMatrix
.push_back(i
);
155 Sorter
IndexSort(this, list
);
157 for (int i
= 0; i
< (int)IndexSort
.indices
.size() / 2; ++i
)
158 sortMatrix
.push_back(i
);
159 std::sort(sortMatrix
.begin(), sortMatrix
.end(), IndexSort
);
160 if (autoSort
== SC_ORDER_CUSTOM
|| sortMatrix
.size() < 2) {
161 lb
->SetList(list
, separator
, typesep
);
162 PLATFORM_ASSERT(lb
->Length() == static_cast<int>(sortMatrix
.size()));
166 std::string sortedList
;
167 char item
[maxItemLen
];
168 for (size_t i
= 0; i
< sortMatrix
.size(); ++i
) {
169 int wordLen
= IndexSort
.indices
[sortMatrix
[i
] * 2 + 2] - IndexSort
.indices
[sortMatrix
[i
] * 2];
170 if (wordLen
> maxItemLen
-2)
171 wordLen
= maxItemLen
- 2;
172 memcpy(item
, list
+ IndexSort
.indices
[sortMatrix
[i
] * 2], wordLen
);
173 if ((i
+1) == sortMatrix
.size()) {
174 // Last item so remove separator if present
175 if ((wordLen
> 0) && (item
[wordLen
-1] == separator
))
178 // Item before last needs a separator
179 if ((wordLen
== 0) || (item
[wordLen
-1] != separator
)) {
180 item
[wordLen
] = separator
;
184 item
[wordLen
] = '\0';
187 for (int i
= 0; i
< (int)sortMatrix
.size(); ++i
)
189 lb
->SetList(sortedList
.c_str(), separator
, typesep
);
192 int AutoComplete::GetSelection() const {
193 return lb
->GetSelection();
196 std::string
AutoComplete::GetValue(int item
) const {
197 char value
[maxItemLen
];
198 lb
->GetValue(item
, value
, sizeof(value
));
199 return std::string(value
);
202 void AutoComplete::Show(bool show
) {
208 void AutoComplete::Cancel() {
217 void AutoComplete::Move(int delta
) {
218 int count
= lb
->Length();
219 int current
= lb
->GetSelection();
221 if (current
>= count
)
228 void AutoComplete::Select(const char *word
) {
229 size_t lenWord
= strlen(word
);
231 int start
= 0; // lower bound of the api array block to search
232 int end
= lb
->Length() - 1; // upper bound of the api array block to search
233 while ((start
<= end
) && (location
== -1)) { // Binary searching loop
234 int pivot
= (start
+ end
) / 2;
235 char item
[maxItemLen
];
236 lb
->GetValue(sortMatrix
[pivot
], item
, maxItemLen
);
239 cond
= CompareNCaseInsensitive(word
, item
, lenWord
);
241 cond
= strncmp(word
, item
, lenWord
);
244 while (pivot
> start
) {
245 lb
->GetValue(sortMatrix
[pivot
-1], item
, maxItemLen
);
247 cond
= CompareNCaseInsensitive(word
, item
, lenWord
);
249 cond
= strncmp(word
, item
, lenWord
);
256 && ignoreCaseBehaviour
== SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE
) {
257 // Check for exact-case match
258 for (; pivot
<= end
; pivot
++) {
259 lb
->GetValue(sortMatrix
[pivot
], item
, maxItemLen
);
260 if (!strncmp(word
, item
, lenWord
)) {
264 if (CompareNCaseInsensitive(word
, item
, lenWord
))
268 } else if (cond
< 0) {
270 } else if (cond
> 0) {
274 if (location
== -1) {
280 if (autoSort
== SC_ORDER_CUSTOM
) {
281 // Check for a logically earlier match
282 char item
[maxItemLen
];
283 for (int i
= location
+ 1; i
<= end
; ++i
) {
284 lb
->GetValue(sortMatrix
[i
], item
, maxItemLen
);
285 if (CompareNCaseInsensitive(word
, item
, lenWord
))
287 if (sortMatrix
[i
] < sortMatrix
[location
] && !strncmp(word
, item
, lenWord
))
291 lb
->Select(sortMatrix
[location
]);