Browse Source

Improvements to AvalonEdit CompletionWindow. Implemented TextAreaInputHandler.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3889 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
5380d99724
  1. 11
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs
  2. 47
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
  3. 6
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs
  4. 17
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs
  5. 26
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  6. 9
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
  7. 6
      src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs
  8. 8
      src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs
  9. 73
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
  10. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml
  11. 13
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
  12. 77
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
  13. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs
  14. 17
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
  15. 23
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
  16. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs
  17. 78
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
  18. 84
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs
  19. 184
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaInputHandler.cs
  20. 84
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
  21. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj
  22. 64
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs
  23. 4
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  24. 12
      src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs
  25. 64
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs
  26. 5
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
  27. 1
      src/Main/Base/Project/Src/TextEditor/ITextEditor.cs

11
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/CompletionBinding.cs

@ -19,7 +19,7 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -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 @@ -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 @@ -52,12 +52,13 @@ namespace Grunwald.BooBinding.CodeCompletion
return true;
case "as":
case "isa":
if (IsInComment(editor)) return false;
if (!IsInComment(editor)) {
editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(ExpressionContext.Type), ' ');
return true;
default:
return base.HandleKeyword(editor, word);
}
break;
}
return base.HandleKeyword(editor, word);
}
}
}

47
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs

@ -33,21 +33,21 @@ namespace CSharpBinding @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -129,6 +130,7 @@ namespace CSharpBinding
ShowTemplates = true,
AllowCompleteExistingExpression = afterUnderscore
}, '\0');
return CodeCompletionKeyPressResult.Completed;
}
}
}
@ -136,7 +138,7 @@ namespace CSharpBinding @@ -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 @@ -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 @@ -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 @@ -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 false;
}
break;
case "as":
case "is":
if (IsInComment(editor)) return false;
@ -214,12 +211,10 @@ namespace CSharpBinding @@ -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)

6
src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs

@ -32,14 +32,14 @@ namespace VBNetBinding @@ -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));
}

17
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/AvalonEditTextEditorAdapter.cs

@ -5,14 +5,16 @@ @@ -5,14 +5,16 @@
// <version>$Revision$</version>
// </file>
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 @@ -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 @@ -162,5 +169,9 @@ namespace ICSharpCode.AvalonEdit.AddIn
public object Description {
get { return item.Description; }
}
public ImageSource Image {
get { return null; }
}
}
}

26
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -5,11 +5,11 @@ @@ -5,11 +5,11 @@
// <version>$Revision$</version>
// </file>
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 @@ -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; };
}
}
}

9
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs

@ -5,7 +5,9 @@ @@ -5,7 +5,9 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop;
using System;
using ICSharpCode.AvalonEdit.CodeCompletion;
namespace ICSharpCode.AvalonEdit.AddIn
{
@ -26,5 +28,12 @@ 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;
}
}
}

6
src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs

@ -20,7 +20,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion @@ -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 @@ -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;
}
// ********************************************************************************************************************************

8
src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs

@ -21,7 +21,7 @@ namespace Hornung.ResourceToolkit.CodeCompletion @@ -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 @@ -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 @@ -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;
}
}

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

@ -111,6 +111,74 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -111,6 +111,74 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
}
/// <summary>
/// Selects the item that starts with the specified text.
/// </summary>
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 @@ -120,5 +188,10 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
listBox.SelectedIndex = offset;
listBox.ScrollIntoView(listBox.SelectedItem);
}
void CenterViewOn(int offset)
{
// TODO: implement me
}
}
}

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml

@ -41,7 +41,10 @@ @@ -41,7 +41,10 @@
<cc:CompletionListBox x:Name="PART_ListBox" ItemContainerStyle="{StaticResource CompletionListBoxItem}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}"/>
<ContentControl Content="{Binding Content}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</cc:CompletionListBox>

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

