Browse Source

CodeCompletion: filtered items are shown in the same order as they were before filtering. The best match is selected.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5750 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Martin Koníček 15 years ago
parent
commit
ef7c0f1457
  1. 77
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
  2. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
  3. 5
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

77
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs

@ -28,10 +28,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -28,10 +28,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
new FrameworkPropertyMetadata(typeof(CompletionList)));
}
bool isFiltering = true;
/// <summary>
/// If true, enables the old behavior: no filtering, search by string.StartsWith.
/// If true, the CompletionList is filtered to show only matching items. Also enables search by substring.
/// If false, enables the old behavior: no filtering, search by string.StartsWith.
/// </summary>
public bool IsSearchByStartOnly { get; set; }
public bool IsFiltering {
get { return isFiltering; }
set { isFiltering = value; }
}
/// <summary>
/// Is raised when the completion list indicates that the user has chosen
@ -175,39 +180,49 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -175,39 +180,49 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
/// <summary>
/// Selects the best match, and possibly filters the items.
/// Selects the best match, and filter the items if turned on using <see cref="IsFiltering" />.
/// </summary>
public void SelectItem(string text)
{
if (string.IsNullOrEmpty(text))
return;
if (listBox == null)
ApplyTemplate();
if (this.IsSearchByStartOnly)
SelectItemWithStart(text);
else
if (this.IsFiltering) {
FilterMatchingItems(text);
}
else {
SelectItemWithStart(text);
}
}
/// <summary>
/// Filters CompletionList items to show only those matching given text, and selects the best match.
/// </summary>
void FilterMatchingItems(string text)
{
// BUG Find references to itemsWithQualities returns just this one
// assign qualities to items
var itemsWithQualities =
from item in completionData
var itemsWithQualities =
from item in this.completionData
select new { Item = item, Quality = GetMatchQuality(item.Text, text) };
// take items with quality > 0, order by quality
var matchingOrdered = from itemWithQ in itemsWithQualities
where itemWithQ.Quality > 0
orderby itemWithQ.Quality descending, itemWithQ.Item.Priority descending, itemWithQ.Item.Text
select itemWithQ.Item;
var matchingItems = new ObservableCollection<ICompletionData>();
foreach (var matchingItem in matchingOrdered) {
matchingItems.Add(matchingItem);
var matchingItems = itemsWithQualities.Where(item => item.Quality > 0);
var listBoxItems = new ObservableCollection<ICompletionData>();
int bestIndex = -1;
int bestQuality = -1;
double bestPriority = 0;
int i = 0;
foreach (var matchingItem in matchingItems) {
double priority = matchingItem.Item.Priority;
int quality = matchingItem.Quality;
if (quality > bestQuality || (quality == bestQuality && priority > bestPriority)) {
bestIndex = i;
bestPriority = priority;
bestQuality = quality;
}
listBoxItems.Add(matchingItem.Item);
i++;
}
listBox.ItemsSource = matchingItems;
listBox.SelectIndex(0);
listBox.ItemsSource = listBoxItems;
SelectIndexCentered(bestIndex);
}
/// <summary>
@ -215,6 +230,9 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -215,6 +230,9 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// </summary>
void SelectItemWithStart(string startText)
{
if (string.IsNullOrEmpty(startText))
return;
int selectedItem = listBox.SelectedIndex;
int bestIndex = -1;
@ -231,6 +249,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -231,6 +249,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
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?
useThisItem = false;
} else if (i == selectedItem) {
useThisItem = bestQuality == quality;
@ -244,11 +263,17 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -244,11 +263,17 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
bestQuality = quality;
}
}
SelectIndexCentered(bestIndex);
}
void SelectIndexCentered(int bestIndex)
{
if (bestIndex < 0) {
listBox.ClearSelection();
} else {
int firstItem = listBox.FirstVisibleItem;
if (bestIndex < firstItem || firstItem + listBox.VisibleItemCount <= bestIndex) {
// CenterViewOn does nothing as CompletionListBox.ScrollViewer is null
listBox.CenterViewOn(bestIndex);
listBox.SelectIndex(bestIndex);
} else {
@ -264,7 +289,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -264,7 +289,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
// 1 = match CamelCase
// 2 = match sustring
// 3 = match substring case sensitive
// 4 = match CamelCase when length of query is only 1 or 2 characters
// 4 = match CamelCase when length of query is 1 or 2 characters
// 5 = match start
// 6 = match start case sensitive
// 7 = full match
@ -282,10 +307,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -282,10 +307,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
if (query.Length <= 2 && CamelCaseMatch(itemText, query))
return 4;
// search by substring, if not turned off
if (!IsSearchByStartOnly && itemText.Contains(query))
// search by substring, if filtering (i.e. new behavior) turned on
if (IsFiltering && query.Length > 1 && itemText.Contains(query))
return 3;
if (!IsSearchByStartOnly && itemText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
if (IsFiltering && query.Length > 1 && itemText.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)
return 2;
if (CamelCaseMatch(itemText, query))

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -38,7 +38,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// </summary>
public int FirstVisibleItem {
get {
if (scrollViewer == null) {
if (scrollViewer == null || scrollViewer.ExtentHeight == 0) {
return 0;
} else {
return (int)(this.Items.Count * scrollViewer.VerticalOffset / scrollViewer.ExtentHeight);
@ -57,7 +57,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -57,7 +57,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// </summary>
public int VisibleItemCount {
get {
if (scrollViewer == null) {
if (scrollViewer == null || scrollViewer.ExtentHeight == 0) {
return 10;
} else {
return Math.Max(

5
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

@ -163,8 +163,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -163,8 +163,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
{
int offset = this.TextArea.Caret.Offset;
if (offset == this.StartOffset) {
if (CloseAutomatically && CloseWhenCaretAtBeginning)
if (CloseAutomatically && CloseWhenCaretAtBeginning) {
Close();
} else {
completionList.SelectItem(string.Empty);
}
return;
}
if (offset < this.StartOffset || offset > this.EndOffset) {

Loading…
Cancel
Save