Merge pull request #826 from kugel-/doxygen-fixes2
[geany-mirror.git] / scintilla / src / AutoComplete.cxx
blob3f3570283cf16ac4c9b1451193bb3deb2a564912
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 <stdexcept>
14 #include <string>
15 #include <vector>
16 #include <algorithm>
18 #include "Platform.h"
20 #include "Scintilla.h"
21 #include "CharacterSet.h"
22 #include "Position.h"
23 #include "AutoComplete.h"
25 #ifdef SCI_NAMESPACE
26 using namespace Scintilla;
27 #endif
29 AutoComplete::AutoComplete() :
30 active(false),
31 separator(' '),
32 typesep('?'),
33 ignoreCase(false),
34 chooseSingle(false),
35 lb(0),
36 posStart(0),
37 startLen(0),
38 cancelAtStartPos(true),
39 autoHide(true),
40 dropRestOfWord(false),
41 ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE),
42 widthLBDefault(100),
43 heightLBDefault(100),
44 autoSort(SC_ORDER_PRESORTED) {
45 lb = ListBox::Allocate();
48 AutoComplete::~AutoComplete() {
49 if (lb) {
50 lb->Destroy();
51 delete lb;
52 lb = 0;
56 bool AutoComplete::Active() const {
57 return active;
60 void AutoComplete::Start(Window &parent, int ctrlID,
61 int position, Point location, int startLen_,
62 int lineHeight, bool unicodeMode, int technology) {
63 if (active) {
64 Cancel();
66 lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology);
67 lb->Clear();
68 active = true;
69 startLen = startLen_;
70 posStart = position;
73 void AutoComplete::SetStopChars(const char *stopChars_) {
74 stopChars = stopChars_;
77 bool AutoComplete::IsStopChar(char ch) {
78 return ch && (stopChars.find(ch) != std::string::npos);
81 void AutoComplete::SetFillUpChars(const char *fillUpChars_) {
82 fillUpChars = fillUpChars_;
85 bool AutoComplete::IsFillUpChar(char ch) {
86 return ch && (fillUpChars.find(ch) != std::string::npos);
89 void AutoComplete::SetSeparator(char separator_) {
90 separator = separator_;
93 char AutoComplete::GetSeparator() const {
94 return separator;
97 void AutoComplete::SetTypesep(char separator_) {
98 typesep = separator_;
101 char AutoComplete::GetTypesep() const {
102 return typesep;
105 struct Sorter {
106 AutoComplete *ac;
107 const char *list;
108 std::vector<int> indices;
110 Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
111 int i = 0;
112 while (list[i]) {
113 indices.push_back(i); // word start
114 while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
115 ++i;
116 indices.push_back(i); // word end
117 if (list[i] == ac->GetTypesep()) {
118 while (list[i] != ac->GetSeparator() && list[i])
119 ++i;
121 if (list[i] == ac->GetSeparator()) {
122 ++i;
123 // preserve trailing separator as blank entry
124 if (!list[i]) {
125 indices.push_back(i);
126 indices.push_back(i);
130 indices.push_back(i); // index of last position
133 bool operator()(int a, int b) {
134 int lenA = indices[a * 2 + 1] - indices[a * 2];
135 int lenB = indices[b * 2 + 1] - indices[b * 2];
136 int len = std::min(lenA, lenB);
137 int cmp;
138 if (ac->ignoreCase)
139 cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
140 else
141 cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
142 if (cmp == 0)
143 cmp = lenA - lenB;
144 return cmp < 0;
148 void AutoComplete::SetList(const char *list) {
149 if (autoSort == SC_ORDER_PRESORTED) {
150 lb->SetList(list, separator, typesep);
151 sortMatrix.clear();
152 for (int i = 0; i < lb->Length(); ++i)
153 sortMatrix.push_back(i);
154 return;
157 Sorter IndexSort(this, list);
158 sortMatrix.clear();
159 for (int i = 0; i < (int)IndexSort.indices.size() / 2; ++i)
160 sortMatrix.push_back(i);
161 std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort);
162 if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) {
163 lb->SetList(list, separator, typesep);
164 PLATFORM_ASSERT(lb->Length() == static_cast<int>(sortMatrix.size()));
165 return;
168 std::string sortedList;
169 char item[maxItemLen];
170 for (size_t i = 0; i < sortMatrix.size(); ++i) {
171 int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2];
172 if (wordLen > maxItemLen-2)
173 wordLen = maxItemLen - 2;
174 memcpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
175 if ((i+1) == sortMatrix.size()) {
176 // Last item so remove separator if present
177 if ((wordLen > 0) && (item[wordLen-1] == separator))
178 wordLen--;
179 } else {
180 // Item before last needs a separator
181 if ((wordLen == 0) || (item[wordLen-1] != separator)) {
182 item[wordLen] = separator;
183 wordLen++;
186 item[wordLen] = '\0';
187 sortedList += item;
189 for (int i = 0; i < (int)sortMatrix.size(); ++i)
190 sortMatrix[i] = i;
191 lb->SetList(sortedList.c_str(), separator, typesep);
194 int AutoComplete::GetSelection() const {
195 return lb->GetSelection();
198 std::string AutoComplete::GetValue(int item) const {
199 char value[maxItemLen];
200 lb->GetValue(item, value, sizeof(value));
201 return std::string(value);
204 void AutoComplete::Show(bool show) {
205 lb->Show(show);
206 if (show)
207 lb->Select(0);
210 void AutoComplete::Cancel() {
211 if (lb->Created()) {
212 lb->Clear();
213 lb->Destroy();
214 active = false;
219 void AutoComplete::Move(int delta) {
220 int count = lb->Length();
221 int current = lb->GetSelection();
222 current += delta;
223 if (current >= count)
224 current = count - 1;
225 if (current < 0)
226 current = 0;
227 lb->Select(current);
230 void AutoComplete::Select(const char *word) {
231 size_t lenWord = strlen(word);
232 int location = -1;
233 int start = 0; // lower bound of the api array block to search
234 int end = lb->Length() - 1; // upper bound of the api array block to search
235 while ((start <= end) && (location == -1)) { // Binary searching loop
236 int pivot = (start + end) / 2;
237 char item[maxItemLen];
238 lb->GetValue(sortMatrix[pivot], item, maxItemLen);
239 int cond;
240 if (ignoreCase)
241 cond = CompareNCaseInsensitive(word, item, lenWord);
242 else
243 cond = strncmp(word, item, lenWord);
244 if (!cond) {
245 // Find first match
246 while (pivot > start) {
247 lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
248 if (ignoreCase)
249 cond = CompareNCaseInsensitive(word, item, lenWord);
250 else
251 cond = strncmp(word, item, lenWord);
252 if (0 != cond)
253 break;
254 --pivot;
256 location = pivot;
257 if (ignoreCase
258 && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
259 // Check for exact-case match
260 for (; pivot <= end; pivot++) {
261 lb->GetValue(sortMatrix[pivot], item, maxItemLen);
262 if (!strncmp(word, item, lenWord)) {
263 location = pivot;
264 break;
266 if (CompareNCaseInsensitive(word, item, lenWord))
267 break;
270 } else if (cond < 0) {
271 end = pivot - 1;
272 } else if (cond > 0) {
273 start = pivot + 1;
276 if (location == -1) {
277 if (autoHide)
278 Cancel();
279 else
280 lb->Select(-1);
281 } else {
282 if (autoSort == SC_ORDER_CUSTOM) {
283 // Check for a logically earlier match
284 char item[maxItemLen];
285 for (int i = location + 1; i <= end; ++i) {
286 lb->GetValue(sortMatrix[i], item, maxItemLen);
287 if (CompareNCaseInsensitive(word, item, lenWord))
288 break;
289 if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
290 location = i;
293 lb->Select(sortMatrix[location]);