@ -32,6 +32,19 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -32,6 +32,19 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
}
}
/// <summary>
/// Gets the number of the first visible item.
/// </summary>
public int FirstVisibleItem {
get {
if (scrollViewer == null) {
return 0;
} else {
return (int)(this.Items.Count * scrollViewer.VerticalOffset / scrollViewer.ExtentHeight);
}
}
}
/// <summary>
/// Gets the number of visible items.
/// </summary>

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

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
@ -13,6 +14,7 @@ using System.Windows.Input; @@ -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 @@ -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)
/// <summary>
/// Gets/Sets the start offset of the edited text portion.
/// </summary>
public int StartOffset {
get { return startOffset; }
set { startOffset = value; }
}
/// <summary>
/// Gets/Sets the end offset of the edited text portion.
/// </summary>
public int EndOffset {
get { return endOffset; }
set { endOffset = value; }
}
/// <inheritdoc/>
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);
}
/// <inheritdoc/>
@ -60,6 +77,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -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);
}
/// <inheritdoc/>
@ -69,8 +87,42 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -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
/// <summary>
/// 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.
/// </summary>
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
/// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e)
{
@ -104,12 +156,19 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -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 @@ -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));
}
}

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICodeCompletionData.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Windows.Media;
namespace ICSharpCode.AvalonEdit.CodeCompletion
{
@ -14,6 +15,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -14,6 +15,11 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// </summary>
public interface ICompletionData
{
/// <summary>
/// Gets the image.
/// </summary>
ImageSource Image { get; }
/// <summary>
/// Gets the text. This property is used to filter the list of visible elements.
/// </summary>

17
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs

@ -6,11 +6,13 @@ @@ -6,11 +6,13 @@
// </file>
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 @@ -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();
/// <summary>
/// Creates a new <see cref="TextAreaInputHandler"/> for the text area.
/// </summary>
public static TextAreaInputHandler Create(TextArea textArea)
{
TextAreaInputHandler handler = new TextAreaInputHandler(textArea);
handler.CommandBindings.AddRange(CommandBindings);
handler.InputBindings.AddRange(InputBindings);
return handler;
}
static readonly List<CommandBinding> CommandBindings = new List<CommandBinding>();
static readonly List<InputBinding> InputBindings = new List<InputBinding>();
static void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
{

23
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs

@ -6,24 +6,37 @@ @@ -6,24 +6,37 @@
// </file>
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
{
/// <summary>
/// We re-use the CommandBinding and InputBinding instances between multiple text areas,
/// so this class is static.
/// </summary>
static class EditingCommandHandler
{
public static readonly CommandBindingCollection CommandBindings = new CommandBindingCollection();
public static readonly InputBindingCollection InputBindings = new InputBindingCollection();
/// <summary>
/// Creates a new <see cref="TextAreaInputHandler"/> for the text area.
/// </summary>
public static TextAreaInputHandler Create(TextArea textArea)
{
TextAreaInputHandler handler = new TextAreaInputHandler(textArea);
handler.CommandBindings.AddRange(CommandBindings);
handler.InputBindings.AddRange(InputBindings);
return handler;
}
static readonly List<CommandBinding> CommandBindings = new List<CommandBinding>();
static readonly List<InputBinding> InputBindings = new List<InputBinding>();
static void AddBinding(ICommand command, ModifierKeys modifiers, Key key, ExecutedRoutedEventHandler handler)
{

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/SelectionMouseHandler.cs

@ -21,7 +21,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -21,7 +21,7 @@ namespace ICSharpCode.AvalonEdit.Gui
/// <summary>
/// Handles selection of text using the mouse.
/// </summary>
sealed class SelectionMouseHandler
sealed class SelectionMouseHandler : ITextAreaInputHandler
{
#region enum SelectionMode
enum SelectionMode
@ -62,9 +62,15 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -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;

78
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs

@ -77,17 +77,44 @@ namespace ICSharpCode.AvalonEdit @@ -77,17 +77,44 @@ 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.DefaultInputHandler = new TextAreaDefaultInputHandler(this);
this.ActiveInputHandler = this.DefaultInputHandler;
}
#endregion
#region InputHandler management
/// <summary>
/// Gets the default input handler.
/// </summary>
public TextAreaDefaultInputHandler DefaultInputHandler { get; private set; }
this.CommandBindings.AddRange(EditingCommandHandler.CommandBindings);
this.InputBindings.AddRange(EditingCommandHandler.InputBindings);
ITextAreaInputHandler activeInputHandler;
new SelectionMouseHandler(this).Attach();
/// <summary>
/// Gets/Sets the active input handler.
/// </summary>
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);
}
}
}
/// <summary>
/// Occurs when the ActiveInputHandler property changes.
/// </summary>
public event EventHandler ActiveInputHandlerChanged;
#endregion
#region Document property
@ -330,43 +357,6 @@ namespace ICSharpCode.AvalonEdit @@ -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;

84
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaDefaultInputHandlers.cs

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Gui
{
/// <summary>
/// Contains the predefined input handlers.
/// </summary>
public class TextAreaDefaultInputHandler : TextAreaInputHandler
{
/// <summary>
/// Gets the caret navigation input handler.
/// </summary>
public TextAreaInputHandler CaretNavigation { get; private set; }
/// <summary>
/// Gets the editing input handler.
/// </summary>
public TextAreaInputHandler Editing { get; private set; }
/// <summary>
/// Gets the mouse selection input handler.
/// </summary>
public ITextAreaInputHandler MouseSelection { get; private set; }
/// <summary>
/// Creates a new TextAreaDefaultInputHandler instance.
/// </summary>
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
}
}

184
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextAreaInputHandler.cs

@ -0,0 +1,184 @@ @@ -0,0 +1,184 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace ICSharpCode.AvalonEdit.Gui
{
/// <summary>
/// A set of input bindings and event handlers for the text area.
/// </summary>
public interface ITextAreaInputHandler
{
/// <summary>
/// Gets the text area that the input handler belongs to.
/// </summary>
TextArea TextArea {
get;
}
/// <summary>
/// Attaches an input handler to the text area.
/// </summary>
void Attach();
/// <summary>
/// Detaches the input handler from the text area.
/// </summary>
void Detach();
}
/// <summary>
/// Default-implementation of <see cref="ITextAreaInputHandler"/>.
/// </summary>
public class TextAreaInputHandler : ITextAreaInputHandler
{
readonly ObserveAddRemoveCollection<CommandBinding> commandBindings;
readonly ObserveAddRemoveCollection<InputBinding> inputBindings;
readonly ObserveAddRemoveCollection<ITextAreaInputHandler> nestedInputHandlers;
readonly TextArea textArea;
bool isAttached;
/// <summary>
/// Creates a new TextAreaInputHandler.
/// </summary>
public TextAreaInputHandler(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this.textArea = textArea;
commandBindings = new ObserveAddRemoveCollection<CommandBinding>(CommandBinding_Added, CommandBinding_Removed);
inputBindings = new ObserveAddRemoveCollection<InputBinding>(InputBinding_Added, InputBinding_Removed);
nestedInputHandlers = new ObserveAddRemoveCollection<ITextAreaInputHandler>(NestedInputHandler_Added, NestedInputHandler_Removed);
}
/// <inheritdoc/>
public TextArea TextArea {
get { return textArea; }
}
/// <summary>
/// Gets whether the input handler is currently attached to the text area.
/// </summary>
public bool IsAttached {
get { return isAttached; }
}
#region CommandBindings / InputBindings
/// <summary>
/// Gets the command bindings of this input handler.
/// </summary>
public ICollection<CommandBinding> 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);
}
/// <summary>
/// Gets the input bindings of this input handler.
/// </summary>
public ICollection<InputBinding> 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);
}
/// <summary>
/// Adds a command and input binding.
/// </summary>
/// <param name="command">The command ID.</param>
/// <param name="modifiers">The modifiers of the keyboard shortcut.</param>
/// <param name="key">The key of the keyboard shortcut.</param>
/// <param name="handler">The event handler to run when the command is executed.</param>
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
/// <summary>
/// Gets the collection of nested input handlers. NestedInputHandlers are activated and deactivated
/// together with this input handler.
/// </summary>
public ICollection<ITextAreaInputHandler> 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
/// <inheritdoc/>
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();
}
/// <inheritdoc/>
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
}
}

