Update Scintilla to version 3.4.4
[TortoiseGit.git] / ext / scintilla / src / AutoComplete.cxx
blob3ee8d15653705447f852346f37bb6e8bdc066204
1 // Scintilla source code edit control
2 /** @file AutoComplete.cxx
3 ** Defines the auto completion list box.
4 **/
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.
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <assert.h>
13 #include <string>
14 #include <vector>
15 #include <algorithm>
17 #include "Platform.h"
19 #include "Scintilla.h"
20 #include "CharacterSet.h"
21 #include "AutoComplete.h"
23 #ifdef SCI_NAMESPACE
24 using namespace Scintilla;
25 #endif
27 AutoComplete::AutoComplete() :
28 active(false),
29 separator(' '),
30 typesep('?'),
31 ignoreCase(false),
32 chooseSingle(false),
33 lb(0),
34 posStart(0),
35 startLen(0),
36 cancelAtStartPos(true),
37 autoHide(true),
38 dropRestOfWord(false),
39 ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE),
40 widthLBDefault(100),
41 heightLBDefault(100),
42 autoSort(SC_ORDER_PRESORTED) {
43 lb = ListBox::Allocate();
46 AutoComplete::~AutoComplete() {
47 if (lb) {
48 lb->Destroy();
49 delete lb;
50 lb = 0;
54 bool AutoComplete::Active() const {
55 return active;
58 void AutoComplete::Start(Window &parent, int ctrlID,
59 int position, Point location, int startLen_,
60 int lineHeight, bool unicodeMode, int technology) {
61 if (active) {
62 Cancel();
64 lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology);
65 lb->Clear();
66 active = true;
67 startLen = startLen_;
68 posStart = position;
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 {
92 return separator;
95 void AutoComplete::SetTypesep(char separator_) {
96 typesep = separator_;
99 char AutoComplete::GetTypesep() const {
100 return typesep;
103 struct Sorter {
104 AutoComplete *ac;
105 const char *list;
106 std::vector<int> indices;
108 Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
109 int i = 0;
110 while (list[i]) {
111 indices.push_back(i); // word start
112 while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
113 ++i;
114 indices.push_back(i); // word end
115 if (list[i] == ac->GetTypesep()) {
116 while (list[i] != ac->GetSeparator() && list[i])
117 ++i;
119 if (list[i] == ac->GetSeparator()) {
120 ++i;
121 // preserve trailing separator as blank entry
122 if (!list[i]) {
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);
135 int cmp;
136 if (ac->ignoreCase)
137 cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
138 else
139 cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
140 if (cmp == 0)
141 cmp = lenA - lenB;
142 return cmp < 0;
146 void AutoComplete::SetList(const char *list) {
147 if (autoSort == SC_ORDER_PRESORTED) {
148 lb->SetList(list, separator, typesep);
149 sortMatrix.clear();
150 for (int i = 0; i < lb->Length(); ++i)
151 sortMatrix.push_back(i);
152 return;
155 Sorter IndexSort(this, list);
156 sortMatrix.clear();
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()));
163 return;
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 strncpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
171 if ((i+1) == sortMatrix.size()) {
172 // Last item so remove separator if present
173 if ((wordLen > 0) && (item[wordLen-1] == separator))
174 wordLen--;
175 } else {
176 // Item before last needs a separator
177 if ((wordLen == 0) || (item[wordLen-1] != separator)) {
178 item[wordLen] = separator;
179 wordLen++;
182 item[wordLen] = '\0';
183 sortedList += item;
185 for (int i = 0; i < (int)sortMatrix.size(); ++i)
186 sortMatrix[i] = i;
187 lb->SetList(sortedList.c_str(), separator, typesep);
190 int AutoComplete::GetSelection() const {
191 return lb->GetSelection();
194 std::string AutoComplete::GetValue(int item) const {
195 char value[maxItemLen];
196 lb->GetValue(item, value, sizeof(value));
197 return std::string(value);
200 void AutoComplete::Show(bool show) {
201 lb->Show(show);
202 if (show)
203 lb->Select(0);
206 void AutoComplete::Cancel() {
207 if (lb->Created()) {
208 lb->Clear();
209 lb->Destroy();
210 active = false;
215 void AutoComplete::Move(int delta) {
216 int count = lb->Length();
217 int current = lb->GetSelection();
218 current += delta;
219 if (current >= count)
220 current = count - 1;
221 if (current < 0)
222 current = 0;
223 lb->Select(current);
226 void AutoComplete::Select(const char *word) {
227 size_t lenWord = strlen(word);
228 int location = -1;
229 int start = 0; // lower bound of the api array block to search
230 int end = lb->Length() - 1; // upper bound of the api array block to search
231 while ((start <= end) && (location == -1)) { // Binary searching loop
232 int pivot = (start + end) / 2;
233 char item[maxItemLen];
234 lb->GetValue(sortMatrix[pivot], item, maxItemLen);
235 int cond;
236 if (ignoreCase)
237 cond = CompareNCaseInsensitive(word, item, lenWord);
238 else
239 cond = strncmp(word, item, lenWord);
240 if (!cond) {
241 // Find first match
242 while (pivot > start) {
243 lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
244 if (ignoreCase)
245 cond = CompareNCaseInsensitive(word, item, lenWord);
246 else
247 cond = strncmp(word, item, lenWord);
248 if (0 != cond)
249 break;
250 --pivot;
252 location = pivot;
253 if (ignoreCase
254 && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
255 // Check for exact-case match
256 for (; pivot <= end; pivot++) {
257 lb->GetValue(sortMatrix[pivot], item, maxItemLen);
258 if (!strncmp(word, item, lenWord)) {
259 location = pivot;
260 break;
262 if (CompareNCaseInsensitive(word, item, lenWord))
263 break;
266 } else if (cond < 0) {
267 end = pivot - 1;
268 } else if (cond > 0) {
269 start = pivot + 1;
272 if (location == -1) {
273 if (autoHide)
274 Cancel();
275 else
276 lb->Select(-1);
277 } else {
278 if (autoSort == SC_ORDER_CUSTOM) {
279 // Check for a logically earlier match
280 char item[maxItemLen];
281 for (int i = location + 1; i <= end; ++i) {
282 lb->GetValue(sortMatrix[i], item, maxItemLen);
283 if (CompareNCaseInsensitive(word, item, lenWord))
284 break;
285 if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
286 location = i;
289 lb->Select(sortMatrix[location]);