diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs index 8c930847ff..517ef66603 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs @@ -6,6 +6,7 @@ // using System; +using System.IO; using System.Collections; using System.Collections.Specialized; using System.Text.RegularExpressions; @@ -16,6 +17,7 @@ using System.Text; using ICSharpCode.TextEditor.Document; using ICSharpCode.TextEditor.Actions; using ICSharpCode.TextEditor; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.Core; @@ -254,25 +256,70 @@ namespace VBNetBinding.FormattingStrategy doCasing = PropertyService.Get("VBBinding.TextEditor.EnableCasing", true); doInsertion = PropertyService.Get("VBBinding.TextEditor.EnableEndConstructs", true); - if (lineNr > 0) { + if (lineNr > 0) + { LineSegment curLine = textArea.Document.GetLineSegment(lineNr); LineSegment lineAbove = lineNr > 0 ? textArea.Document.GetLineSegment(lineNr - 1) : null; string curLineText = textArea.Document.GetText(curLine.Offset, curLine.Length); - string lineAboveText = textArea.Document.GetText(lineAbove.Offset, lineAbove.Length); + string lineAboveText = lineAbove == null ? "" : textArea.Document.GetText(lineAbove); + + if (ch == '@') { + curLineText = textArea.Document.GetText(curLine); + + if (curLineText != null && curLineText.EndsWith("'@") && (lineAboveText == null || !lineAboveText.Trim().StartsWith("'@"))) { + string indentation = base.GetIndentation(textArea, lineNr); + object member = GetMember(textArea, lineNr); + if (member != null) { + StringBuilder sb = new StringBuilder(); + sb.Append(" \n"); + sb.Append(indentation); + sb.Append("'@ \n"); + sb.Append(indentation); + sb.Append("'@ "); + + if (member is IMethod) { + IMethod method = (IMethod)member; + if (method.Parameters != null && method.Parameters.Count > 0) { + for (int i = 0; i < method.Parameters.Count; ++i) { + sb.Append("\n"); + sb.Append(indentation); + sb.Append("'@ "); + } + } + if (method.ReturnType != null && method.ReturnType.FullyQualifiedName != "System.Void") { + sb.Append("\n"); + sb.Append(indentation); + sb.Append("'@ "); + } + } + textArea.Document.Insert(cursorOffset, sb.ToString()); + + textArea.Refresh(); + textArea.Caret.Position = textArea.Document.OffsetToPosition(cursorOffset + indentation.Length + "/// ".Length + " \n".Length); + return 0; + } + } + return 0; + } - if (ch == '\n' && lineAboveText != null) { + if (ch == '\n' && lineAboveText != null) + { int undoCount = 1; // remove comments string texttoreplace = Regex.Replace(lineAboveText, "'.*$", "", RegexOptions.Singleline); // remove string content MatchCollection strmatches = Regex.Matches(texttoreplace, "\"[^\"]*?\"", RegexOptions.Singleline); - foreach (Match match in strmatches) { + foreach (Match match in strmatches) + { texttoreplace = texttoreplace.Remove(match.Index, match.Length).Insert(match.Index, new String('-', match.Length)); } - if (doCasing) { + if (doCasing) + { foreach (string keyword in keywords) { string regex = "(?:\\W|^)(" + keyword + ")(?:\\W|$)"; MatchCollection matches = Regex.Matches(texttoreplace, regex, RegexOptions.IgnoreCase | RegexOptions.Singleline); @@ -286,7 +333,8 @@ namespace VBNetBinding.FormattingStrategy } } - if (doInsertion) { + if (doInsertion) + { foreach (VBStatement statement in statements) { if (Regex.IsMatch(texttoreplace.Trim(), statement.StartRegex, RegexOptions.IgnoreCase)) { string indentation = GetIndentation(textArea, lineNr - 1); @@ -305,8 +353,8 @@ namespace VBNetBinding.FormattingStrategy } } - - if (IsInString(lineAboveText)) { + if (IsInString(lineAboveText)) + { if (IsFinishedString(curLineText)) { textArea.Document.Insert(lineAbove.Offset + lineAbove.Length, "\" & _"); @@ -327,7 +375,9 @@ namespace VBNetBinding.FormattingStrategy textArea.Document.UndoStack.UndoLast(undoCount + 2); return result; } - } else { + } + else + { string indent = GetIndentation(textArea, lineNr - 1); if (indent.Length > 0) { string newLineText = indent + TextUtilities.GetLineAsString(textArea.Document, lineNr).Trim(); @@ -341,10 +391,119 @@ namespace VBNetBinding.FormattingStrategy return indent.Length; } } + else if(ch == '>') + { + if (IsInsideDocumentationComment(textArea, curLine, cursorOffset)) + { + curLineText = textArea.Document.GetText(curLine); + int column = textArea.Caret.Offset - curLine.Offset; + int index = Math.Min(column - 1, curLineText.Length - 1); + + while (index >= 0 && curLineText[index] != '<') { + --index; + if(curLineText[index] == '/') + return 0; // the tag was an end tag or already + } + + if (index > 0) { + StringBuilder commentBuilder = new StringBuilder(""); + for (int i = index; i < curLineText.Length && i < column && !Char.IsWhiteSpace(curLineText[i]); ++i) { + commentBuilder.Append(curLineText[ i]); + } + string tag = commentBuilder.ToString().Trim(); + if (!tag.EndsWith(">")) { + tag += ">"; + } + if (!tag.StartsWith("/")) { + textArea.Document.Insert(textArea.Caret.Offset, " 0 ) { + string fullPath = Path.GetFullPath(fileName); + ParseInformation parseInfo = ParserService.GetParseInformation(fullPath); + if (parseInfo != null) { + ICompilationUnit currentCompilationUnit = (ICompilationUnit)parseInfo.BestCompilationUnit; + if (currentCompilationUnit != null) { + foreach (IClass c in currentCompilationUnit.Classes) { + object o = GetClassMember(textArea, lineNr, c); + if (o != null) { + return o; + } + } + } + } + } + return null; + } + + object GetClassMember(TextArea textArea, int lineNr, IClass c) + { + if (IsBeforeRegion(textArea, c.Region, lineNr)) { + return c; + } + + foreach (IClass inner in c.InnerClasses) { + object o = GetClassMember(textArea, lineNr, inner); + if (o != null) { + return o; + } + } + + foreach (IField f in c.Fields) { + if (IsBeforeRegion(textArea, f.Region, lineNr)) { + return f; + } + } + foreach (IProperty p in c.Properties) { + if (IsBeforeRegion(textArea, p.Region, lineNr)) { + return p; + } + } + foreach (IEvent e in c.Events) { + if (IsBeforeRegion(textArea, e.Region, lineNr)) { + return e; + } + } + foreach (IMethod m in c.Methods) { + if (IsBeforeRegion(textArea, m.Region, lineNr)) { + return m; + } + } + return null; + } + + bool IsBeforeRegion(TextArea textArea, DomRegion region, int lineNr) + { + if (region.IsEmpty) { + return false; + } + return region.BeginLine - 2 <= lineNr && lineNr <= region.BeginLine; + } + bool IsInString(string start) { bool inString = false; diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs index d092d11f9f..8b9efb2c75 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs @@ -17,6 +17,7 @@ using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; using ICSharpCode.NRefactory.Parser; +using ICSharpCode.TextEditor; using VBTokens = ICSharpCode.NRefactory.Parser.VB.Tokens; namespace VBNetBinding diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CommentCompletionDataProvider.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CommentCompletionDataProvider.cs index 1e3d174f28..90b5e26543 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CommentCompletionDataProvider.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CommentCompletionDataProvider.cs @@ -66,7 +66,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor caretColumn = textArea.Caret.Column; LineSegment caretLine = textArea.Document.GetLineSegment(caretLineNumber); string lineText = textArea.Document.GetText(caretLine.Offset, caretLine.Length); - if (!lineText.Trim().StartsWith("///") && !lineText.Trim().StartsWith("'''")) { + if (!lineText.Trim().StartsWith("///") && !lineText.Trim().StartsWith("'@")) { return null; }