From c3eb3c38a669b8ed733d61befeb8da44729325fd Mon Sep 17 00:00:00 2001 From: mkonicek Date: Thu, 9 Dec 2010 03:30:18 +0100 Subject: [PATCH] Extend selection works with comments (CTRL+W, will be a command in menu). --- .../AvalonEdit.AddIn/Src/CodeEditorView.cs | 57 +++++++++++++++---- .../Project/Src/ContextActions/Extensions.cs | 15 ----- .../ContextActions/EditorContext.cs | 1 - .../Base/Project/Src/Util/ExtensionMethods.cs | 18 ++++++ 4 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index 2875913005..7d72090d01 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -387,18 +387,21 @@ namespace ICSharpCode.AvalonEdit.AddIn } #endregion - #region Expand selection + #region CTRL+W extend selection 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 editorLang = EditorContext.GetEditorLanguage(this.Adapter); + if (editorLang == null) return; var parser = ParserFactory.CreateParser(editorLang.Value, new StringReader(this.Text)); parser.ParseMethodBodies = true; + parser.Lexer.SkipAllComments = false; // f parser.Parse(); - var parsedCU = parser.CompilationUnit; if (parsedCU == null) return; + 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); @@ -409,23 +412,57 @@ namespace ICSharpCode.AvalonEdit.AddIn Ast.INode currentNode = parsedCU.Children.Select( n => EditorContext.FindInnermostNodeContainingSelection(n, selectionStart, selectionEnd)).Where(n => n != null).FirstOrDefault(); if (currentNode == null) return; - + + // whole node already selected -> expand selection if (currentNode.StartLocation == selectionStart && currentNode.EndLocation == selectionEnd) { - // if whole node already selected, expand selection to parent - currentNode = currentNode.Parent; - if (currentNode == null) - return; + var commentsBlankLines = parser.Lexer.SpecialTracker.CurrentSpecials; + + // if there is a comment block immediately before selection, or behind selection on the same line, add it to selection + var comments = commentsBlankLines.Where(s => s is Comment).Cast().ToList(); + int commentIndex = comments.FindIndex(c => c.EndPosition.Line == currentNode.StartLocation.Line); + if (commentIndex >= 0 && IsWhitespaceBetween(this.Adapter.Document, comments[commentIndex].EndPosition, selectionStart)) { + while (commentIndex >= 0 && comments[commentIndex].EndPosition.Line == selectionStart.Line) + { + var comment = comments[commentIndex]; + selectionStart = comment.StartPosition; + if (comment.CommentStartsLine) + selectionStart.Column = 1; + commentIndex--; + } + } + else { + // if the extended selection would contain blank lines, extend the selection only to the blank lines/comments on both sides (use siblings) + // if the selection contains blank lines or comments on both sides, dont do this + + + var parent = currentNode.Parent; + if (parent == null) + return; + selectionStart = parent.StartLocation; + selectionEnd = parent.EndLocation; + } + } else { + // select current node + selectionStart = currentNode.StartLocation; + selectionEnd = currentNode.EndLocation; } 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); + startOffset = this.Adapter.Document.PositionToOffset(selectionStart); + endOffset = this.Adapter.Document.PositionToOffset(selectionEnd); } catch(ArgumentOutOfRangeException) { return; } this.Select(startOffset, endOffset - startOffset); } } + + bool IsWhitespaceBetween(IDocument document, Location startPos, Location endPos) + { + int startOffset = document.PositionToOffset(startPos); + int endOffset = document.PositionToOffset(endPos); + return string.IsNullOrWhiteSpace(document.GetText(startOffset, endOffset - startOffset)); + } #endregion public void JumpTo(int line, int column) diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/Extensions.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/Extensions.cs index 16464d7fae..051940be99 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/Extensions.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/Extensions.cs @@ -48,21 +48,6 @@ namespace SharpRefactoring.ContextActions } } - public static Location GetStart(this DomRegion region) - { - return new Location(region.BeginColumn, region.BeginLine); - } - - public static Location GetEnd(this DomRegion region) - { - return new Location(region.EndColumn, region.EndLine); - } - - public static int PositionToOffset(this IDocument document, Location location) - { - return document.PositionToOffset(location.Line, location.Column); - } - /// /// Gets offset for the start of line at which given location is. /// diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs index 639d676b99..791cbdf2d0 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs @@ -100,7 +100,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring this.CurrentMemberAST = GetCurrentMemberAST(editor); this.CurrentElement = FindInnermostNode(this.CurrentMemberAST, new Location(CaretColumn, CaretLine)); - // DebugLog(); } diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs index f734266f5b..ca38419b4a 100644 --- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs +++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs @@ -18,6 +18,7 @@ using System.Xml; using System.Xml.Linq; using ICSharpCode.Core.Presentation; +using ICSharpCode.NRefactory; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; @@ -578,5 +579,22 @@ namespace ICSharpCode.SharpDevelop element.AddFirst(new XText(Environment.NewLine + indentation.ToString())); return newContent; } + +#region Dom, AST, Editor, Document + public static Location GetStart(this DomRegion region) + { + return new Location(region.BeginColumn, region.BeginLine); + } + + public static Location GetEnd(this DomRegion region) + { + return new Location(region.EndColumn, region.EndLine); + } + + public static int PositionToOffset(this IDocument document, Location location) + { + return document.PositionToOffset(location.Line, location.Column); + } +#endregion } }