Browse Source

Implemented Extend selection (Ctrl+W, will be in menu). Does not work perfectly for constructor and indexer declarations yet.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@6373 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Martin Koníček 16 years ago
parent
commit
745d903188
  1. 47
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs
  2. 1
      src/Libraries/NRefactory/Project/NRefactory.csproj
  3. 66
      src/Libraries/NRefactory/Project/Src/Visitors/SetRegionInclusionVisitor.cs
  4. 50
      src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs

47
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs

@ -17,17 +17,19 @@ using System.Windows.Controls; @@ -17,17 +17,19 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.AddIn.Options;
using ICSharpCode.AvalonEdit.AddIn.Snippets;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.AvalonEdit;
using ICSharpCode.SharpDevelop.Editor.Commands;
using ICSharpCode.SharpDevelop.Refactoring;
using Ast = ICSharpCode.NRefactory.Ast;
namespace ICSharpCode.AvalonEdit.AddIn
{
@ -359,9 +361,11 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -359,9 +361,11 @@ namespace ICSharpCode.AvalonEdit.AddIn
void TextViewMouseDown(object sender, MouseButtonEventArgs e)
{
// close existing popup immediately on text editor mouse down
// close existing debugger popup immediately on text editor mouse down
TryCloseExistingPopup(false);
if (options.CtrlClickGoToDefinition && e.ChangedButton == MouseButton.Left && Keyboard.Modifiers == ModifierKeys.Control) {
// Ctrl+Click Go to definition
var position = GetPositionFromPoint(e.GetPosition(this));
if (position == null)
return;
@ -372,6 +376,45 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -372,6 +376,45 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
#endregion
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (e.Handled) return;
if (e.Key == Key.W && Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) {
// Select AST Node
var editorLang = EditorContext.GetEditorLanguage(this.Adapter); if (editorLang == null) return;
var parser = ParserFactory.CreateParser(editorLang.Value, new StringReader(this.Text));
parser.ParseMethodBodies = true;
parser.Parse();
var parsedCU = parser.CompilationUnit; if (parsedCU == null) return;
//var caretLocation = new Location(this.Adapter.Caret.Column, this.Adapter.Caret.Line);
var selectionStart = this.Adapter.Document.OffsetToPosition(this.SelectionStart);
var selectionEnd = this.Adapter.Document.OffsetToPosition(this.SelectionStart + this.SelectionLength);
foreach (var node in parsedCU.Children) {
// fix StartLocation / EndLocation
node.AcceptVisitor(new ICSharpCode.NRefactory.Visitors.SetRegionInclusionVisitor(), null);
}
Ast.INode currentNode = parsedCU.Children.Select(
n => EditorContext.FindInnermostNodeContainingSelection(n, selectionStart, selectionEnd)).Where(n => n != null).FirstOrDefault();
if (currentNode == null) return;
if (currentNode.StartLocation == selectionStart && currentNode.EndLocation == selectionEnd) {
// if whole node already selected, expand selection to parent
currentNode = currentNode.Parent;
if (currentNode == null)
return;
}
int startOffset, endOffset;
try {
startOffset = this.Adapter.Document.PositionToOffset(currentNode.StartLocation.Line, currentNode.StartLocation.Column);
endOffset = this.Adapter.Document.PositionToOffset(currentNode.EndLocation.Line, currentNode.EndLocation.Column);
} catch(ArgumentOutOfRangeException) {
return;
}
this.Select(startOffset, endOffset - startOffset);
}
}
public void JumpTo(int line, int column)
{
// closes Debugger popup on debugger step

1
src/Libraries/NRefactory/Project/NRefactory.csproj

@ -128,6 +128,7 @@ @@ -128,6 +128,7 @@
<Compile Include="Src\Visitors\PrefixFieldsVisitor.cs" />
<Compile Include="Src\Visitors\RenameIdentifierVisitor.cs" />
<Compile Include="Src\Visitors\SetParentVisitor.cs" />
<Compile Include="Src\Visitors\SetRegionInclusionVisitor.cs" />
<Compile Include="Src\Visitors\ToCSharpConvertVisitor.cs" />
<Compile Include="Src\Visitors\ToVBNetConvertVisitor.cs" />
<Compile Include="Src\Visitors\ToVBNetRenameConflictingVariables.cs" />

66
src/Libraries/NRefactory/Project/Src/Visitors/SetRegionInclusionVisitor.cs

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Konicek" email="martin.konicek@gmail.com"/>
// <version>$Revision: $</version>
// </file>
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Ast;
namespace ICSharpCode.NRefactory.Visitors
{
/// <summary>
/// Sets StartLocation and EndLocation (region) of every node to union of regions of its children.
/// Parsers don't do this by default,
/// e.g. "a.Foo()" is InvocationExpression, its region includes only the "()" and it has a child MemberReferenceExpression, with region ".Foo".
/// </summary>
public class SetRegionInclusionVisitor : NodeTrackingAstVisitor
{
Stack<INode> parentNodes = new Stack<INode>();
public SetRegionInclusionVisitor()
{
parentNodes.Push(null);
}
protected override void BeginVisit(INode node)
{
base.BeginVisit(node);
// Only push nodes on the stack which have valid position information.
if (node != null &&
node.StartLocation.X >= 1 && node.StartLocation.Y >= 1 &&
node.EndLocation.X >= 1 && node.EndLocation.Y >= 1) {
if (node is PropertyDeclaration) {
// PropertyDeclaration has correctly set BodyStart and BodyEnd by the parser,
// but it has no subnode "body", just 2 children GetRegion and SetRegion which don't cover
// the whole (BodyStart, BodyEnd) region => We have to handle PropertyDeclaration as a special case.
node.EndLocation = ((PropertyDeclaration)node).BodyEnd;
}
this.parentNodes.Push(node);
}
}
protected override void EndVisit(INode node)
{
base.EndVisit(node);
// Only remove those nodes which have actually been pushed before.
if (this.parentNodes.Count > 0 && INode.ReferenceEquals(this.parentNodes.Peek(), node)) {
// remove this node
this.parentNodes.Pop();
// fix region of parent
var parent = this.parentNodes.Peek();
if (parent == null)
return;
if (node.StartLocation < parent.StartLocation)
parent.StartLocation = node.StartLocation;
if (node.EndLocation > parent.EndLocation)
parent.EndLocation = node.EndLocation;
}
}
}
}

50
src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -62,7 +62,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
if (CaretColumn > 1 && editor.Document.GetText(editor.Document.PositionToOffset(CaretLine, CaretColumn - 1), 1) == ";") {
// If caret is just after ';', pretend that caret is before ';'
// (works well e.g. for this.Foo();(*caret*) - we want to get "this.Foo()")
// This is equivalent to pretending that ; don't exist, and actually is not such a bad idea.
// This is equivalent to pretending that ; don't exist, and actually it's not such a bad idea.
CaretColumn -= 1;
}
@ -76,7 +76,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -76,7 +76,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
this.CurrentElement = FindInnermostNodeAtLocation(this.CurrentMemberAST, new Location(CaretColumn, CaretLine));
//DebugLog();
// DebugLog();
}
void DebugLog()
@ -131,41 +131,56 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -131,41 +131,56 @@ namespace ICSharpCode.SharpDevelop.Refactoring
if (memberDecl == null)
return null;
if (memberDecl is MethodDeclaration) {
return FindInnermostNodeInBlock(((MethodDeclaration)memberDecl).Body, position);
return FindInnermostNode(((MethodDeclaration)memberDecl).Body, position);
} else if (memberDecl is PropertyDeclaration) {
var propertyDecl = (PropertyDeclaration)memberDecl;
if (propertyDecl.HasGetRegion && position >= propertyDecl.GetRegion.StartLocation && position <= propertyDecl.GetRegion.EndLocation) {
return FindInnermostNodeInBlock(propertyDecl.GetRegion.Block, position);
return FindInnermostNode(propertyDecl.GetRegion.Block, position);
}
if (propertyDecl.HasSetRegion && position >= propertyDecl.SetRegion.StartLocation && position <= propertyDecl.SetRegion.EndLocation) {
return FindInnermostNodeInBlock(propertyDecl.SetRegion.Block, position);
return FindInnermostNode(propertyDecl.SetRegion.Block, position);
}
}
return null;
}
INode FindInnermostNodeInBlock(BlockStatement node, Location position)
public static INode FindInnermostNode(INode node, Location position)
{
if (node == null)
return null;
var findInnermostVisitor = new FindInnermostNodeVisitor(position);
var findInnermostVisitor = new FindInnermostNodeByRangeVisitor(position);
node.AcceptVisitor(findInnermostVisitor, null);
return findInnermostVisitor.InnermostNode;
}
class FindInnermostNodeVisitor : NodeTrackingAstVisitor
public static INode FindInnermostNodeContainingSelection(INode node, Location start, Location end)
{
public Location CaretLocation { get; private set; }
if (node == null)
return null;
var findInnermostVisitor = new FindInnermostNodeByRangeVisitor(start, end);
node.AcceptVisitor(findInnermostVisitor, null);
return findInnermostVisitor.InnermostNode;
}
class FindInnermostNodeByRangeVisitor : NodeTrackingAstVisitor
{
public Location RangeStart { get; private set; }
public Location RangeEnd { get; private set; }
public INode InnermostNode { get; private set; }
public FindInnermostNodeVisitor(Location caretLocation)
public FindInnermostNodeByRangeVisitor(Location caretPosition) : this(caretPosition, caretPosition)
{
}
public FindInnermostNodeByRangeVisitor(Location selectionStart, Location selectionEnd)
{
this.CaretLocation = caretLocation;
this.RangeStart = selectionStart;
this.RangeEnd = selectionEnd;
}
protected override void BeginVisit(INode node)
{
if (node.StartLocation <= CaretLocation && node.EndLocation >= CaretLocation) {
if (node.StartLocation <= RangeStart && node.EndLocation >= RangeEnd) {
// the node visited last will be the innermost
this.InnermostNode = node;
}
@ -218,7 +233,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -218,7 +233,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
return null;
}
SupportedLanguage? GetEditorLanguage(ITextEditor editor)
public static SupportedLanguage? GetEditorLanguage(ITextEditor editor)
{
if (editor == null || editor.Language == null)
return null;
@ -233,8 +248,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -233,8 +248,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
INode GetCurrentMemberAST(ITextEditor editor)
{
try {
var resolver = GetNRefactoryResolver(editor);
resolver.Initialize(ParserService.GetParseInformation(editor.FileName), CaretLine, CaretColumn);
var resolver = GetInitializedNRefactoryResolver(editor, this.CaretLine, this.CaretColumn);
return resolver.ParseCurrentMember(editor.Document.Text);
}
catch {
@ -242,13 +256,15 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -242,13 +256,15 @@ namespace ICSharpCode.SharpDevelop.Refactoring
}
}
NRefactoryResolver GetNRefactoryResolver(ITextEditor editor)
NRefactoryResolver GetInitializedNRefactoryResolver(ITextEditor editor, int caretLine, int caretColumn)
{
if (editor == null || editor.Language == null)
return null;
try
{
return new NRefactoryResolver(editor.Language.Properties);
var resolver = new NRefactoryResolver(editor.Language.Properties);
resolver.Initialize(ParserService.GetParseInformation(editor.FileName), caretLine, caretColumn);
return resolver;
}
catch(NotSupportedException)
{

Loading…
Cancel
Save