diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin
index a000be4aed..f44fee2328 100755
--- a/AddIns/ICSharpCode.SharpDevelop.addin
+++ b/AddIns/ICSharpCode.SharpDevelop.addin
@@ -1455,6 +1455,7 @@
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
index 63a227dfee..50491c288f 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
@@ -198,7 +198,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
// SelectItem gets called twice for every typed character (once from FormatLine), this helps execute SelectItem only once
string currentText;
ObservableCollection currentList;
-
+
///
/// Selects the best match, and filter the items if turned on using .
///
@@ -219,29 +219,32 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
///
- /// Filters CompletionList items to show only those matching given text, and selects the best match.
+ /// Filters CompletionList items to show only those matching given query, and selects the best match.
///
- void SelectItemFiltering(string text)
+ void SelectItemFiltering(string query)
{
// if the user just typed one more character, don't filter all data but just filter what we are already displaying
- var listToFilter = (this.currentList != null && (!string.IsNullOrEmpty(this.currentText)) && (!string.IsNullOrEmpty(text)) &&
- text.StartsWith(this.currentText)) ?
- this.currentList : this.completionData;
+ var listToFilter = (this.currentList != null && (!string.IsNullOrEmpty(this.currentText)) && (!string.IsNullOrEmpty(query)) &&
+ query.StartsWith(this.currentText)) ?
+ this.currentList : this.completionData;
- var itemsWithQualities =
+ var itemsWithQualities =
from item in listToFilter
- select new { Item = item, Quality = GetMatchQuality(item.Text, text) };
+ select new { Item = item, Quality = GetMatchQuality(item.Text, query) };
var matchingItems = itemsWithQualities.Where(item => item.Quality > 0);
+ // e.g. "DateTimeKind k = (*cc here suggests DateTimeKind*)"
+ ICompletionData suggestedItem = listBox.SelectedIndex != -1 ? (ICompletionData)(listBox.Items[listBox.SelectedIndex]) : null;
+
var listBoxItems = new ObservableCollection();
int bestIndex = -1;
int bestQuality = -1;
double bestPriority = 0;
int i = 0;
foreach (var matchingItem in matchingItems) {
- double priority = matchingItem.Item.Priority;
+ double priority = matchingItem.Item == suggestedItem ? double.PositiveInfinity : matchingItem.Item.Priority;
int quality = matchingItem.Quality;
- if (quality > bestQuality || (quality == bestQuality && priority > bestPriority)) {
+ if (quality > bestQuality || (quality == bestQuality && (priority > bestPriority))) {
bestIndex = i;
bestPriority = priority;
bestQuality = quality;
@@ -255,20 +258,20 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
///
- /// Selects the item that starts with the specified text.
+ /// Selects the item that starts with the specified query.
///
- void SelectItemWithStart(string startText)
+ void SelectItemWithStart(string query)
{
- if (string.IsNullOrEmpty(startText))
+ if (string.IsNullOrEmpty(query))
return;
- int selectedItem = listBox.SelectedIndex;
+ int suggestedIndex = listBox.SelectedIndex;
int bestIndex = -1;
int bestQuality = -1;
double bestPriority = 0;
for (int i = 0; i < completionData.Count; ++i) {
- int quality = GetMatchQuality(completionData[i].Text, startText);
+ int quality = GetMatchQuality(completionData[i].Text, query);
if (quality < 0)
continue;
@@ -277,10 +280,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
if (bestQuality < quality) {
useThisItem = true;
} else {
- if (bestIndex == selectedItem) {
- // martin.konicek: I'm not sure what this does. This item could have higher priority, why not select it?
+ if (bestIndex == suggestedIndex) {
useThisItem = false;
- } else if (i == selectedItem) {
+ } else if (i == suggestedIndex) {
+ // prefer recommendedItem, regardless of its priority
useThisItem = bestQuality == quality;
} else {
useThisItem = bestQuality == quality && bestPriority < priority;
@@ -314,15 +317,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
int GetMatchQuality(string itemText, string query)
{
// Qualities:
- // -1 = no match
- // 1 = match CamelCase
- // 2 = match sustring
- // 3 = match substring case sensitive
- // 4 = match CamelCase when length of query is 1 or 2 characters
- // 5 = match start
- // 6 = match start case sensitive
- // 7 = full match
// 8 = full match case sensitive
+ // 7 = full match
+ // 6 = match start case sensitive
+ // 5 = match start
+ // 4 = match CamelCase when length of query is 1 or 2 characters
+ // 3 = match substring case sensitive
+ // 2 = match sustring
+ // 1 = match CamelCase
+ // -1 = no match
if (query == itemText)
return 8;
if (string.Equals(itemText, query, StringComparison.OrdinalIgnoreCase))
@@ -340,11 +343,13 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
// search by substring, if filtering (i.e. new behavior) turned on
- if (IsFiltering && itemText.Contains(query))
- return 3;
- if (IsFiltering && itemText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
- return 2;
-
+ if (IsFiltering) {
+ if (itemText.Contains(query))
+ return 3;
+ if (itemText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
+ return 2;
+ }
+
if (!camelCaseMatch.HasValue)
camelCaseMatch = CamelCaseMatch(itemText, query);
if (camelCaseMatch.GetValueOrDefault(false))
@@ -358,7 +363,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
int i = 0;
foreach (char upper in text.Where(c => char.IsUpper(c))) {
if (i > query.Length - 1)
- return true; // return true here for CamelCase partial match (CQ match CodeQualityAnalysis)
+ return true; // return true here for CamelCase partial match ("CQ" matches "CodeQualityAnalysis")
if (char.ToUpper(query[i]) != upper)
return false;
i++;