diff options
author | nyamatongwe <devnull@localhost> | 2013-04-01 14:25:49 +1100 |
---|---|---|
committer | nyamatongwe <devnull@localhost> | 2013-04-01 14:25:49 +1100 |
commit | 3b9151f20a26c69428590bedab0270fedf334db8 (patch) | |
tree | fc18e116270dcabf429b4367be166fd28826b156 /src | |
parent | 6076715f3edf19f4897d910e6ddb7a032f4d17c6 (diff) | |
download | scintilla-mirror-3b9151f20a26c69428590bedab0270fedf334db8.tar.gz |
Feature [#981]. Added autocompletion order property to allow list to be ordered
according to container preference but still allowing selection by typing.
From Alpha.
Diffstat (limited to 'src')
-rw-r--r-- | src/AutoComplete.cxx | 119 | ||||
-rw-r--r-- | src/AutoComplete.h | 6 | ||||
-rw-r--r-- | src/ScintillaBase.cxx | 7 |
3 files changed, 123 insertions, 9 deletions
diff --git a/src/AutoComplete.cxx b/src/AutoComplete.cxx index bab123a99..d55af8504 100644 --- a/src/AutoComplete.cxx +++ b/src/AutoComplete.cxx @@ -10,7 +10,9 @@ #include <stdio.h> #include <assert.h> +#include <algorithm> #include <string> +#include <vector> #include "Platform.h" @@ -36,7 +38,8 @@ AutoComplete::AutoComplete() : dropRestOfWord(false), ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE), widthLBDefault(100), - heightLBDefault(100) { + heightLBDefault(100), + autoSort(SC_ORDER_PRESORTED) { lb = ListBox::Allocate(); stopChars[0] = '\0'; fillUpChars[0] = '\0'; @@ -101,8 +104,91 @@ char AutoComplete::GetTypesep() const { return typesep; } +struct Sorter { + AutoComplete *ac; + const char *list; + std::vector<int> indices; + + Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) { + int i = 0; + while (list[i]) { + indices.push_back(i); // word start + while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i]) + ++i; + indices.push_back(i); // word end + if (list[i] == ac->GetTypesep()) { + while (list[i] != ac->GetSeparator() && list[i]) + ++i; + } + if (list[i] == ac->GetSeparator()) { + ++i; + // preserve trailing separator as blank entry + if (!list[i]) { + indices.push_back(i); + indices.push_back(i); + } + } + } + indices.push_back(i); // index of last position + } + + bool operator()(int a, int b) { + int lenA = indices[a * 2 + 1] - indices[a * 2]; + int lenB = indices[b * 2 + 1] - indices[b * 2]; + int len = std::min(lenA, lenB); + int cmp; + if (ac->ignoreCase) + cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len); + else + cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len); + if (cmp == 0) + cmp = lenA - lenB; + return cmp < 0; + } +}; + void AutoComplete::SetList(const char *list) { - lb->SetList(list, separator, typesep); + if (autoSort == SC_ORDER_PRESORTED) { + lb->SetList(list, separator, typesep); + sortMatrix.clear(); + for (int i = 0; i < lb->Length(); ++i) + sortMatrix.push_back(i); + return; + } + + Sorter IndexSort(this, list); + sortMatrix.clear(); + for (int i = 0; i < (int)IndexSort.indices.size() / 2; ++i) + sortMatrix.push_back(i); + std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort); + if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) { + lb->SetList(list, separator, typesep); + PLATFORM_ASSERT(lb->Length() == static_cast<int>(sortMatrix.size())); + return; + } + + std::string sortedList; + char item[maxItemLen]; + for (size_t i = 0; i < sortMatrix.size(); ++i) { + int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2]; + strncpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen); + if ((i+1) == sortMatrix.size()) { + // Last item so remove separator if present + if ((wordLen > 0) && (item[wordLen-1] == separator)) + wordLen--; + } else { + // Item before last needs a separator + if ((wordLen == 0) || (item[wordLen-1] != separator)) { + item[wordLen] = separator; + wordLen++; + } + } + item[wordLen] = '\0'; + sortedList += item; + } + for (int i = 0; i < (int)sortMatrix.size(); ++i) + sortMatrix[i] = i; + lb->SetList(sortedList.c_str(), separator, typesep); } int AutoComplete::GetSelection() const { @@ -149,7 +235,7 @@ void AutoComplete::Select(const char *word) { while ((start <= end) && (location == -1)) { // Binary searching loop int pivot = (start + end) / 2; char item[maxItemLen]; - lb->GetValue(pivot, item, maxItemLen); + lb->GetValue(sortMatrix[pivot], item, maxItemLen); int cond; if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); @@ -158,7 +244,7 @@ void AutoComplete::Select(const char *word) { if (!cond) { // Find first match while (pivot > start) { - lb->GetValue(pivot-1, item, maxItemLen); + lb->GetValue(sortMatrix[pivot-1], item, maxItemLen); if (ignoreCase) cond = CompareNCaseInsensitive(word, item, lenWord); else @@ -172,7 +258,7 @@ void AutoComplete::Select(const char *word) { && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) { // Check for exact-case match for (; pivot <= end; pivot++) { - lb->GetValue(pivot, item, maxItemLen); + lb->GetValue(sortMatrix[pivot], item, maxItemLen); if (!strncmp(word, item, lenWord)) { location = pivot; break; @@ -187,9 +273,24 @@ void AutoComplete::Select(const char *word) { start = pivot + 1; } } - if (location == -1 && autoHide) - Cancel(); - else - lb->Select(location); + if (location == -1) { + if (autoHide) + Cancel(); + else + lb->Select(-1); + } else { + if (autoSort == SC_ORDER_CUSTOM) { + // Check for a logically earlier match + char item[maxItemLen]; + for (int i = location + 1; i <= end; ++i) { + lb->GetValue(sortMatrix[i], item, maxItemLen); + if (CompareNCaseInsensitive(word, item, lenWord)) + break; + if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord)) + location = i; + } + } + lb->Select(sortMatrix[location]); + } } diff --git a/src/AutoComplete.h b/src/AutoComplete.h index 4d27e6add..9977196a2 100644 --- a/src/AutoComplete.h +++ b/src/AutoComplete.h @@ -21,6 +21,7 @@ class AutoComplete { char separator; char typesep; // Type seperator enum { maxItemLen=1000 }; + std::vector<int> sortMatrix; public: @@ -36,6 +37,11 @@ public: unsigned int ignoreCaseBehaviour; int widthLBDefault; int heightLBDefault; + /** SC_ORDER_PRESORTED: Assume the list is presorted; selection will fail if it is not alphabetical<br /> + * SC_ORDER_PERFORMSORT: Sort the list alphabetically; start up performance cost for sorting<br /> + * SC_ORDER_CUSTOM: Handle non-alphabetical entries; start up performance cost for generating a sorted lookup table + */ + int autoSort; AutoComplete(); ~AutoComplete(); diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx index 4a0146f7b..35aa1c49e 100644 --- a/src/ScintillaBase.cxx +++ b/src/ScintillaBase.cxx @@ -794,6 +794,13 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara case SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR: return ac.ignoreCaseBehaviour; + case SCI_AUTOCSETORDER: + ac.autoSort = wParam; + break; + + case SCI_AUTOCGETORDER: + return ac.autoSort; + case SCI_USERLISTSHOW: listType = wParam; AutoCompleteStart(0, reinterpret_cast<const char *>(lParam)); |