|
|
|
@ -3,8 +3,16 @@
@@ -3,8 +3,16 @@
|
|
|
|
|
|
|
|
|
|
using System; |
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.ComponentModel.Design; |
|
|
|
|
using System.Linq; |
|
|
|
|
using System.Threading.Tasks; |
|
|
|
|
using System.Windows; |
|
|
|
|
using System.Windows.Documents; |
|
|
|
|
using System.Windows.Input; |
|
|
|
|
using System.Windows.Media; |
|
|
|
|
using ICSharpCode.AvalonEdit; |
|
|
|
|
using ICSharpCode.AvalonEdit.Editing; |
|
|
|
|
using ICSharpCode.AvalonEdit.Rendering; |
|
|
|
|
using CSharpBinding.Parser; |
|
|
|
|
using ICSharpCode.AvalonEdit.Document; |
|
|
|
|
using ICSharpCode.NRefactory; |
|
|
|
@ -27,7 +35,7 @@ namespace CSharpBinding.Refactoring
@@ -27,7 +35,7 @@ namespace CSharpBinding.Refactoring
|
|
|
|
|
readonly TextSegmentCollection<TextSegment> textSegmentCollection; |
|
|
|
|
readonly SDRefactoringContext context; |
|
|
|
|
|
|
|
|
|
public EditorScript(ITextEditor editor, SDRefactoringContext context, CSharpFormattingOptions formattingOptions) |
|
|
|
|
public EditorScript(ITextEditor editor, SDRefactoringContext context, CSharpFormattingOptions formattingOptions) |
|
|
|
|
: base(editor.Document, formattingOptions, context.TextEditorOptions) |
|
|
|
|
{ |
|
|
|
|
this.editor = editor; |
|
|
|
@ -44,22 +52,6 @@ namespace CSharpBinding.Refactoring
@@ -44,22 +52,6 @@ namespace CSharpBinding.Refactoring
|
|
|
|
|
return segment; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*public override void FormatText(AstNode node) |
|
|
|
|
{ |
|
|
|
|
var parseInfo = SD.ParserService.Parse(editor.FileName, editor.Document) as CSharpFullParseInformation; |
|
|
|
|
if (parseInfo != null) { |
|
|
|
|
//var startLocation = editor.Document.GetLocation(offset);
|
|
|
|
|
//var endLocation = editor.Document.GetLocation(offset + length);
|
|
|
|
|
//var node = parseInfo.SyntaxTree.GetNodeContaining(startLocation, endLocation);
|
|
|
|
|
var formatter = new AstFormattingVisitor(FormattingOptionsFactory.CreateSharpDevelop(), editor.Document, context.TextEditorOptions); |
|
|
|
|
parseInfo.SyntaxTree.AcceptVisitor(formatter); |
|
|
|
|
var segment = GetSegment(node); |
|
|
|
|
formatter.ApplyChanges(segment.Offset, segment.Length); |
|
|
|
|
} else { |
|
|
|
|
base.FormatText(node); |
|
|
|
|
} |
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
public override void Select(AstNode node) |
|
|
|
|
{ |
|
|
|
|
var segment = GetSegment(node); |
|
|
|
@ -81,34 +73,72 @@ namespace CSharpBinding.Refactoring
@@ -81,34 +73,72 @@ namespace CSharpBinding.Refactoring
|
|
|
|
|
return completedTask; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
public override Task InsertWithCursor(string operation, InsertPosition defaultPosition, IEnumerable<AstNode> nodes) |
|
|
|
|
public override Task<Script> InsertWithCursor(string operation, InsertPosition defaultPosition, IList<AstNode> nodes) |
|
|
|
|
{ |
|
|
|
|
AstNode contextNode = context.GetNode(); |
|
|
|
|
if (contextNode == null) |
|
|
|
|
return completedTask; |
|
|
|
|
var resolver = context.GetResolverStateBefore(contextNode); |
|
|
|
|
return InsertWithCursor(operation, resolver.CurrentTypeDefinition, nodes); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override Task InsertWithCursor(string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes) |
|
|
|
|
{ |
|
|
|
|
if (parentType == null) |
|
|
|
|
return completedTask; |
|
|
|
|
var currentPart = parentType.Parts.FirstOrDefault(p => p.UnresolvedFile != null && string.Equals(p.UnresolvedFile.FileName, editor.FileName, StringComparison.OrdinalIgnoreCase)); |
|
|
|
|
if (currentPart != null) { |
|
|
|
|
var insertionPoints = InsertionPoint.GetInsertionPoints(editor.Document, currentPart); |
|
|
|
|
if (insertionPoints.Count > 0) { |
|
|
|
|
int indentLevel = GetIndentLevelAt(editor.Document.GetOffset(insertionPoints[0].Location)); |
|
|
|
|
foreach (var node in nodes.Reverse()) { |
|
|
|
|
var tcs = new TaskCompletionSource<Script>(); |
|
|
|
|
var loc = editor.Caret.Location; |
|
|
|
|
var currentPart = context.UnresolvedFile.GetInnermostTypeDefinition(loc); |
|
|
|
|
var insertionPoints = InsertionPoint.GetInsertionPoints(editor.Document, currentPart); |
|
|
|
|
|
|
|
|
|
if (insertionPoints.Count == 0) { |
|
|
|
|
SD.MessageService.ShowErrorFormatted("No valid insertion point can be found in type '{0}'.", currentPart.Name); |
|
|
|
|
return tcs.Task; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TextArea area = editor.GetService<TextArea>(); |
|
|
|
|
if (area == null) return tcs.Task; |
|
|
|
|
|
|
|
|
|
var layer = new InsertionCursorLayer(area, operation, insertionPoints); |
|
|
|
|
area.TextView.InsertLayer(layer, KnownLayer.Text, LayerInsertionPosition.Above); |
|
|
|
|
|
|
|
|
|
switch (defaultPosition) { |
|
|
|
|
case InsertPosition.Start: |
|
|
|
|
layer.CurrentInsertionPoint = 0; |
|
|
|
|
break; |
|
|
|
|
case InsertPosition.End: |
|
|
|
|
layer.CurrentInsertionPoint = insertionPoints.Count - 1; |
|
|
|
|
break; |
|
|
|
|
case InsertPosition.Before: |
|
|
|
|
for (int i = 0; i < insertionPoints.Count; i++) { |
|
|
|
|
if (insertionPoints[i].Location < loc) |
|
|
|
|
layer.CurrentInsertionPoint = i; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case InsertPosition.After: |
|
|
|
|
for (int i = 0; i < insertionPoints.Count; i++) { |
|
|
|
|
if (insertionPoints[i].Location > loc) { |
|
|
|
|
layer.CurrentInsertionPoint = i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
layer.Exited += delegate(object s, InsertionCursorEventArgs args) { |
|
|
|
|
if (args.Success) { |
|
|
|
|
if (args.InsertionPoint.LineAfter == NewLineInsertion.None && |
|
|
|
|
args.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count () > 1) { |
|
|
|
|
args.InsertionPoint.LineAfter = NewLineInsertion.BlankLine; |
|
|
|
|
} |
|
|
|
|
foreach (var node in nodes.Reverse ()) { |
|
|
|
|
int indentLevel = GetIndentLevelAt(editor.Document.GetOffset(insertionPoints[0].Location)); |
|
|
|
|
var output = OutputNode(indentLevel, node); |
|
|
|
|
insertionPoints[0].Insert(editor.Document, output.Text); |
|
|
|
|
var offset = editor.Document.GetOffset(args.InsertionPoint.Location); |
|
|
|
|
var delta = args.InsertionPoint.Insert (editor.Document, output.Text); |
|
|
|
|
output.RegisterTrackedSegments (this, delta + offset); |
|
|
|
|
} |
|
|
|
|
tcs.SetResult (this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return completedTask; |
|
|
|
|
area.TextView.Layers.Remove(layer); |
|
|
|
|
layer.Dispose(); |
|
|
|
|
}; |
|
|
|
|
return tcs.Task; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public override Task<Script> InsertWithCursor(string operation, ITypeDefinition parentType, Func<Script, RefactoringContext, IList<AstNode>> nodeCallback) |
|
|
|
|
{ |
|
|
|
|
return base.InsertWithCursor(operation, parentType, nodeCallback); |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
public override void Dispose() |
|
|
|
|
{ |
|
|
|
@ -117,4 +147,99 @@ namespace CSharpBinding.Refactoring
@@ -117,4 +147,99 @@ namespace CSharpBinding.Refactoring
|
|
|
|
|
SD.ParserService.ParseAsync(editor.FileName, editor.Document).FireAndForget(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class InsertionCursorLayer : UIElement, IDisposable |
|
|
|
|
{ |
|
|
|
|
string operation; |
|
|
|
|
InsertionPoint[] insertionPoints; |
|
|
|
|
readonly TextArea editor; |
|
|
|
|
|
|
|
|
|
public int CurrentInsertionPoint { get; set; } |
|
|
|
|
|
|
|
|
|
public event EventHandler<InsertionCursorEventArgs> Exited; |
|
|
|
|
|
|
|
|
|
public static readonly RoutedCommand ExitCommand = new RoutedCommand( |
|
|
|
|
"Exit", typeof(InsertionCursorLayer), |
|
|
|
|
new InputGestureCollection { new KeyGesture(Key.Escape) } |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
public InsertionCursorLayer(TextArea editor, string operation, IList<InsertionPoint> insertionPoints) |
|
|
|
|
{ |
|
|
|
|
if (editor == null) |
|
|
|
|
throw new ArgumentNullException("editor"); |
|
|
|
|
this.editor = editor; |
|
|
|
|
this.operation = operation; |
|
|
|
|
this.insertionPoints = insertionPoints.ToArray(); |
|
|
|
|
this.editor.ActiveInputHandler = new InputHandler(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static readonly Pen markerPen = new Pen(Brushes.Blue, 1); |
|
|
|
|
|
|
|
|
|
protected override void OnRender(DrawingContext drawingContext) |
|
|
|
|
{ |
|
|
|
|
var currentInsertionPoint = insertionPoints[CurrentInsertionPoint]; |
|
|
|
|
var pos = editor.TextView.GetVisualPosition(new TextViewPosition(currentInsertionPoint.Location), VisualYPosition.LineMiddle); |
|
|
|
|
var endPos = new Point(pos.X + editor.TextView.ActualWidth * 0.6, pos.Y); |
|
|
|
|
drawingContext.DrawLine(markerPen, pos, endPos); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class InputHandler : TextAreaDefaultInputHandler |
|
|
|
|
{ |
|
|
|
|
readonly InsertionCursorLayer layer; |
|
|
|
|
|
|
|
|
|
internal InputHandler(InsertionCursorLayer layer) |
|
|
|
|
: base(layer.editor) |
|
|
|
|
{ |
|
|
|
|
this.layer = layer; |
|
|
|
|
AddBinding(EditingCommands.MoveDownByLine, ModifierKeys.None, Key.Down, MoveMarker(false)); |
|
|
|
|
AddBinding(EditingCommands.MoveUpByLine, ModifierKeys.None, Key.Up, MoveMarker(true)); |
|
|
|
|
AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, layer.InsertCode); |
|
|
|
|
AddBinding(ExitCommand, ModifierKeys.None, Key.Escape, layer.Cancel); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ExecutedRoutedEventHandler MoveMarker(bool up) |
|
|
|
|
{ |
|
|
|
|
return (sender, e) => { |
|
|
|
|
if (up) |
|
|
|
|
layer.CurrentInsertionPoint = Math.Max(0, layer.CurrentInsertionPoint - 1); |
|
|
|
|
else |
|
|
|
|
layer.CurrentInsertionPoint = Math.Min(layer.insertionPoints.Length - 1, layer.CurrentInsertionPoint + 1); |
|
|
|
|
layer.InvalidateVisual(); |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
|
{ |
|
|
|
|
this.editor.ActiveInputHandler = this.editor.DefaultInputHandler; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void InsertCode(object sender, ExecutedRoutedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
if (Exited != null) { |
|
|
|
|
Exited(this, new InsertionCursorEventArgs(insertionPoints[CurrentInsertionPoint], true)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Cancel(object sender, ExecutedRoutedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
if (Exited != null) { |
|
|
|
|
Exited(this, new InsertionCursorEventArgs(insertionPoints[CurrentInsertionPoint], false)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class InsertionCursorEventArgs : EventArgs |
|
|
|
|
{ |
|
|
|
|
public InsertionPoint InsertionPoint { get; private set; } |
|
|
|
|
public bool Success { get; private set; } |
|
|
|
|
|
|
|
|
|
public InsertionCursorEventArgs(InsertionPoint insertionPoint, bool success) |
|
|
|
|
{ |
|
|
|
|
if (insertionPoint == null) |
|
|
|
|
throw new ArgumentNullException("insertionPoint"); |
|
|
|
|
this.InsertionPoint = insertionPoint; |
|
|
|
|
this.Success = success; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|