Browse Source

Ported event handler completion to ITextEditor.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4188 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
f1b423c05e
  1. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 8
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs
  3. 162
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/EventHandlerCompletionItemProvider.cs
  4. 4
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs
  5. 14
      src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
  6. 7
      src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs
  7. 8
      src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionItemList.cs
  8. 2
      src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs
  9. 11
      src/Main/Base/Project/Src/Editor/ITextEditor.cs
  10. 9
      src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs

8
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -37,12 +37,18 @@ @@ -37,12 +37,18 @@
<OutputPath>..\..\..\..\..\AddIns\AddIns\BackendBindings\CSharpBinding\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.Build.Engine" />
<Reference Include="WindowsBase">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Configuration\AssemblyInfo.cs" />
@ -65,7 +71,7 @@ @@ -65,7 +71,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Include="Src\CSharpCompletionBinding.cs" />
<Compile Include="Src\EventHandlerCompletitionDataProvider.cs" />
<Compile Include="Src\EventHandlerCompletionItemProvider.cs" />
<Compile Include="Src\Project\VBNetToCSharpConverter.cs" />
<Compile Include="..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>Configuration\GlobalAssemblyInfo.cs</Link>

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

@ -5,18 +5,17 @@ @@ -5,18 +5,17 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.CSharp;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using AST = ICSharpCode.NRefactory.Ast;
namespace CSharpBinding
@ -61,9 +60,8 @@ namespace CSharpBinding @@ -61,9 +60,8 @@ namespace CSharpBinding
if (resolveResult != null && resolveResult.ResolvedType != null) {
IClass underlyingClass = resolveResult.ResolvedType.GetUnderlyingClass();
if (underlyingClass != null && underlyingClass.IsTypeInInheritanceTree(ParserService.CurrentProjectContent.GetClass("System.MulticastDelegate", 0))) {
EventHandlerCompletitionDataProvider eventHandlerProvider = new EventHandlerCompletitionDataProvider(result.Expression, resolveResult);
eventHandlerProvider.InsertSpace = true;
editor.ShowCompletionWindow(eventHandlerProvider, ch);
EventHandlerCompletionItemProvider eventHandlerProvider = new EventHandlerCompletionItemProvider(result.Expression, resolveResult);
eventHandlerProvider.ShowCompletion(editor);
return CodeCompletionKeyPressResult.Completed;
}
}

162
src/AddIns/BackendBindings/CSharpBinding/Project/Src/EventHandlerCompletitionDataProvider.cs → src/AddIns/BackendBindings/CSharpBinding/Project/Src/EventHandlerCompletionItemProvider.cs