84
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs

@ -50,9 +50,9 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -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<VisualLineElementGenerator>(ElementGenerator_Added, ElementGenerator_Removed);
lineTransformers = new ObserveAddRemoveCollection<IVisualLineTransformer>(LineTransformer_Added, LineTransformer_Removed);
backgroundRenderers = new ObserveAddRemoveCollection<IBackgroundRenderer>(BackgroundRenderer_Added, BackgroundRenderer_Removed);
layers = new UIElementCollection(this, this);
InsertLayer(textLayer, KnownLayer.Text, LayerInsertionPosition.Replace);
}
@ -128,33 +128,45 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -128,33 +128,45 @@ namespace ICSharpCode.AvalonEdit.Gui
#endregion
#region ElementGenerators+LineTransformers Properties
readonly ObservableCollection<VisualLineElementGenerator> elementGenerators = new ObservableCollection<VisualLineElementGenerator>();
readonly ObserveAddRemoveCollection<VisualLineElementGenerator> elementGenerators;
/// <summary>
/// Gets a collection where element generators can be registered.
/// </summary>
public ObservableCollection<VisualLineElementGenerator> ElementGenerators {
public IList<VisualLineElementGenerator> ElementGenerators {
get { return elementGenerators; }
}
void elementGenerators_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
void ElementGenerator_Added(VisualLineElementGenerator generator)
{
HandleTextViewConnect(e);
ConnectToTextView(generator);
Redraw();
}
readonly ObservableCollection<IVisualLineTransformer> lineTransformers = new ObservableCollection<IVisualLineTransformer>();
void ElementGenerator_Removed(VisualLineElementGenerator generator)
{
DisconnectFromTextView(generator);
Redraw();
}
readonly ObserveAddRemoveCollection<IVisualLineTransformer> lineTransformers;
/// <summary>
/// Gets a collection where line transformers can be registered.
/// </summary>
public ObservableCollection<IVisualLineTransformer> LineTransformers {
public IList<IVisualLineTransformer> 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 @@ -700,18 +712,29 @@ namespace ICSharpCode.AvalonEdit.Gui
#endregion
#region Render
readonly ObservableCollection<IBackgroundRenderer> backgroundRenderer = new ObservableCollection<IBackgroundRenderer>();
readonly ObserveAddRemoveCollection<IBackgroundRenderer> backgroundRenderers;
/// <summary>
/// Gets the list of background renderers.
/// </summary>
public ObservableCollection<IBackgroundRenderer> BackgroundRenderer {
get { return backgroundRenderer; }
public IList<IBackgroundRenderer> 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 @@ -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 @@ -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<ITextViewConnect>())
c.RemoveFromTextView(this);
}
if (e.NewItems != null) {
foreach (ITextViewConnect c in e.NewItems.OfType<ITextViewConnect>())
ITextViewConnect c = obj as ITextViewConnect;
if (c != null)
c.AddToTextView(this);
}
break;
case NotifyCollectionChangedAction.Move:
// ignore Move
break;
default:
throw new NotSupportedException(e.Action.ToString());
}
void DisconnectFromTextView(object obj)
{
ITextViewConnect c = obj as ITextViewConnect;
if (c != null)
c.RemoveFromTextView(this);
}
#endregion

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -134,6 +134,8 @@ @@ -134,6 +134,8 @@
<DependentUpon>FoldingManager.cs</DependentUpon>
</Compile>
<Compile Include="Gui\IBackgroundRenderer.cs" />
<Compile Include="Gui\TextAreaDefaultInputHandlers.cs" />
<Compile Include="Gui\TextAreaInputHandler.cs" />
<Compile Include="Gui\IReadOnlySectionProvider.cs" />
<Compile Include="Gui\ITextViewConnect.cs">
<DependentUpon>TextView.cs</DependentUpon>
@ -278,6 +280,7 @@ @@ -278,6 +280,7 @@
<Compile Include="Utils\HtmlClipboard.cs" />
<Compile Include="Utils\ImmutableStack.cs" />
<Compile Include="Utils\NullSafeCollection.cs" />
<Compile Include="Utils\ObserveAddRemoveCollection.cs" />
<Compile Include="Utils\TextUtilities.cs" />
<Compile Include="Utils\WeakEventManagerBase.cs" />
<Compile Include="Utils\PixelSnapHelpers.cs" />

