xref: /MusicPlayer2/scintilla/src/AutoComplete.cxx (revision 8af74909132ed5e696cb05b6689ae4baf14c1c96)
1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file AutoComplete.cxx
3*8af74909SZhong Yang  ** Defines the auto completion list box.
4*8af74909SZhong Yang  **/
5*8af74909SZhong Yang // Copyright 1998-2003 by Neil Hodgson <[email protected]>
6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
7*8af74909SZhong Yang 
8*8af74909SZhong Yang #include <cstddef>
9*8af74909SZhong Yang #include <cstdlib>
10*8af74909SZhong Yang #include <cassert>
11*8af74909SZhong Yang #include <cstring>
12*8af74909SZhong Yang #include <cstdio>
13*8af74909SZhong Yang 
14*8af74909SZhong Yang #include <stdexcept>
15*8af74909SZhong Yang #include <string>
16*8af74909SZhong Yang #include <string_view>
17*8af74909SZhong Yang #include <vector>
18*8af74909SZhong Yang #include <algorithm>
19*8af74909SZhong Yang #include <memory>
20*8af74909SZhong Yang 
21*8af74909SZhong Yang #include "Platform.h"
22*8af74909SZhong Yang 
23*8af74909SZhong Yang #include "Scintilla.h"
24*8af74909SZhong Yang #include "CharacterSet.h"
25*8af74909SZhong Yang #include "Position.h"
26*8af74909SZhong Yang #include "AutoComplete.h"
27*8af74909SZhong Yang 
28*8af74909SZhong Yang using namespace Scintilla;
29*8af74909SZhong Yang 
AutoComplete()30*8af74909SZhong Yang AutoComplete::AutoComplete() :
31*8af74909SZhong Yang 	active(false),
32*8af74909SZhong Yang 	separator(' '),
33*8af74909SZhong Yang 	typesep('?'),
34*8af74909SZhong Yang 	ignoreCase(false),
35*8af74909SZhong Yang 	chooseSingle(false),
36*8af74909SZhong Yang 	posStart(0),
37*8af74909SZhong Yang 	startLen(0),
38*8af74909SZhong Yang 	cancelAtStartPos(true),
39*8af74909SZhong Yang 	autoHide(true),
40*8af74909SZhong Yang 	dropRestOfWord(false),
41*8af74909SZhong Yang 	ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE),
42*8af74909SZhong Yang 	widthLBDefault(100),
43*8af74909SZhong Yang 	heightLBDefault(100),
44*8af74909SZhong Yang 	autoSort(SC_ORDER_PRESORTED) {
45*8af74909SZhong Yang 	lb.reset(ListBox::Allocate());
46*8af74909SZhong Yang }
47*8af74909SZhong Yang 
~AutoComplete()48*8af74909SZhong Yang AutoComplete::~AutoComplete() {
49*8af74909SZhong Yang 	if (lb) {
50*8af74909SZhong Yang 		lb->Destroy();
51*8af74909SZhong Yang 	}
52*8af74909SZhong Yang }
53*8af74909SZhong Yang 
Active() const54*8af74909SZhong Yang bool AutoComplete::Active() const noexcept {
55*8af74909SZhong Yang 	return active;
56*8af74909SZhong Yang }
57*8af74909SZhong Yang 
Start(Window & parent,int ctrlID,Sci::Position position,Point location,Sci::Position startLen_,int lineHeight,bool unicodeMode,int technology)58*8af74909SZhong Yang void AutoComplete::Start(Window &parent, int ctrlID,
59*8af74909SZhong Yang 	Sci::Position position, Point location, Sci::Position startLen_,
60*8af74909SZhong Yang 	int lineHeight, bool unicodeMode, int technology) {
61*8af74909SZhong Yang 	if (active) {
62*8af74909SZhong Yang 		Cancel();
63*8af74909SZhong Yang 	}
64*8af74909SZhong Yang 	lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology);
65*8af74909SZhong Yang 	lb->Clear();
66*8af74909SZhong Yang 	active = true;
67*8af74909SZhong Yang 	startLen = startLen_;
68*8af74909SZhong Yang 	posStart = position;
69*8af74909SZhong Yang }
70*8af74909SZhong Yang 
SetStopChars(const char * stopChars_)71*8af74909SZhong Yang void AutoComplete::SetStopChars(const char *stopChars_) {
72*8af74909SZhong Yang 	stopChars = stopChars_;
73*8af74909SZhong Yang }
74*8af74909SZhong Yang 
IsStopChar(char ch) const75*8af74909SZhong Yang bool AutoComplete::IsStopChar(char ch) const noexcept {
76*8af74909SZhong Yang 	return ch && (stopChars.find(ch) != std::string::npos);
77*8af74909SZhong Yang }
78*8af74909SZhong Yang 
SetFillUpChars(const char * fillUpChars_)79*8af74909SZhong Yang void AutoComplete::SetFillUpChars(const char *fillUpChars_) {
80*8af74909SZhong Yang 	fillUpChars = fillUpChars_;
81*8af74909SZhong Yang }
82*8af74909SZhong Yang 
IsFillUpChar(char ch) const83*8af74909SZhong Yang bool AutoComplete::IsFillUpChar(char ch) const noexcept {
84*8af74909SZhong Yang 	return ch && (fillUpChars.find(ch) != std::string::npos);
85*8af74909SZhong Yang }
86*8af74909SZhong Yang 
SetSeparator(char separator_)87*8af74909SZhong Yang void AutoComplete::SetSeparator(char separator_) {
88*8af74909SZhong Yang 	separator = separator_;
89*8af74909SZhong Yang }
90*8af74909SZhong Yang 
GetSeparator() const91*8af74909SZhong Yang char AutoComplete::GetSeparator() const noexcept {
92*8af74909SZhong Yang 	return separator;
93*8af74909SZhong Yang }
94*8af74909SZhong Yang 
SetTypesep(char separator_)95*8af74909SZhong Yang void AutoComplete::SetTypesep(char separator_) {
96*8af74909SZhong Yang 	typesep = separator_;
97*8af74909SZhong Yang }
98*8af74909SZhong Yang 
GetTypesep() const99*8af74909SZhong Yang char AutoComplete::GetTypesep() const noexcept {
100*8af74909SZhong Yang 	return typesep;
101*8af74909SZhong Yang }
102*8af74909SZhong Yang 
103*8af74909SZhong Yang struct Sorter {
104*8af74909SZhong Yang 	AutoComplete *ac;
105*8af74909SZhong Yang 	const char *list;
106*8af74909SZhong Yang 	std::vector<int> indices;
107*8af74909SZhong Yang 
SorterSorter108*8af74909SZhong Yang 	Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
109*8af74909SZhong Yang 		int i = 0;
110*8af74909SZhong Yang 		while (list[i]) {
111*8af74909SZhong Yang 			indices.push_back(i); // word start
112*8af74909SZhong Yang 			while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
113*8af74909SZhong Yang 				++i;
114*8af74909SZhong Yang 			indices.push_back(i); // word end
115*8af74909SZhong Yang 			if (list[i] == ac->GetTypesep()) {
116*8af74909SZhong Yang 				while (list[i] != ac->GetSeparator() && list[i])
117*8af74909SZhong Yang 					++i;
118*8af74909SZhong Yang 			}
119*8af74909SZhong Yang 			if (list[i] == ac->GetSeparator()) {
120*8af74909SZhong Yang 				++i;
121*8af74909SZhong Yang 				// preserve trailing separator as blank entry
122*8af74909SZhong Yang 				if (!list[i]) {
123*8af74909SZhong Yang 					indices.push_back(i);
124*8af74909SZhong Yang 					indices.push_back(i);
125*8af74909SZhong Yang 				}
126*8af74909SZhong Yang 			}
127*8af74909SZhong Yang 		}
128*8af74909SZhong Yang 		indices.push_back(i); // index of last position
129*8af74909SZhong Yang 	}
130*8af74909SZhong Yang 
operator ()Sorter131*8af74909SZhong Yang 	bool operator()(int a, int b) {
132*8af74909SZhong Yang 		const int lenA = indices[a * 2 + 1] - indices[a * 2];
133*8af74909SZhong Yang 		const int lenB = indices[b * 2 + 1] - indices[b * 2];
134*8af74909SZhong Yang 		const int len  = std::min(lenA, lenB);
135*8af74909SZhong Yang 		int cmp;
136*8af74909SZhong Yang 		if (ac->ignoreCase)
137*8af74909SZhong Yang 			cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
138*8af74909SZhong Yang 		else
139*8af74909SZhong Yang 			cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
140*8af74909SZhong Yang 		if (cmp == 0)
141*8af74909SZhong Yang 			cmp = lenA - lenB;
142*8af74909SZhong Yang 		return cmp < 0;
143*8af74909SZhong Yang 	}
144*8af74909SZhong Yang };
145*8af74909SZhong Yang 
SetList(const char * list)146*8af74909SZhong Yang void AutoComplete::SetList(const char *list) {
147*8af74909SZhong Yang 	if (autoSort == SC_ORDER_PRESORTED) {
148*8af74909SZhong Yang 		lb->SetList(list, separator, typesep);
149*8af74909SZhong Yang 		sortMatrix.clear();
150*8af74909SZhong Yang 		for (int i = 0; i < lb->Length(); ++i)
151*8af74909SZhong Yang 			sortMatrix.push_back(i);
152*8af74909SZhong Yang 		return;
153*8af74909SZhong Yang 	}
154*8af74909SZhong Yang 
155*8af74909SZhong Yang 	Sorter IndexSort(this, list);
156*8af74909SZhong Yang 	sortMatrix.clear();
157*8af74909SZhong Yang 	for (int i = 0; i < static_cast<int>(IndexSort.indices.size()) / 2; ++i)
158*8af74909SZhong Yang 		sortMatrix.push_back(i);
159*8af74909SZhong Yang 	std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort);
160*8af74909SZhong Yang 	if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) {
161*8af74909SZhong Yang 		lb->SetList(list, separator, typesep);
162*8af74909SZhong Yang 		PLATFORM_ASSERT(lb->Length() == static_cast<int>(sortMatrix.size()));
163*8af74909SZhong Yang 		return;
164*8af74909SZhong Yang 	}
165*8af74909SZhong Yang 
166*8af74909SZhong Yang 	std::string sortedList;
167*8af74909SZhong Yang 	char item[maxItemLen];
168*8af74909SZhong Yang 	for (size_t i = 0; i < sortMatrix.size(); ++i) {
169*8af74909SZhong Yang 		int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2];
170*8af74909SZhong Yang 		if (wordLen > maxItemLen-2)
171*8af74909SZhong Yang 			wordLen = maxItemLen - 2;
172*8af74909SZhong Yang 		memcpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
173*8af74909SZhong Yang 		if ((i+1) == sortMatrix.size()) {
174*8af74909SZhong Yang 			// Last item so remove separator if present
175*8af74909SZhong Yang 			if ((wordLen > 0) && (item[wordLen-1] == separator))
176*8af74909SZhong Yang 				wordLen--;
177*8af74909SZhong Yang 		} else {
178*8af74909SZhong Yang 			// Item before last needs a separator
179*8af74909SZhong Yang 			if ((wordLen == 0) || (item[wordLen-1] != separator)) {
180*8af74909SZhong Yang 				item[wordLen] = separator;
181*8af74909SZhong Yang 				wordLen++;
182*8af74909SZhong Yang 			}
183*8af74909SZhong Yang 		}
184*8af74909SZhong Yang 		item[wordLen] = '\0';
185*8af74909SZhong Yang 		sortedList += item;
186*8af74909SZhong Yang 	}
187*8af74909SZhong Yang 	for (int i = 0; i < static_cast<int>(sortMatrix.size()); ++i)
188*8af74909SZhong Yang 		sortMatrix[i] = i;
189*8af74909SZhong Yang 	lb->SetList(sortedList.c_str(), separator, typesep);
190*8af74909SZhong Yang }
191*8af74909SZhong Yang 
GetSelection() const192*8af74909SZhong Yang int AutoComplete::GetSelection() const {
193*8af74909SZhong Yang 	return lb->GetSelection();
194*8af74909SZhong Yang }
195*8af74909SZhong Yang 
GetValue(int item) const196*8af74909SZhong Yang std::string AutoComplete::GetValue(int item) const {
197*8af74909SZhong Yang 	char value[maxItemLen];
198*8af74909SZhong Yang 	lb->GetValue(item, value, sizeof(value));
199*8af74909SZhong Yang 	return std::string(value);
200*8af74909SZhong Yang }
201*8af74909SZhong Yang 
Show(bool show)202*8af74909SZhong Yang void AutoComplete::Show(bool show) {
203*8af74909SZhong Yang 	lb->Show(show);
204*8af74909SZhong Yang 	if (show)
205*8af74909SZhong Yang 		lb->Select(0);
206*8af74909SZhong Yang }
207*8af74909SZhong Yang 
Cancel()208*8af74909SZhong Yang void AutoComplete::Cancel() {
209*8af74909SZhong Yang 	if (lb->Created()) {
210*8af74909SZhong Yang 		lb->Clear();
211*8af74909SZhong Yang 		lb->Destroy();
212*8af74909SZhong Yang 		active = false;
213*8af74909SZhong Yang 	}
214*8af74909SZhong Yang }
215*8af74909SZhong Yang 
216*8af74909SZhong Yang 
Move(int delta)217*8af74909SZhong Yang void AutoComplete::Move(int delta) {
218*8af74909SZhong Yang 	const int count = lb->Length();
219*8af74909SZhong Yang 	int current = lb->GetSelection();
220*8af74909SZhong Yang 	current += delta;
221*8af74909SZhong Yang 	if (current >= count)
222*8af74909SZhong Yang 		current = count - 1;
223*8af74909SZhong Yang 	if (current < 0)
224*8af74909SZhong Yang 		current = 0;
225*8af74909SZhong Yang 	lb->Select(current);
226*8af74909SZhong Yang }
227*8af74909SZhong Yang 
Select(const char * word)228*8af74909SZhong Yang void AutoComplete::Select(const char *word) {
229*8af74909SZhong Yang 	const size_t lenWord = strlen(word);
230*8af74909SZhong Yang 	int location = -1;
231*8af74909SZhong Yang 	int start = 0; // lower bound of the api array block to search
232*8af74909SZhong Yang 	int end = lb->Length() - 1; // upper bound of the api array block to search
233*8af74909SZhong Yang 	while ((start <= end) && (location == -1)) { // Binary searching loop
234*8af74909SZhong Yang 		int pivot = (start + end) / 2;
235*8af74909SZhong Yang 		char item[maxItemLen];
236*8af74909SZhong Yang 		lb->GetValue(sortMatrix[pivot], item, maxItemLen);
237*8af74909SZhong Yang 		int cond;
238*8af74909SZhong Yang 		if (ignoreCase)
239*8af74909SZhong Yang 			cond = CompareNCaseInsensitive(word, item, lenWord);
240*8af74909SZhong Yang 		else
241*8af74909SZhong Yang 			cond = strncmp(word, item, lenWord);
242*8af74909SZhong Yang 		if (!cond) {
243*8af74909SZhong Yang 			// Find first match
244*8af74909SZhong Yang 			while (pivot > start) {
245*8af74909SZhong Yang 				lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
246*8af74909SZhong Yang 				if (ignoreCase)
247*8af74909SZhong Yang 					cond = CompareNCaseInsensitive(word, item, lenWord);
248*8af74909SZhong Yang 				else
249*8af74909SZhong Yang 					cond = strncmp(word, item, lenWord);
250*8af74909SZhong Yang 				if (0 != cond)
251*8af74909SZhong Yang 					break;
252*8af74909SZhong Yang 				--pivot;
253*8af74909SZhong Yang 			}
254*8af74909SZhong Yang 			location = pivot;
255*8af74909SZhong Yang 			if (ignoreCase
256*8af74909SZhong Yang 				&& ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
257*8af74909SZhong Yang 				// Check for exact-case match
258*8af74909SZhong Yang 				for (; pivot <= end; pivot++) {
259*8af74909SZhong Yang 					lb->GetValue(sortMatrix[pivot], item, maxItemLen);
260*8af74909SZhong Yang 					if (!strncmp(word, item, lenWord)) {
261*8af74909SZhong Yang 						location = pivot;
262*8af74909SZhong Yang 						break;
263*8af74909SZhong Yang 					}
264*8af74909SZhong Yang 					if (CompareNCaseInsensitive(word, item, lenWord))
265*8af74909SZhong Yang 						break;
266*8af74909SZhong Yang 				}
267*8af74909SZhong Yang 			}
268*8af74909SZhong Yang 		} else if (cond < 0) {
269*8af74909SZhong Yang 			end = pivot - 1;
270*8af74909SZhong Yang 		} else if (cond > 0) {
271*8af74909SZhong Yang 			start = pivot + 1;
272*8af74909SZhong Yang 		}
273*8af74909SZhong Yang 	}
274*8af74909SZhong Yang 	if (location == -1) {
275*8af74909SZhong Yang 		if (autoHide)
276*8af74909SZhong Yang 			Cancel();
277*8af74909SZhong Yang 		else
278*8af74909SZhong Yang 			lb->Select(-1);
279*8af74909SZhong Yang 	} else {
280*8af74909SZhong Yang 		if (autoSort == SC_ORDER_CUSTOM) {
281*8af74909SZhong Yang 			// Check for a logically earlier match
282*8af74909SZhong Yang 			char item[maxItemLen];
283*8af74909SZhong Yang 			for (int i = location + 1; i <= end; ++i) {
284*8af74909SZhong Yang 				lb->GetValue(sortMatrix[i], item, maxItemLen);
285*8af74909SZhong Yang 				if (CompareNCaseInsensitive(word, item, lenWord))
286*8af74909SZhong Yang 					break;
287*8af74909SZhong Yang 				if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
288*8af74909SZhong Yang 					location = i;
289*8af74909SZhong Yang 			}
290*8af74909SZhong Yang 		}
291*8af74909SZhong Yang 		lb->Select(sortMatrix[location]);
292*8af74909SZhong Yang 	}
293*8af74909SZhong Yang }
294*8af74909SZhong Yang 
295