Browse Source

first implementation of InsertWithCursor

pull/315/head
Siegfried Pammer 12 years ago
parent
commit
989b259278
  1. 205
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs
  2. 5
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertionPoint.cs

205
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs

@ -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;
}
}
}

5
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertionPoint.cs

@ -81,7 +81,7 @@ namespace CSharpBinding.Refactoring @@ -81,7 +81,7 @@ namespace CSharpBinding.Refactoring
offset += str.Length;
}
public void Insert (IDocument document, string text)
public int Insert (IDocument document, string text)
{
int offset = document.GetOffset (Location);
using (var undo = document.OpenUndoGroup ()) {
@ -95,6 +95,7 @@ namespace CSharpBinding.Refactoring @@ -95,6 +95,7 @@ namespace CSharpBinding.Refactoring
document.Insert (offset, text);
offset += text.Length;
InsertNewLine (document, LineAfter, ref offset);
return offset;
}
}
@ -106,7 +107,7 @@ namespace CSharpBinding.Refactoring @@ -106,7 +107,7 @@ namespace CSharpBinding.Refactoring
// update type from parsed document, since this is always newer.
//type = parsedDocument.GetInnermostTypeDefinition (type.GetLocation ()) ?? type;
List<InsertionPoint > result = new List<InsertionPoint> ();
List<InsertionPoint> result = new List<InsertionPoint> ();
int offset = document.GetOffset (type.Region.Begin);
if (offset < 0)
return result;

Loading…
Cancel
Save