@ -6,30 +6,25 @@ @@ -6,30 +6,25 @@
// </file>
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.CSharp;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System.Windows.Input;
namespace CSharpBinding
{
public class EventHandlerCompletitionDataProvider : AbstractCompletionDataProvider
public class EventHandlerCompletionItemProvider : AbstractCompletionItemProvider
{
string expression;
ResolveResult resolveResult;
IReturnType resolvedReturnType;
IClass resolvedClass;
public EventHandlerCompletitionDataProvider(string expression, ResolveResult resolveResult)
public EventHandlerCompletionItemProvider(string expression, ResolveResult resolveResult)
{
this.expression = expression;
this.resolveResult = resolveResult;
@ -37,16 +32,14 @@ namespace CSharpBinding @@ -37,16 +32,14 @@ namespace CSharpBinding
this.resolvedClass = resolvedReturnType.GetUnderlyingClass();
}
/// <summary>
/// Generates the completion data. This method is called by the text editor control.
/// </summary>
public override ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped)
public override ICompletionItemList GenerateCompletionList(ITextEditor editor)
{
List<ICompletionData> completionData = new List<ICompletionData>();
DefaultCompletionItemList result = new DefaultCompletionItemList();
result.InsertSpace = true;
// delegate { }
completionData.Add(new DelegateCompletionData("delegate { };", 3,
"${res:CSharpBinding.InsertAnonymousMethod}"));
result.Items.Add(new DelegateCompletionItem("delegate { };", 3,
"${res:CSharpBinding.InsertAnonymousMethod}"));
CSharpAmbience ambience = new CSharpAmbience();
// get eventHandler type name incl. type argument list
@ -73,8 +66,8 @@ namespace CSharpBinding @@ -73,8 +66,8 @@ namespace CSharpBinding
// delegate(object sender, EventArgs e) { };
StringBuilder anonMethodWithParametersBuilder =
new StringBuilder("delegate(").Append(parameterString.ToString()).Append(") { };");
completionData.Add(new DelegateCompletionData(anonMethodWithParametersBuilder.ToString(), 3,
"${res:CSharpBinding.InsertAnonymousMethodWithParameters}"));
result.Items.Add(new DelegateCompletionItem(anonMethodWithParametersBuilder.ToString(), 3,
"${res:CSharpBinding.InsertAnonymousMethodWithParameters}"));
// new EventHandler(ClassName_EventName);
IClass callingClass = resolveResult.CallingClass;
@ -109,13 +102,13 @@ namespace CSharpBinding @@ -109,13 +102,13 @@ namespace CSharpBinding
newHandlerCodeBuilder.Append("}");
// ...and add it to the completionData.
completionData.Add(new NewEventHandlerCompletionData(
result.Items.Add(new NewEventHandlerCompletionItem(
newHandlerTextBuilder.ToString(),
2+newHandlerName.Length,
newHandlerName.Length,
"new " + eventHandlerFullyQualifiedTypeName +
"(" + newHandlerName + StringParser.Parse(")\n${res:CSharpBinding.GenerateNewHandlerInstructions}\n")
+ CodeCompletionData.ConvertDocumentation(resolvedClass.Documentation),
+ CodeCompletionItem.ConvertDocumentation(resolvedClass.Documentation),
resolveResult,
newHandlerCodeBuilder.ToString()
));
@ -139,12 +132,13 @@ namespace CSharpBinding @@ -139,12 +132,13 @@ namespace CSharpBinding
}
}
if (ok) {
completionData.Add(new CodeCompletionData(method));
result.Items.Add(new CodeCompletionItem(method));
}
}
}
}
return completionData.ToArray();
result.SortItems();
return result;
}
string BuildHandlerName()
@ -171,107 +165,103 @@ namespace CSharpBinding @@ -171,107 +165,103 @@ namespace CSharpBinding
return handlerNameBuilder.ToString();
}
private class DelegateCompletionData : DefaultCompletionData
sealed class DelegateCompletionItem : DefaultCompletionItem
{
int cursorOffset;
public DelegateCompletionData(string text, int cursorOffset, string documentation)
: base(text, StringParser.Parse(documentation), ClassBrowserIconService.Delegate.ImageIndex)
public DelegateCompletionItem(string text, int cursorOffset, string documentation)
: base(text)
{
this.cursorOffset = cursorOffset;
this.Description = StringParser.Parse(documentation);
this.Image = ClassBrowserIconService.Delegate;
}
public override bool InsertAction(TextArea textArea, char ch)
public override void Complete(CompletionContext context)
{
bool r = base.InsertAction(textArea, ch);
textArea.Caret.Column -= cursorOffset;
return r;
base.Complete(context);
context.Editor.Caret.Column -= cursorOffset;
}
}
private class NewEventHandlerCompletionData : DefaultCompletionData
sealed class NewEventHandlerCompletionItem : DefaultCompletionItem
{
int selectionBeginOffset;
int selectionLength;
TextArea textArea;
ResolveResult resolveResult;
string newHandlerCode;
public NewEventHandlerCompletionData(string text, int selectionBeginOffset, int selectionLength, string documentation, ResolveResult resolveResult, string newHandlerCode)
: base(text, StringParser.Parse(documentation), ClassBrowserIconService.Delegate.ImageIndex)
ITextEditor editor;
public NewEventHandlerCompletionItem(string text, int selectionBeginOffset, int selectionLength, string documentation, ResolveResult resolveResult, string newHandlerCode)
: base(text)
{
this.selectionBeginOffset = selectionBeginOffset;
this.selectionLength = selectionLength;
this.resolveResult = resolveResult;
this.newHandlerCode = newHandlerCode;
this.Description = StringParser.Parse(documentation);
this.Image = ClassBrowserIconService.Delegate;
}
public override bool InsertAction(TextArea textArea, char ch)
public override void Complete(CompletionContext context)
{
bool r = base.InsertAction(textArea, ch);
base.Complete(context);
// save a reference to the relevant textArea so that we can remove our event handlers after the next keystroke
editor = context.Editor;
// select suggested name
textArea.Caret.Column -= this.selectionBeginOffset;
int selectBegin = textArea.Caret.Offset;
textArea.SelectionManager.SetSelection(
textArea.Document.OffsetToPosition(selectBegin),
textArea.Document.OffsetToPosition(selectBegin + this.selectionLength));
editor.Caret.Column -= this.selectionBeginOffset;
editor.Select(editor.Caret.Offset, this.selectionLength);
// TODO: refactor ToolTip architecture to allow for showing a tooltip relative to the current caret position so that we can show our "press TAB to create this method" text as a text-based tooltip
// TODO: skip the auto-insert step if the method already exists, or change behavior so that it moves the caret inside the existing method.
// attatch our keydown filter to catch the next character pressed
textArea.PreviewKeyDown += new PreviewKeyDownEventHandler(NewEventHandlerPreviewKeyDown);
// save a reference to the relevant textArea so that we can remove our keydown filter after the next keystroke
this.textArea = textArea;
return r;
// attach our keydown filter to catch the next character pressed
editor.SelectionChanged += EditorSelectionChanged;
editor.KeyPress += EditorKeyPress;
}
public void NewEventHandlerPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
void RemoveEventHandlers()
{
if (e.KeyCode == Keys.Tab
|| e.KeyCode == Keys.Enter
|| e.KeyCode == Keys.Return) {
textArea.BeginUpdate();
textArea.Document.UndoStack.StartUndoGroup();
textArea.SelectionManager.ClearSelection();
// is there a better way to calculate the optimal insertion point?
DomRegion region = resolveResult.CallingMember.BodyRegion;
textArea.Caret.Line = region.EndLine - 1;
textArea.Caret.Column = region.EndColumn;
textArea.InsertString(this.newHandlerCode);
textArea.Document.FormattingStrategy.IndentLines(textArea, region.EndLine, textArea.Caret.Line);
textArea.Caret.Line -= 1;
LineSegment segment = textArea.Document.GetLineSegment(textArea.Caret.Line);
textArea.SelectionManager.SetSelection(
textArea.Document.OffsetToPosition(TextUtilities.GetFirstNonWSChar(textArea.Document, segment.Offset)),
textArea.Document.OffsetToPosition(segment.Offset+segment.Length));
textArea.Document.UndoStack.EndUndoGroup();
textArea.EndUpdate();
textArea.DoProcessDialogKey += new DialogKeyProcessor(IgnoreNextDialogKey);
if (editor != null) {
editor.SelectionChanged -= EditorSelectionChanged;
editor.KeyPress -= EditorKeyPress;
editor = null;
}
// detatch our keydown filter to return to the normal processing state
this.textArea.PreviewKeyDown -= new PreviewKeyDownEventHandler(NewEventHandlerPreviewKeyDown);
}
bool IgnoreNextDialogKey(Keys keyData) {
this.textArea.DoProcessDialogKey -= new DialogKeyProcessor(IgnoreNextDialogKey);
return true; // yes, we've processed this key
void EditorSelectionChanged(object sender, EventArgs e)
{
RemoveEventHandlers();
}
void EditorKeyPress(object sender, KeyEventArgs e)
{
if (e.Key == Key.Tab || e.Key == Key.Enter || e.Key == Key.Return) {
using (editor.Document.OpenUndoGroup()) {
// is there a better way to calculate the optimal insertion point?
DomRegion region = resolveResult.CallingMember.BodyRegion;
editor.Caret.Line = region.EndLine;
editor.Caret.Column = region.EndColumn;
editor.Document.Insert(editor.Caret.Offset, this.newHandlerCode);
editor.FormattingStrategy.IndentLines(editor, region.EndLine, editor.Caret.Line);
IDocumentLine line = editor.Document.GetLine(editor.Caret.Line - 1);
int indentationLength = DocumentUtilitites.GetIndentation(editor.Document, line.Offset).Length;
editor.Select(line.Offset + indentationLength, line.Length - indentationLength);
}
e.Handled = true;
}
// detatch our keydown filter to return to the normal processing state
RemoveEventHandlers();
}
}
}

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

@ -33,6 +33,10 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -33,6 +33,10 @@ namespace ICSharpCode.AvalonEdit.AddIn
get { return codeEditor.FileName; }
}
public override IFormattingStrategy FormattingStrategy {
get { return codeEditor.FormattingStrategy; }
}
public override void ShowCompletionWindow(ICompletionItemList data)
{
if (data == null || !data.Items.Any())

14
src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs

@ -5,12 +5,14 @@ @@ -5,12 +5,14 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.SharpDevelop.Editor
{
@ -68,6 +70,10 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -68,6 +70,10 @@ namespace ICSharpCode.SharpDevelop.Editor
public ITextEditorCaret Caret { get; private set; }
public ITextEditorOptions Options { get; private set; }
public virtual IFormattingStrategy FormattingStrategy {
get { return DefaultFormattingStrategy.DefaultInstance; }
}
sealed class CaretAdapter : ITextEditorCaret
{
Caret caret;
@ -159,6 +165,11 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -159,6 +165,11 @@ namespace ICSharpCode.SharpDevelop.Editor
}
}
public event KeyEventHandler KeyPress {
add { textEditor.TextArea.PreviewKeyDown += value; }
remove { textEditor.TextArea.PreviewKeyDown -= value; }
}
public event EventHandler SelectionChanged {
add { textEditor.TextArea.SelectionChanged += value; }
remove { textEditor.TextArea.SelectionChanged -= value; }
@ -167,6 +178,7 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -167,6 +178,7 @@ namespace ICSharpCode.SharpDevelop.Editor
public void Select(int selectionStart, int selectionLength)
{
textEditor.Select(selectionStart, selectionLength);
textEditor.TextArea.Caret.BringCaretToView();
}
public void JumpTo(int line, int column)

7
src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs

@ -226,7 +226,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -226,7 +226,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
}
string entityDoc = entity.Documentation;
if (!string.IsNullOrEmpty(entityDoc)) {
string documentation = ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.CodeCompletionData.ConvertDocumentation(entityDoc);
string documentation = ConvertDocumentation(entityDoc);
if (!string.IsNullOrEmpty(documentation)) {
description += Environment.NewLine + documentation;
}
@ -236,6 +236,11 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -236,6 +236,11 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
}
}
}
public static string ConvertDocumentation(string xmlDocumentation)
{
return ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.CodeCompletionData.ConvertDocumentation(xmlDocumentation);
}
#endregion
}
}