64
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/ObserveAddRemoveCollection.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.ObjectModel;
namespace ICSharpCode.AvalonEdit.Utils
{
/// <summary>
/// A collection where adding and removing items causes a callback.
/// </summary>
sealed class ObserveAddRemoveCollection<T> : Collection<T>
{
readonly Action<T> onAdd, onRemove;
public ObserveAddRemoveCollection(Action<T> onAdd, Action<T> 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);
}
}
}

4
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -750,10 +750,6 @@ @@ -750,10 +750,6 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
<Name>ICSharpCode.AvalonEdit</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\ICSharpCode.TextEditor\Project\ICSharpCode.TextEditor.csproj">
<Project>{2D18BE89-D210-49EB-A9DD-2246FBB3DF6D}</Project>
<Name>ICSharpCode.TextEditor</Name>

12
src/Main/Base/Project/Src/TextEditor/CodeCompletionItemProvider.cs

@ -37,6 +37,11 @@ namespace ICSharpCode.SharpDevelop @@ -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 @@ -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 @@ -92,6 +97,11 @@ namespace ICSharpCode.SharpDevelop
}
}
public class DotCodeCompletionItemProvider : CodeCompletionItemProvider
{
}
public class CodeCompletionItem : ICompletionItem
{
readonly IEntity entity;

64
src/Main/Base/Project/Src/TextEditor/Gui/Editor/CodeCompletionBinding.cs

@ -18,10 +18,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -18,10 +18,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
/// </summary>
public interface ICodeCompletionBinding
{
bool HandleKeyPress(ITextEditor editor, char ch);
CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch);
bool CtrlSpace(ITextEditor editor);
}
/// <summary>
/// The result of <see cref="ICodeCompletionBinding.HandleKeyPress"/>.
/// </summary>
public enum CodeCompletionKeyPressResult
{
/// <summary>
/// The binding did not run code completion. The pressed key will be handled normally.
/// </summary>
None,
/// <summary>
/// The binding handled code completion, the pressed key will be handled normally.
/// </summary>
Completed,
/// <summary>
/// The binding handled code completion, and the key will not be handled by the text editor.
/// </summary>
EatKey
}
/// <summary>
/// Creates code completion bindings that manage code completion for one language.
/// </summary>
@ -68,7 +87,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -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 @@ -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 @@ -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;
if (CodeCompletionOptions.KeywordCompletionEnabled) {
string word = editor.GetWordBeforeCaret();
if (word != null)
return HandleKeyword(editor, word);
else
return false;
default:
return false;
if (word != null) {
return HandleKeyword(editor, word) ? CodeCompletionKeyPressResult.Completed : CodeCompletionKeyPressResult.None;
}
}
break;
}
return CodeCompletionKeyPressResult.None;
}
public virtual bool HandleKeyword(ITextEditor editor, string word)

5
src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

@ -328,8 +328,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -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) {

1
src/Main/Base/Project/Src/TextEditor/ITextEditor.cs

@ -38,6 +38,7 @@ namespace ICSharpCode.SharpDevelop @@ -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);

Loading…
Cancel
Save