diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs
index fbece530dd..11d2c8261c 100644
--- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs
+++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs
@@ -19,7 +19,7 @@ namespace Grunwald.BooBinding.CodeCompletion
this.EnableXmlCommentCompletion = false;
}
- public override bool HandleKeyPress(ITextEditor editor, char ch)
+ public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
if (ch == '[') {
int cursor = editor.Caret.Offset;
@@ -28,7 +28,7 @@ namespace Grunwald.BooBinding.CodeCompletion
if (c == '\n' || c == '(' || c == ',') {
// -> Attribute completion
editor.ShowCompletionWindow(new AttributesDataProvider(ExpressionFinder.BooAttributeContext.Instance), ch);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
if (!char.IsWhiteSpace(c))
break;
@@ -52,12 +52,13 @@ namespace Grunwald.BooBinding.CodeCompletion
return true;
case "as":
case "isa":
- if (IsInComment(editor)) return false;
- editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(ExpressionContext.Type), ' ');
- return true;
- default:
- return base.HandleKeyword(editor, word);
+ if (!IsInComment(editor)) {
+ editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(ExpressionContext.Type), ' ');
+ return true;
+ }
+ break;
}
+ return base.HandleKeyword(editor, word);
}
}
}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
index 0df14d7881..cc83f7ad44 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
@@ -33,21 +33,21 @@ namespace CSharpBinding
return new CSharpExpressionFinder(ParserService.GetParseInformation(fileName));
}
- public override bool HandleKeyPress(ITextEditor editor, char ch)
+ public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
CSharpExpressionFinder ef = CreateExpressionFinder(editor.FileName);
int cursor = editor.Caret.Offset;
ExpressionContext context = null;
if (ch == '(') {
if (context != null) {
- if (IsInComment(editor)) return false;
+ if (IsInComment(editor)) return CodeCompletionKeyPressResult.None;
editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(context), ch);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
} else if (EnableMethodInsight && CodeCompletionOptions.InsightEnabled) {
editor.ShowInsightWindow(new MethodInsightDataProvider());
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
- return false;
+ return CodeCompletionKeyPressResult.None;
} else if (ch == '[') {
var line = editor.Document.GetLineForOffset(cursor);
/* TODO: AVALONEDIT Reimplement this
@@ -59,7 +59,7 @@ namespace CSharpBinding
}*/
} else if (ch == ',' && CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled) {
if (InsightRefreshOnComma(editor, ch))
- return true;
+ return CodeCompletionKeyPressResult.Completed;
} else if(ch == '=') {
var curLine = editor.Document.GetLineForOffset(cursor);
string documentText = editor.Document.Text;
@@ -76,6 +76,7 @@ namespace CSharpBinding
EventHandlerCompletitionDataProvider eventHandlerProvider = new EventHandlerCompletitionDataProvider(result.Expression, resolveResult);
eventHandlerProvider.InsertSpace = true;
editor.ShowCompletionWindow(eventHandlerProvider, ch);
+ return CodeCompletionKeyPressResult.Completed;
}
}
}
@@ -86,21 +87,21 @@ namespace CSharpBinding
ResolveResult resolveResult = ParserService.Resolve(result, editor.Caret.Line, editor.Caret.Column, editor.FileName, documentText);
if (resolveResult != null && resolveResult.ResolvedType != null) {
if (ProvideContextCompletion(editor, resolveResult.ResolvedType, ch)) {
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
}
}
}
} else if (ch == '.') {
new CSharpCodeCompletionDataProvider().ShowCompletion(editor);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
} else if (ch == '>') {
- if (IsInComment(editor)) return false;
+ if (IsInComment(editor)) return CodeCompletionKeyPressResult.None;
char prevChar = cursor > 1 ? editor.Document.GetCharAt(cursor - 1) : ' ';
if (prevChar == '-') {
new PointerArrowCompletionDataProvider().ShowCompletion(editor);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
}
@@ -111,7 +112,7 @@ namespace CSharpBinding
int endOffset = cursor + editor.SelectionLength;
// but block code completion when overwriting only part of an identifier
if (endOffset < editor.Document.TextLength && char.IsLetterOrDigit(editor.Document.GetCharAt(endOffset)))
- return false;
+ return CodeCompletionKeyPressResult.None;
editor.Document.Remove(editor.SelectionStart, editor.SelectionLength);
editor.Caret.Offset = cursor;
}
@@ -129,6 +130,7 @@ namespace CSharpBinding
ShowTemplates = true,
AllowCompleteExistingExpression = afterUnderscore
}, '\0');
+ return CodeCompletionKeyPressResult.Completed;
}
}
}
@@ -136,7 +138,7 @@ namespace CSharpBinding
return base.HandleKeyPress(editor, ch);
}
- class CSharpCodeCompletionDataProvider : CodeCompletionItemProvider
+ class CSharpCodeCompletionDataProvider : DotCodeCompletionItemProvider
{
public override ResolveResult Resolve(ITextEditor editor, ExpressionResult expressionResult)
{
@@ -148,7 +150,7 @@ namespace CSharpBinding
}
}
- class PointerArrowCompletionDataProvider : CodeCompletionItemProvider
+ class PointerArrowCompletionDataProvider : DotCodeCompletionItemProvider
{
public override ResolveResult Resolve(ITextEditor editor, ExpressionResult expressionResult)
{
@@ -163,13 +165,8 @@ namespace CSharpBinding
public override ExpressionResult GetExpression(ITextEditor editor)
{
- var document = editor.Document;
- IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(editor.FileName);
- if (expressionFinder == null) {
- return ExpressionResult.Empty;
- } else {
- return expressionFinder.FindExpression(document.GetText(0, editor.Caret.Offset - 1), editor.Caret.Offset - 1);
- }
+ // - 1 because the "-" is already inserted (the ">" is about to be inserted)
+ return GetExpressionFromOffset(editor, editor.Caret.Offset - 1);
}
}
@@ -191,10 +188,10 @@ namespace CSharpBinding
IClass innerMostClass = parseInfo.MostRecentCompilationUnit.GetInnermostClass(editor.Caret.Line, editor.Caret.Column);
if (innerMostClass == null) {
editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(ExpressionContext.Namespace), ' ');
+ return true;
}
- return true;
}
- return false;
+ break;
case "as":
case "is":
if (IsInComment(editor)) return false;
@@ -214,12 +211,10 @@ namespace CSharpBinding
IMember m = GetCurrentMember(editor);
if (m != null) {
return ProvideContextCompletion(editor, m.ReturnType, ' ');
- } else {
- goto default;
}
- default:
- return base.HandleKeyword(editor, word);
+ break;
}
+ return base.HandleKeyword(editor, word);
}
bool ShowNewCompletion(ITextEditor editor)
diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs
index 2cb5953e5e..952eef7ce4 100644
--- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs
+++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs
@@ -32,14 +32,14 @@ namespace VBNetBinding
this.EnableIndexerInsight = false;
}
- public override bool HandleKeyPress(ITextEditor editor, char ch)
+ public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
if(ch == '(' && EnableMethodInsight && CodeCompletionOptions.InsightEnabled) {
editor.ShowInsightWindow(new MethodInsightDataProvider());
- return true;
+ return CodeCompletionKeyPressResult.Completed;
} else if(ch == ',' && CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled) {
if (InsightRefreshOnComma(editor, ch))
- return true;
+ return CodeCompletionKeyPressResult.Completed;
} else if (ch == '\n') {
TryDeclarationTypeInference(editor, editor.Document.GetLineForOffset(editor.Caret.Offset));
}
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs
index 58c7e1d3f8..1e7b3e4d68 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs
@@ -5,14 +5,16 @@
// $Revision$
//
-using ICSharpCode.AvalonEdit.CodeCompletion;
using System;
-using System.Linq;
using System.Diagnostics;
+using System.Linq;
using System.Windows;
+
+using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Gui;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
+using System.Windows.Media;
namespace ICSharpCode.AvalonEdit.AddIn
{
@@ -107,11 +109,16 @@ namespace ICSharpCode.AvalonEdit.AddIn
{
if (data == null || !data.Items.Any())
return;
- CompletionWindow window = textEditor.CreateCompletionWindow(data.Items.Select(i => (ICompletionData)new CodeCompletionDataAdapter(i)));
+ CompletionWindow window = CreateCompletionWindow(data);
if (window != null)
window.Show();
}
+ protected virtual CompletionWindow CreateCompletionWindow(ICompletionItemList data)
+ {
+ return textEditor.CreateCompletionWindow(data.Items.Select(i => (ICompletionData)new CodeCompletionDataAdapter(i)));;
+ }
+
public string GetWordBeforeCaret()
{
throw new NotImplementedException();
@@ -162,5 +169,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
public object Description {
get { return item.Description; }
}
+
+ public ImageSource Image {
+ get { return null; }
+ }
}
}
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
index ea3d334b93..8a67677f96 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
@@ -5,11 +5,11 @@
// $Revision$
//
+using ICSharpCode.AvalonEdit.CodeCompletion;
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Media;
-
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
@@ -47,14 +47,30 @@ namespace ICSharpCode.AvalonEdit.AddIn
base.OnPreviewTextInput(e);
if (!e.Handled && e.Text.Length == 1) {
foreach (ICodeCompletionBinding cc in CodeCompletionBindings) {
- if (cc.HandleKeyPress(textEditorAdapter, e.Text[0])) {
- // Don't set e.Handled - we still want to insert the typed text.
- // This isn't optimal, but that's how the ICodeCompletionBinding interface
- // has always worked; and I don't want to change too much at once.
+ CompletionWindow oldCompletionWindow = lastCompletionWindow;
+ CodeCompletionKeyPressResult result = cc.HandleKeyPress(textEditorAdapter, e.Text[0]);
+ if (result == CodeCompletionKeyPressResult.Completed) {
+ if (lastCompletionWindow != null && lastCompletionWindow != oldCompletionWindow) {
+ // a new CompletionWindow was shown, but does not eat the input
+ // increment the offsets so that they are correct after the text insertion
+ lastCompletionWindow.StartOffset++;
+ lastCompletionWindow.EndOffset++;
+ }
+ return;
+ } else if (result == CodeCompletionKeyPressResult.EatKey) {
+ e.Handled = true;
return;
}
}
}
}
+
+ CompletionWindow lastCompletionWindow;
+
+ internal void NotifyCompletionWindowOpened(CompletionWindow window)
+ {
+ lastCompletionWindow = window;
+ window.Closed += delegate { lastCompletionWindow = null; };
+ }
}
}
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
index e3bf200848..851f592e2c 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
@@ -5,7 +5,9 @@
// $Revision$
//
+using ICSharpCode.SharpDevelop;
using System;
+using ICSharpCode.AvalonEdit.CodeCompletion;
namespace ICSharpCode.AvalonEdit.AddIn
{
@@ -26,5 +28,12 @@ namespace ICSharpCode.AvalonEdit.AddIn
public override string FileName {
get { return codeEditor.FileName; }
}
+
+ protected override CompletionWindow CreateCompletionWindow(ICompletionItemList data)
+ {
+ CompletionWindow window = base.CreateCompletionWindow(data);
+ codeEditor.NotifyCompletionWindowOpened(window);
+ return window;
+ }
}
}
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs
index b14cadfad3..57f4fc4a4c 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs
@@ -20,7 +20,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion
public abstract class AbstractNRefactoryResourceCodeCompletionBinding : DefaultCodeCompletionBinding
{
- public override bool HandleKeyPress(ITextEditor editor, char ch)
+ public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
if (this.CompletionPossible(editor, ch)) {
@@ -42,13 +42,13 @@ namespace Hornung.ResourceToolkit.CodeCompletion
}
editor.ShowCompletionWindow(new ResourceCodeCompletionDataProvider(content, this.OutputVisitor, result.CallingClass != null ? result.CallingClass.Name+"." : null), ch);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
}
}
- return false;
+ return CodeCompletionKeyPressResult.None;
}
// ********************************************************************************************************************************
diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs
index ef56c22af7..67ce5d3226 100644
--- a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs
+++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs
@@ -21,7 +21,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion
public class ICSharpCodeCoreResourceCodeCompletionBinding : DefaultCodeCompletionBinding
{
- public override bool HandleKeyPress(ITextEditor editor, char ch)
+ public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
if (ch == ':') {
@@ -49,7 +49,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion
if (content != null) {
editor.ShowCompletionWindow(new ResourceCodeCompletionDataProvider(content, null, null), ch);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
}
@@ -62,13 +62,13 @@ namespace Hornung.ResourceToolkit.CodeCompletion
ICSharpCodeCoreResourceResolver.GetICSharpCodeCoreLocalResourceSet(editor.FileName).ResourceFileContent != null) {
editor.ShowCompletionWindow(new ICSharpCodeCoreTagCompletionDataProvider(), ch);
- return true;
+ return CodeCompletionKeyPressResult.Completed;
}
}
- return false;
+ return CodeCompletionKeyPressResult.None;
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
index b70f7b6e55..d920c808eb 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
@@ -111,6 +111,74 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
}
+ ///
+ /// Selects the item that starts with the specified text.
+ ///
+ public void SelectItemWithStart(string startText)
+ {
+ if (string.IsNullOrEmpty(startText))
+ return;
+ int selectedItem = listBox.SelectedIndex;
+
+ int bestIndex = -1;
+ int bestQuality = -1;
+ // Qualities: 0 = match start
+ // 1 = match start case sensitive
+ // 2 = full match
+ // 3 = full match case sensitive
+ double bestPriority = 0;
+ for (int i = 0; i < completionData.Count; ++i) {
+ string itemText = completionData[i].Text;
+ if (itemText.StartsWith(startText, StringComparison.InvariantCultureIgnoreCase)) {
+ double priority = 0; //completionData[i].Priority;
+ int quality;
+ if (string.Equals(itemText, startText, StringComparison.InvariantCultureIgnoreCase)) {
+ if (startText == itemText)
+ quality = 3;
+ else
+ quality = 2;
+ } else if (itemText.StartsWith(startText, StringComparison.InvariantCulture)) {
+ quality = 1;
+ } else {
+ quality = 0;
+ }
+ bool useThisItem;
+ if (bestQuality < quality) {
+ useThisItem = true;
+ } else {
+ if (bestIndex == selectedItem) {
+ useThisItem = false;
+ } else if (i == selectedItem) {
+ useThisItem = bestQuality == quality;
+ } else {
+ useThisItem = bestQuality == quality && bestPriority < priority;
+ }
+ }
+ if (useThisItem) {
+ bestIndex = i;
+ bestPriority = priority;
+ bestQuality = quality;
+ }
+ }
+ }
+ if (bestIndex < 0) {
+ ClearSelection();
+ } else {
+ int firstItem = listBox.FirstVisibleItem;
+ if (bestIndex < firstItem || firstItem + listBox.VisibleItemCount <= bestIndex) {
+ CenterViewOn(bestIndex);
+ SelectIndex(bestIndex);
+ } else {
+ SelectIndex(bestIndex);
+ }
+ }
+ }
+
+ void ClearSelection()
+ {
+ listBox.SelectedIndex = -1;
+ }
+
void SelectIndex(int offset)
{
if (offset >= listBox.Items.Count)
@@ -120,5 +188,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
listBox.SelectedIndex = offset;
listBox.ScrollIntoView(listBox.SelectedItem);
}
+
+ void CenterViewOn(int offset)
+ {
+ // TODO: implement me
+ }
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml
index 4d17e02f22..3eb76e5521 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml
@@ -41,7 +41,10 @@
-
+
+
+
+
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
index 667f8c987b..2966c009ff 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
@@ -32,6 +32,19 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
}
+ ///
+ /// Gets the number of the first visible item.
+ ///
+ public int FirstVisibleItem {
+ get {
+ if (scrollViewer == null) {
+ return 0;
+ } else {
+ return (int)(this.Items.Count * scrollViewer.VerticalOffset / scrollViewer.ExtentHeight);
+ }
+ }
+ }
+
///
/// Gets the number of visible items.
///
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
index 061acf3d2d..a33dea9137 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
@@ -6,6 +6,7 @@
//
using System;
+using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
@@ -13,6 +14,7 @@ using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Gui;
namespace ICSharpCode.AvalonEdit.CodeCompletion
{
@@ -36,21 +38,36 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.Width = 200;
this.Content = completionList;
- completionList.SizeChanged += completionList_SizeChanged;
-
+ startOffset = endOffset = this.TextArea.Caret.Offset;
document = textArea.TextView.Document;
- startOffset = endOffset = textArea.Caret.Offset;
}
- void completionList_SizeChanged(object sender, SizeChangedEventArgs e)
+ ///
+ /// Gets/Sets the start offset of the edited text portion.
+ ///
+ public int StartOffset {
+ get { return startOffset; }
+ set { startOffset = value; }
+ }
+
+ ///
+ /// Gets/Sets the end offset of the edited text portion.
+ ///
+ public int EndOffset {
+ get { return endOffset; }
+ set { endOffset = value; }
+ }
+
+ ///
+ protected override void OnSourceInitialized(EventArgs e)
{
- if (completionList.ActualHeight < 200) {
- this.SizeToContent = SizeToContent.Height;
- this.Height = double.NaN;
- } else if (completionList.ActualHeight > 300) {
+ // prevent CompletionWindow from growing too large
+ if (this.ActualHeight > 300) {
this.SizeToContent = SizeToContent.Manual;
this.Height = 300;
}
+
+ base.OnSourceInitialized(e);
}
///
@@ -60,6 +77,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
document.Changing += textArea_Document_Changing;
this.TextArea.Caret.PositionChanged += CaretPositionChanged;
this.TextArea.MouseWheel += textArea_MouseWheel;
+ this.TextArea.ActiveInputHandler = new InputHandler(this);
}
///
@@ -69,8 +87,42 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
this.TextArea.Caret.PositionChanged -= CaretPositionChanged;
this.TextArea.MouseWheel -= textArea_MouseWheel;
base.DetachEvents();
+ this.TextArea.ActiveInputHandler = this.TextArea.DefaultInputHandler;
}
+ #region InputHandler
+ ///
+ /// A dummy input handler (that justs invokes the default input handler).
+ /// This is used to ensure the completion window closes when any other input handler
+ /// becomes active.
+ ///
+ sealed class InputHandler : ITextAreaInputHandler
+ {
+ readonly CompletionWindow window;
+
+ public InputHandler(CompletionWindow window)
+ {
+ Debug.Assert(window != null);
+ this.window = window;
+ }
+
+ public TextArea TextArea {
+ get { return window.TextArea; }
+ }
+
+ public void Attach()
+ {
+ this.TextArea.DefaultInputHandler.Attach();
+ }
+
+ public void Detach()
+ {
+ this.TextArea.DefaultInputHandler.Detach();
+ window.Close();
+ }
+ }
+ #endregion
+
///
protected override void OnKeyDown(KeyEventArgs e)
{
@@ -104,12 +156,19 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
return completionList.ScrollViewer ?? completionList.ListBox ?? (UIElement)completionList;
}
+ bool expectInsertionBeforeStart = true;
+
void textArea_Document_Changing(object sender, DocumentChangeEventArgs e)
{
// => startOffset test required so that this startOffset/endOffset are not incremented again
// for BeforeStartKey characters
if (e.Offset >= startOffset && e.Offset <= endOffset) {
endOffset += e.InsertionLength - e.RemovalLength;
+ } else if (expectInsertionBeforeStart && e.Offset == startOffset - 1 && e.InsertionLength == 1 && e.RemovalLength == 0) {
+ // allow a single one-character insertion in front of StartOffset.
+ // this is necessary because for dot-completion, the CompletionWindow is shown before
+ // the dot is actually inserted.
+ expectInsertionBeforeStart = false;
} else {
Close();
}
@@ -133,7 +192,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
if (offset < startOffset || offset > endOffset) {
Close();
} else {
- //codeCompletionListView.SelectItemWithStart(document.GetText(startOffset, offset - startOffset));
+ completionList.SelectItemWithStart(document.GetText(startOffset, offset - startOffset));
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs
index 44b5ed116f..77f9108e7b 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs
@@ -6,6 +6,7 @@
//
using System;
+using System.Windows.Media;
namespace ICSharpCode.AvalonEdit.CodeCompletion
{
@@ -14,6 +15,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
///
public interface ICompletionData
{
+ ///
+ /// Gets the image.
+ ///
+ ImageSource Image { get; }
+
///
/// Gets the text. This property is used to filter the list of visible elements.
///
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
index 1e4861d01a..f12e380a8b 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
@@ -6,11 +6,13 @@
//
using System;
+using System.Collections.Generic;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.TextFormatting;
using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Gui
{
@@ -35,8 +37,19 @@ namespace ICSharpCode.AvalonEdit.Gui
static class CaretNavigationCommandHandler
{
- public static readonly CommandBindingCollection CommandBindings = new CommandBindingCollection();
- public static readonly InputBindingCollection InputBindings = new InputBindingCollection();
+ ///
+ /// Creates a new for the text area.
+ ///
+ public static TextAreaInputHandler Create(TextArea textArea)
+ {
+ TextAreaInputHandler handler = new TextAreaInputHandler(textArea);
+ handler.CommandBindings.AddRange(CommandBindings);
+ handler.InputBindings.AddRange(InputBindings);
+ return handler;
+ }
+
+ static readonly List CommandBindings = new List();
+ static readonly List InputBindings = new List();
static void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
{
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
index 9e588b8194..cdafabbc3b 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
@@ -6,24 +6,37 @@
//
using System;
+using System.Collections.Generic;
using System.Diagnostics;
-using System.Globalization;
using System.Linq;
-using System.Text;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.Document;
-using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Gui
{
+ ///
+ /// We re-use the CommandBinding and InputBinding instances between multiple text areas,
+ /// so this class is static.
+ ///
static class EditingCommandHandler
{
- public static readonly CommandBindingCollection CommandBindings = new CommandBindingCollection();
- public static readonly InputBindingCollection InputBindings = new InputBindingCollection();
+ ///
+ /// Creates a new for the text area.
+ ///
+ public static TextAreaInputHandler Create(TextArea textArea)
+ {
+ TextAreaInputHandler handler = new TextAreaInputHandler(textArea);
+ handler.CommandBindings.AddRange(CommandBindings);
+ handler.InputBindings.AddRange(InputBindings);
+ return handler;
+ }
+
+ static readonly List CommandBindings = new List();
+ static readonly List InputBindings = new List();
static void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
{
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs
index 9b7484be3f..10c1b32e46 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs
@@ -21,7 +21,7 @@ namespace ICSharpCode.AvalonEdit.Gui
///
/// Handles selection of text using the mouse.
///
- sealed class SelectionMouseHandler
+ sealed class SelectionMouseHandler : ITextAreaInputHandler
{
#region enum SelectionMode
enum SelectionMode
@@ -62,9 +62,15 @@ namespace ICSharpCode.AvalonEdit.Gui
#region Constructor + Attach + Detach
public SelectionMouseHandler(TextArea textArea)
{
+ if (textArea == null)
+ throw new ArgumentNullException("textArea");
this.textArea = textArea;
}
+ public TextArea TextArea {
+ get { return textArea; }
+ }
+
public void Attach()
{
textArea.MouseLeftButtonDown += textArea_MouseLeftButtonDown;
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
index fc3a0a6b3d..d4f34e40db 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
@@ -77,19 +77,46 @@ namespace ICSharpCode.AvalonEdit
caret = new Caret(this);
caret.PositionChanged += (sender, e) => RequestSelectionValidation();
- this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, ExecuteUndo, CanExecuteUndo));
- this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, ExecuteRedo, CanExecuteRedo));
- this.CommandBindings.AddRange(CaretNavigationCommandHandler.CommandBindings);
- this.InputBindings.AddRange(CaretNavigationCommandHandler.InputBindings);
-
- this.CommandBindings.AddRange(EditingCommandHandler.CommandBindings);
- this.InputBindings.AddRange(EditingCommandHandler.InputBindings);
-
- new SelectionMouseHandler(this).Attach();
+ this.DefaultInputHandler = new TextAreaDefaultInputHandler(this);
+ this.ActiveInputHandler = this.DefaultInputHandler;
}
#endregion
+ #region InputHandler management
+ ///
+ /// Gets the default input handler.
+ ///
+ public TextAreaDefaultInputHandler DefaultInputHandler { get; private set; }
+
+ ITextAreaInputHandler activeInputHandler;
+
+ ///
+ /// Gets/Sets the active input handler.
+ ///
+ public ITextAreaInputHandler ActiveInputHandler {
+ get { return activeInputHandler; }
+ set {
+ if (value != null && value.TextArea != this)
+ throw new ArgumentException("The input handler was created for a different text area than this one.");
+ if (activeInputHandler != value) {
+ if (activeInputHandler != null)
+ activeInputHandler.Detach();
+ activeInputHandler = value;
+ if (value != null)
+ value.Attach();
+ if (ActiveInputHandlerChanged != null)
+ ActiveInputHandlerChanged(this, EventArgs.Empty);
+ }
+ }
+ }
+
+ ///
+ /// Occurs when the ActiveInputHandler property changes.
+ ///
+ public event EventHandler ActiveInputHandlerChanged;
+ #endregion
+
#region Document property
///
/// Document property.
@@ -330,43 +357,6 @@ namespace ICSharpCode.AvalonEdit
}
#endregion
- #region Undo / Redo
- UndoStack GetUndoStack()
- {
- TextDocument document = this.Document;
- if (document != null)
- return document.UndoStack;
- else
- return null;
- }
-
- void ExecuteUndo(object sender, ExecutedRoutedEventArgs e)
- {
- var undoStack = GetUndoStack();
- if (undoStack != null && undoStack.CanUndo)
- undoStack.Undo();
- }
-
- void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e)
- {
- var undoStack = GetUndoStack();
- e.CanExecute = undoStack != null && undoStack.CanUndo;
- }
-
- void ExecuteRedo(object sender, ExecutedRoutedEventArgs e)
- {
- var undoStack = GetUndoStack();
- if (undoStack != null && undoStack.CanRedo)
- undoStack.Redo();
- }
-
- void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e)
- {
- var undoStack = GetUndoStack();
- e.CanExecute = undoStack != null && undoStack.CanRedo;
- }
- #endregion
-
#region IScrollInfo implementation
ScrollViewer scrollOwner;
bool canVerticallyScroll, canHorizontallyScroll;
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs
new file mode 100644
index 0000000000..17c7252df0
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs
@@ -0,0 +1,84 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Windows.Input;
+using ICSharpCode.AvalonEdit.Document;
+
+namespace ICSharpCode.AvalonEdit.Gui
+{
+ ///
+ /// Contains the predefined input handlers.
+ ///
+ public class TextAreaDefaultInputHandler : TextAreaInputHandler
+ {
+ ///
+ /// Gets the caret navigation input handler.
+ ///
+ public TextAreaInputHandler CaretNavigation { get; private set; }
+
+ ///
+ /// Gets the editing input handler.
+ ///
+ public TextAreaInputHandler Editing { get; private set; }
+
+ ///
+ /// Gets the mouse selection input handler.
+ ///
+ public ITextAreaInputHandler MouseSelection { get; private set; }
+
+ ///
+ /// Creates a new TextAreaDefaultInputHandler instance.
+ ///
+ public TextAreaDefaultInputHandler(TextArea textArea) : base(textArea)
+ {
+ this.NestedInputHandlers.Add(CaretNavigation = CaretNavigationCommandHandler.Create(textArea));
+ this.NestedInputHandlers.Add(Editing = EditingCommandHandler.Create(textArea));
+ this.NestedInputHandlers.Add(MouseSelection = new SelectionMouseHandler(textArea));
+
+ this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, ExecuteUndo, CanExecuteUndo));
+ this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, ExecuteRedo, CanExecuteRedo));
+ }
+
+ #region Undo / Redo
+ UndoStack GetUndoStack()
+ {
+ TextDocument document = this.TextArea.Document;
+ if (document != null)
+ return document.UndoStack;
+ else
+ return null;
+ }
+
+ void ExecuteUndo(object sender, ExecutedRoutedEventArgs e)
+ {
+ var undoStack = GetUndoStack();
+ if (undoStack != null && undoStack.CanUndo)
+ undoStack.Undo();
+ }
+
+ void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e)
+ {
+ var undoStack = GetUndoStack();
+ e.CanExecute = undoStack != null && undoStack.CanUndo;
+ }
+
+ void ExecuteRedo(object sender, ExecutedRoutedEventArgs e)
+ {
+ var undoStack = GetUndoStack();
+ if (undoStack != null && undoStack.CanRedo)
+ undoStack.Redo();
+ }
+
+ void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e)
+ {
+ var undoStack = GetUndoStack();
+ e.CanExecute = undoStack != null && undoStack.CanRedo;
+ }
+ #endregion
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaInputHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaInputHandler.cs
new file mode 100644
index 0000000000..481290fe90
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaInputHandler.cs
@@ -0,0 +1,184 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using ICSharpCode.AvalonEdit.Utils;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Windows.Input;
+
+namespace ICSharpCode.AvalonEdit.Gui
+{
+ ///
+ /// A set of input bindings and event handlers for the text area.
+ ///
+ public interface ITextAreaInputHandler
+ {
+ ///
+ /// Gets the text area that the input handler belongs to.
+ ///
+ TextArea TextArea {
+ get;
+ }
+
+ ///
+ /// Attaches an input handler to the text area.
+ ///
+ void Attach();
+
+ ///
+ /// Detaches the input handler from the text area.
+ ///
+ void Detach();
+ }
+
+ ///
+ /// Default-implementation of .
+ ///
+ public class TextAreaInputHandler : ITextAreaInputHandler
+ {
+ readonly ObserveAddRemoveCollection commandBindings;
+ readonly ObserveAddRemoveCollection inputBindings;
+ readonly ObserveAddRemoveCollection nestedInputHandlers;
+ readonly TextArea textArea;
+ bool isAttached;
+
+ ///
+ /// Creates a new TextAreaInputHandler.
+ ///
+ public TextAreaInputHandler(TextArea textArea)
+ {
+ if (textArea == null)
+ throw new ArgumentNullException("textArea");
+ this.textArea = textArea;
+ commandBindings = new ObserveAddRemoveCollection(CommandBinding_Added, CommandBinding_Removed);
+ inputBindings = new ObserveAddRemoveCollection(InputBinding_Added, InputBinding_Removed);
+ nestedInputHandlers = new ObserveAddRemoveCollection(NestedInputHandler_Added, NestedInputHandler_Removed);
+ }
+
+ ///
+ public TextArea TextArea {
+ get { return textArea; }
+ }
+
+ ///
+ /// Gets whether the input handler is currently attached to the text area.
+ ///
+ public bool IsAttached {
+ get { return isAttached; }
+ }
+
+ #region CommandBindings / InputBindings
+ ///
+ /// Gets the command bindings of this input handler.
+ ///
+ public ICollection CommandBindings {
+ get { return commandBindings; }
+ }
+
+ void CommandBinding_Added(CommandBinding commandBinding)
+ {
+ if (isAttached)
+ textArea.CommandBindings.Add(commandBinding);
+ }
+
+ void CommandBinding_Removed(CommandBinding commandBinding)
+ {
+ if (isAttached)
+ textArea.CommandBindings.Remove(commandBinding);
+ }
+
+ ///
+ /// Gets the input bindings of this input handler.
+ ///
+ public ICollection InputBindings {
+ get { return inputBindings; }
+ }
+
+ void InputBinding_Added(InputBinding inputBinding)
+ {
+ if (isAttached)
+ textArea.InputBindings.Add(inputBinding);
+ }
+
+ void InputBinding_Removed(InputBinding inputBinding)
+ {
+ if (isAttached)
+ textArea.InputBindings.Remove(inputBinding);
+ }
+
+ ///
+ /// Adds a command and input binding.
+ ///
+ /// The command ID.
+ /// The modifiers of the keyboard shortcut.
+ /// The key of the keyboard shortcut.
+ /// The event handler to run when the command is executed.
+ protected void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
+ {
+ this.CommandBindings.Add(new CommandBinding(command, handler));
+ this.InputBindings.Add(new KeyBinding(command, key, modifiers));
+ }
+ #endregion
+
+ #region NestedInputHandlers
+ ///
+ /// Gets the collection of nested input handlers. NestedInputHandlers are activated and deactivated
+ /// together with this input handler.
+ ///
+ public ICollection NestedInputHandlers {
+ get { return nestedInputHandlers; }
+ }
+
+ void NestedInputHandler_Added(ITextAreaInputHandler handler)
+ {
+ if (handler == null)
+ throw new ArgumentNullException("handler");
+ if (handler.TextArea != textArea)
+ throw new ArgumentException("The nested handler must be working for the same text area!");
+ if (isAttached)
+ handler.Attach();
+ }
+
+ void NestedInputHandler_Removed(ITextAreaInputHandler handler)
+ {
+ if (isAttached)
+ handler.Detach();
+ }
+ #endregion
+
+ #region Attach/Detach
+ ///
+ public virtual void Attach()
+ {
+ if (isAttached)
+ throw new InvalidOperationException("Input handler is already attached");
+ isAttached = true;
+
+ textArea.CommandBindings.AddRange(commandBindings);
+ textArea.InputBindings.AddRange(inputBindings);
+ foreach (ITextAreaInputHandler handler in nestedInputHandlers)
+ handler.Attach();
+ }
+
+ ///
+ public virtual void Detach()
+ {
+ if (!isAttached)
+ throw new InvalidOperationException("Input handler is not attached");
+ isAttached = false;
+
+ foreach (CommandBinding b in commandBindings)
+ textArea.CommandBindings.Remove(b);
+ foreach (InputBinding b in inputBindings)
+ textArea.InputBindings.Remove(b);
+ foreach (ITextAreaInputHandler handler in nestedInputHandlers)
+ handler.Detach();
+ }
+ #endregion
+ }
+}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
index 5f0cdebf6f..3997b895ce 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
@@ -50,9 +50,9 @@ namespace ICSharpCode.AvalonEdit.Gui
public TextView()
{
textLayer = new TextLayer(this);
- elementGenerators.CollectionChanged += elementGenerators_CollectionChanged;
- lineTransformers.CollectionChanged += lineTransformers_CollectionChanged;
- backgroundRenderer.CollectionChanged += backgroundRenderer_CollectionChanged;
+ elementGenerators = new ObserveAddRemoveCollection(ElementGenerator_Added, ElementGenerator_Removed);
+ lineTransformers = new ObserveAddRemoveCollection(LineTransformer_Added, LineTransformer_Removed);
+ backgroundRenderers = new ObserveAddRemoveCollection(BackgroundRenderer_Added, BackgroundRenderer_Removed);
layers = new UIElementCollection(this, this);
InsertLayer(textLayer, KnownLayer.Text, LayerInsertionPosition.Replace);
}
@@ -128,33 +128,45 @@ namespace ICSharpCode.AvalonEdit.Gui
#endregion
#region ElementGenerators+LineTransformers Properties
- readonly ObservableCollection elementGenerators = new ObservableCollection();
+ readonly ObserveAddRemoveCollection elementGenerators;
///
/// Gets a collection where element generators can be registered.
///
- public ObservableCollection ElementGenerators {
+ public IList ElementGenerators {
get { return elementGenerators; }
}
- void elementGenerators_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ void ElementGenerator_Added(VisualLineElementGenerator generator)
{
- HandleTextViewConnect(e);
+ ConnectToTextView(generator);
Redraw();
}
- readonly ObservableCollection lineTransformers = new ObservableCollection();
+ void ElementGenerator_Removed(VisualLineElementGenerator generator)
+ {
+ DisconnectFromTextView(generator);
+ Redraw();
+ }
+
+ readonly ObserveAddRemoveCollection lineTransformers;
///
/// Gets a collection where line transformers can be registered.
///
- public ObservableCollection LineTransformers {
+ public IList LineTransformers {
get { return lineTransformers; }
}
- void lineTransformers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ void LineTransformer_Added(IVisualLineTransformer lineTransformer)
+ {
+ ConnectToTextView(lineTransformer);
+ Redraw();
+ }
+
+ void LineTransformer_Removed(IVisualLineTransformer lineTransformer)
{
- HandleTextViewConnect(e);
+ DisconnectFromTextView(lineTransformer);
Redraw();
}
#endregion
@@ -700,18 +712,29 @@ namespace ICSharpCode.AvalonEdit.Gui
#endregion
#region Render
- readonly ObservableCollection backgroundRenderer = new ObservableCollection();
+ readonly ObserveAddRemoveCollection backgroundRenderers;
///
/// Gets the list of background renderers.
///
- public ObservableCollection BackgroundRenderer {
- get { return backgroundRenderer; }
+ public IList BackgroundRenderers {
+ get { return backgroundRenderers; }
+ }
+
+ void BackgroundRenderer_Added(IBackgroundRenderer renderer)
+ {
+ ConnectToTextView(renderer);
+ InvalidateVisualAndLayerVisuals();
}
- void backgroundRenderer_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ void BackgroundRenderer_Removed(IBackgroundRenderer renderer)
+ {
+ DisconnectFromTextView(renderer);
+ InvalidateVisualAndLayerVisuals();
+ }
+
+ void InvalidateVisualAndLayerVisuals()
{
- HandleTextViewConnect(e);
InvalidateVisual();
foreach (UIElement layer in this.Layers) {
// invalidate known layers
@@ -728,7 +751,7 @@ namespace ICSharpCode.AvalonEdit.Gui
internal void RenderBackground(DrawingContext drawingContext, KnownLayer layer)
{
- foreach (IBackgroundRenderer bg in backgroundRenderer) {
+ foreach (IBackgroundRenderer bg in backgroundRenderers) {
if (bg.Layer == layer) {
bg.Draw(drawingContext);
}
@@ -1155,27 +1178,18 @@ namespace ICSharpCode.AvalonEdit.Gui
return services.GetService(serviceType);
}
- void HandleTextViewConnect(NotifyCollectionChangedEventArgs e)
+ void ConnectToTextView(object obj)
{
- switch (e.Action) {
- case NotifyCollectionChangedAction.Add:
- case NotifyCollectionChangedAction.Remove:
- case NotifyCollectionChangedAction.Replace:
- if (e.OldItems != null) {
- foreach (ITextViewConnect c in e.OldItems.OfType())
- c.RemoveFromTextView(this);
- }
- if (e.NewItems != null) {
- foreach (ITextViewConnect c in e.NewItems.OfType())
- c.AddToTextView(this);
- }
- break;
- case NotifyCollectionChangedAction.Move:
- // ignore Move
- break;
- default:
- throw new NotSupportedException(e.Action.ToString());
- }
+ ITextViewConnect c = obj as ITextViewConnect;
+ if (c != null)
+ c.AddToTextView(this);
+ }
+
+ void DisconnectFromTextView(object obj)
+ {
+ ITextViewConnect c = obj as ITextViewConnect;
+ if (c != null)
+ c.RemoveFromTextView(this);
}
#endregion
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
index 74a7d73248..4b1abe7251 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
@@ -134,6 +134,8 @@
FoldingManager.cs
+
+
TextView.cs
@@ -278,6 +280,7 @@
+
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
new file mode 100644
index 0000000000..2f13a4f972
--- /dev/null
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
@@ -0,0 +1,64 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.ObjectModel;
+
+namespace ICSharpCode.AvalonEdit.Utils
+{
+ ///
+ /// A collection where adding and removing items causes a callback.
+ ///
+ sealed class ObserveAddRemoveCollection : Collection
+ {
+ readonly Action onAdd, onRemove;
+
+ public ObserveAddRemoveCollection(Action onAdd, Action onRemove)
+ {
+ this.onAdd = onAdd;
+ this.onRemove = onRemove;
+ }
+
+ protected override void ClearItems()
+ {
+ if (onRemove != null) {
+ foreach (T val in this)
+ onRemove(val);
+ }
+ base.ClearItems();
+ }
+
+ protected override void InsertItem(int index, T item)
+ {
+ if (onAdd != null)
+ onAdd(item);
+ base.InsertItem(index, item);
+ }
+
+ protected override void RemoveItem(int index)
+ {
+ if (onRemove != null)
+ onRemove(this[index]);
+ base.RemoveItem(index);
+ }
+
+ protected override void SetItem(int index, T item)
+ {
+ if (onRemove != null)
+ onRemove(this[index]);
+ try {
+ if (onAdd != null)
+ onAdd(item);
+ } catch {
+ // when adding the new item fails, just remove the old one
+ base.RemoveAt(index);
+ throw;
+ }
+ base.SetItem(index, item);
+ }
+ }
+}
diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
index 71a8f55cbe..b01753ae4f 100644
--- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
+++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
@@ -750,10 +750,6 @@
-
- {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}
- ICSharpCode.AvalonEdit
-
{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}
ICSharpCode.TextEditor
diff --git a/src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs b/src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs
index 4948c977d2..36fce41423 100644
--- a/src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs
+++ b/src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs
@@ -37,6 +37,11 @@ namespace ICSharpCode.SharpDevelop
}
public virtual ExpressionResult GetExpression(ITextEditor editor)
+ {
+ return GetExpressionFromOffset(editor, editor.Caret.Offset);
+ }
+
+ protected ExpressionResult GetExpressionFromOffset(ITextEditor editor, int offset)
{
if (editor == null)
throw new ArgumentNullException("editor");
@@ -45,7 +50,7 @@ namespace ICSharpCode.SharpDevelop
if (expressionFinder == null) {
return ExpressionResult.Empty;
} else {
- return expressionFinder.FindExpression(document.GetText(0, editor.Caret.Offset), editor.Caret.Offset);
+ return expressionFinder.FindExpression(document.GetText(0, offset), offset);
}
}
@@ -92,6 +97,11 @@ namespace ICSharpCode.SharpDevelop
}
}
+ public class DotCodeCompletionItemProvider : CodeCompletionItemProvider
+ {
+
+ }
+
public class CodeCompletionItem : ICompletionItem
{
readonly IEntity entity;
diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs
index 4693a287bf..63d86fe116 100644
--- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs
+++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs
@@ -18,10 +18,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
///
public interface ICodeCompletionBinding
{
- bool HandleKeyPress(ITextEditor editor, char ch);
+ CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch);
bool CtrlSpace(ITextEditor editor);
}
+ ///
+ /// The result of .
+ ///
+ public enum CodeCompletionKeyPressResult
+ {
+ ///
+ /// The binding did not run code completion. The pressed key will be handled normally.
+ ///
+ None,
+ ///
+ /// The binding handled code completion, the pressed key will be handled normally.
+ ///
+ Completed,
+ ///
+ /// The binding handled code completion, and the key will not be handled by the text editor.
+ ///
+ EatKey
+ }
+
///
/// Creates code completion bindings that manage code completion for one language.
///
@@ -68,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
this.extensions = extensions;
}
- public bool HandleKeyPress(ITextEditor editor, char ch)
+ public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
string ext = Path.GetExtension(editor.FileName);
foreach (string extension in extensions) {
@@ -79,7 +98,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
return binding.HandleKeyPress(editor, ch);
}
}
- return false;
+ return CodeCompletionKeyPressResult.None;
}
public bool CtrlSpace(ITextEditor editor)
@@ -140,48 +159,43 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
}
}
- public virtual bool HandleKeyPress(ITextEditor editor, char ch)
+ public virtual CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
switch (ch) {
case '(':
if (enableMethodInsight && CodeCompletionOptions.InsightEnabled) {
editor.ShowInsightWindow(new MethodInsightDataProvider());
- return true;
- } else {
- return false;
+ return CodeCompletionKeyPressResult.Completed;
}
+ break;
case '[':
if (enableIndexerInsight && CodeCompletionOptions.InsightEnabled) {
editor.ShowInsightWindow(new IndexerInsightDataProvider());
- return true;
- } else {
- return false;
+ return CodeCompletionKeyPressResult.Completed;
}
+ break;
case '<':
if (enableXmlCommentCompletion) {
editor.ShowCompletionWindow(new CommentCompletionDataProvider(), ch);
- return true;
- } else {
- return false;
+ return CodeCompletionKeyPressResult.Completed;
}
+ break;
case '.':
if (enableDotCompletion) {
- new CodeCompletionItemProvider().ShowCompletion(editor);
- return true;
- } else {
- return false;
+ new DotCodeCompletionItemProvider().ShowCompletion(editor);
+ return CodeCompletionKeyPressResult.Completed;
}
+ break;
case ' ':
- if (!CodeCompletionOptions.KeywordCompletionEnabled)
- return false;
- string word = editor.GetWordBeforeCaret();
- if (word != null)
- return HandleKeyword(editor, word);
- else
- return false;
- default:
- return false;
+ if (CodeCompletionOptions.KeywordCompletionEnabled) {
+ string word = editor.GetWordBeforeCaret();
+ if (word != null) {
+ return HandleKeyword(editor, word) ? CodeCompletionKeyPressResult.Completed : CodeCompletionKeyPressResult.None;
+ }
+ }
+ break;
}
+ return CodeCompletionKeyPressResult.None;
}
public virtual bool HandleKeyword(ITextEditor editor, string word)
diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
index 4171584f04..1d6eb6420a 100644
--- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
+++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
@@ -328,8 +328,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
if (CodeCompletionOptions.EnableCodeCompletion) {
foreach (ICodeCompletionBinding ccBinding in CodeCompletionBindings) {
- if (ccBinding.HandleKeyPress(adapter, ch))
+ CodeCompletionKeyPressResult result = ccBinding.HandleKeyPress(adapter, ch);
+ if (result == CodeCompletionKeyPressResult.Completed)
return false;
+ else if (result == CodeCompletionKeyPressResult.EatKey)
+ return true;
}
}
} catch (Exception ex) {
diff --git a/src/Main/Base/Project/Src/TextEditor/ITextEditor.cs b/src/Main/Base/Project/Src/TextEditor/ITextEditor.cs
index f80aa75ab6..28813af114 100644
--- a/src/Main/Base/Project/Src/TextEditor/ITextEditor.cs
+++ b/src/Main/Base/Project/Src/TextEditor/ITextEditor.cs
@@ -38,6 +38,7 @@ namespace ICSharpCode.SharpDevelop
void Select(int selectionStart, int selectionLength);
string FileName { get; }
+
void ShowInsightWindow(ICSharpCode.TextEditor.Gui.InsightWindow.IInsightDataProvider provider);
[Obsolete]
void ShowCompletionWindow(ICSharpCode.TextEditor.Gui.CompletionWindow.ICompletionDataProvider provider, char ch);