8
src/Main/Base/Project/Src/Editor/CodeCompletion/ICompletionItemList.cs

@ -110,8 +110,16 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion @@ -110,8 +110,16 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
/// <inheritdoc/>
public virtual void Complete(CompletionContext context, ICompletionItem item)
{
if (context == null)
throw new ArgumentNullException("context");
if (item == null)
throw new ArgumentNullException("item");
if (InsertSpace) {
InsertSpace = false;
context.Editor.Document.Insert(context.StartOffset, " ");
context.StartOffset++;
context.EndOffset++;
}
item.Complete(context);
}
}

2
src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs

@ -32,6 +32,8 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -32,6 +32,8 @@ namespace ICSharpCode.SharpDevelop.Editor
public class DefaultFormattingStrategy : IFormattingStrategy
{
internal static readonly DefaultFormattingStrategy DefaultInstance = new DefaultFormattingStrategy();
public virtual void FormatLine(ITextEditor editor, char charTyped)
{
}

11
src/Main/Base/Project/Src/Editor/ITextEditor.cs

@ -5,10 +5,12 @@ @@ -5,10 +5,12 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
using System;
using System.Collections.Generic;
using System.Windows.Input;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
namespace ICSharpCode.SharpDevelop.Editor
{
@ -28,6 +30,8 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -28,6 +30,8 @@ namespace ICSharpCode.SharpDevelop.Editor
ITextEditorCaret Caret { get; }
ITextEditorOptions Options { get; }
IFormattingStrategy FormattingStrategy { get; }
/// <summary>
/// Gets the start offset of the selection.
/// </summary>
@ -55,6 +59,11 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -55,6 +59,11 @@ namespace ICSharpCode.SharpDevelop.Editor
/// </summary>
event EventHandler SelectionChanged;
/// <summary>
/// Is raised before a key is pressed.
/// </summary>
event KeyEventHandler KeyPress;
/// <summary>
/// Sets the caret to the specified line/column and brings the caret into view.
/// </summary>

9
src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs

@ -118,6 +118,10 @@ namespace ICSharpCode.SharpDevelop @@ -118,6 +118,10 @@ namespace ICSharpCode.SharpDevelop
public ITextEditorCaret Caret { get; private set; }
public ITextEditorOptions Options { get; private set; }
public virtual Editor.IFormattingStrategy FormattingStrategy {
get { return Editor.DefaultFormattingStrategy.DefaultInstance; }
}
public string FileName {
get { return editor.FileName; }
}
@ -188,6 +192,11 @@ namespace ICSharpCode.SharpDevelop @@ -188,6 +192,11 @@ namespace ICSharpCode.SharpDevelop
}
}
public event System.Windows.Input.KeyEventHandler KeyPress {
add { throw new NotImplementedException(); }
remove { throw new NotImplementedException(); }
}
public event EventHandler SelectionChanged {
add { sdtac.ActiveTextAreaControl.SelectionManager.SelectionChanged += value; }
remove { sdtac.ActiveTextAreaControl.SelectionManager.SelectionChanged -= value; }

Loading…
Cancel
Save