diff --git a/src/Libraries/NRefactory/Project/Src/Ast/General/PrimitiveExpression.cs b/src/Libraries/NRefactory/Project/Src/Ast/General/PrimitiveExpression.cs index 3e7ea9e753..ae6d22877c 100644 --- a/src/Libraries/NRefactory/Project/Src/Ast/General/PrimitiveExpression.cs +++ b/src/Libraries/NRefactory/Project/Src/Ast/General/PrimitiveExpression.cs @@ -5,6 +5,7 @@ // $Revision$ // +using ICSharpCode.NRefactory.PrettyPrinter; using System; namespace ICSharpCode.NRefactory.Ast @@ -18,13 +19,21 @@ namespace ICSharpCode.NRefactory.Ast public string StringValue { get { - return stringValue; + if (stringValue == null) + return CSharpOutputVisitor.ToCSharpString(this); + else + return stringValue; } set { stringValue = value == null ? String.Empty : value; } } + public PrimitiveExpression(object val) + { + this.Value = val; + } + public PrimitiveExpression(object val, string stringValue) { this.Value = val; @@ -39,9 +48,9 @@ namespace ICSharpCode.NRefactory.Ast public override string ToString() { return String.Format("[PrimitiveExpression: Value={1}, ValueType={2}, StringValue={0}]", - stringValue, - Value, - Value == null ? "null" : Value.GetType().FullName + this.StringValue, + this.Value, + this.Value == null ? "null" : this.Value.GetType().FullName ); } } diff --git a/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs b/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs index 4c0be34acd..49d89dd5bc 100644 --- a/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs +++ b/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs @@ -83,6 +83,16 @@ namespace ICSharpCode.NRefactory.AstBuilder return new PrimitiveExpression(null, "null"); } } + + /// + /// Just calls the BinaryOperatorExpression constructor, + /// but being an extension method; this allows for a nicer + /// infix syntax in some cases. + /// + public static BinaryOperatorExpression Operator(this Expression left, BinaryOperatorType op, Expression right) + { + return new BinaryOperatorExpression(left, op, right); + } } #endif } diff --git a/src/Libraries/NRefactory/Project/Src/AstBuilder/StatementBuilder.cs b/src/Libraries/NRefactory/Project/Src/AstBuilder/StatementBuilder.cs index 28117b9537..64451cd511 100644 --- a/src/Libraries/NRefactory/Project/Src/AstBuilder/StatementBuilder.cs +++ b/src/Libraries/NRefactory/Project/Src/AstBuilder/StatementBuilder.cs @@ -11,7 +11,6 @@ using ICSharpCode.NRefactory.Ast; namespace ICSharpCode.NRefactory.AstBuilder { - #if NET35 /// /// Extension methods for NRefactory.Ast.Expression. /// @@ -57,5 +56,4 @@ namespace ICSharpCode.NRefactory.AstBuilder AddStatement(block, new AssignmentExpression(left, AssignmentOperatorType.Assign, right)); } } - #endif } diff --git a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs index 651183206d..74311d582c 100644 --- a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs +++ b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs @@ -1747,70 +1747,69 @@ namespace ICSharpCode.NRefactory.PrettyPrinter } public override object TrackedVisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) + { + outputFormatter.PrintText(ToCSharpString(primitiveExpression)); + return null; + } + + internal static string ToCSharpString(PrimitiveExpression primitiveExpression) { if (primitiveExpression.Value == null) { - outputFormatter.PrintToken(Tokens.Null); - return null; + return "null"; } object val = primitiveExpression.Value; if (val is bool) { if ((bool)val) { - outputFormatter.PrintToken(Tokens.True); + return "true"; } else { - outputFormatter.PrintToken(Tokens.False); + return "false"; } - return null; } if (val is string) { - outputFormatter.PrintText('"' + ConvertString(val.ToString()) + '"'); - return null; + return "\"" + ConvertString(val.ToString()) + "\""; } if (val is char) { - outputFormatter.PrintText("'" + ConvertCharLiteral((char)val) + "'"); - return null; + return "'" + ConvertCharLiteral((char)val) + "'"; } if (val is decimal) { - outputFormatter.PrintText(((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"); - return null; + return ((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"; } if (val is float) { - outputFormatter.PrintText(((float)val).ToString(NumberFormatInfo.InvariantInfo) + "f"); - return null; + return ((float)val).ToString(NumberFormatInfo.InvariantInfo) + "f"; } if (val is double) { string text = ((double)val).ToString(NumberFormatInfo.InvariantInfo); if (text.IndexOf('.') < 0 && text.IndexOf('E') < 0) - outputFormatter.PrintText(text + ".0"); + return text + ".0"; else - outputFormatter.PrintText(text); - return null; + return text; } if (val is IFormattable) { + StringBuilder b = new StringBuilder(); if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) { - outputFormatter.PrintText("0x"); - outputFormatter.PrintText(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo)); + b.Append("0x"); + b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo)); } else { - outputFormatter.PrintText(((IFormattable)val).ToString(null, NumberFormatInfo.InvariantInfo)); + b.Append(((IFormattable)val).ToString(null, NumberFormatInfo.InvariantInfo)); } if (val is uint || val is ulong) { - outputFormatter.PrintText("u"); + b.Append("u"); } if (val is long || val is ulong) { - outputFormatter.PrintText("L"); + b.Append("L"); } + return b.ToString(); } else { - outputFormatter.PrintText(val.ToString()); + return val.ToString(); } - - return null; } static bool IsNullLiteralExpression(Expression expr) diff --git a/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs b/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs index e45bffd686..0b468d2621 100644 --- a/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs +++ b/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs @@ -236,9 +236,9 @@ namespace ICSharpCode.NRefactory.Visitors if (methodDeclaration.TypeReference.Type != "System.Void" && methodDeclaration.Body.Children.Count > 0) { if (IsAssignmentTo(methodDeclaration.Body.Children[methodDeclaration.Body.Children.Count - 1], methodDeclaration.Name)) { - ReturnStatement rs = new ReturnStatement(GetAssignmentFromStatement(methodDeclaration.Body.Children[methodDeclaration.Body.Children.Count - 1]).Right); + Expression returnValue = GetAssignmentFromStatement(methodDeclaration.Body.Children[methodDeclaration.Body.Children.Count - 1]).Right; methodDeclaration.Body.Children.RemoveAt(methodDeclaration.Body.Children.Count - 1); - methodDeclaration.Body.AddChild(rs); + methodDeclaration.Body.Return(returnValue); } else { ReturnStatementForFunctionAssignment visitor = new ReturnStatementForFunctionAssignment(methodDeclaration.Name); methodDeclaration.Body.AcceptVisitor(visitor, null); @@ -247,7 +247,7 @@ namespace ICSharpCode.NRefactory.Visitors init = ExpressionBuilder.CreateDefaultValueForType(methodDeclaration.TypeReference); methodDeclaration.Body.Children.Insert(0, new LocalVariableDeclaration(new VariableDeclaration(FunctionReturnValueName, init, methodDeclaration.TypeReference))); methodDeclaration.Body.Children[0].Parent = methodDeclaration.Body; - methodDeclaration.Body.AddChild(new ReturnStatement(new IdentifierExpression(FunctionReturnValueName))); + methodDeclaration.Body.Return(new IdentifierExpression(FunctionReturnValueName)); } } } diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 6530ecf132..caa209fb82 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -497,6 +497,7 @@ Form + diff --git a/src/Main/Base/Project/Src/TextEditor/Commands/PasteAsCommands.cs b/src/Main/Base/Project/Src/TextEditor/Commands/PasteAsCommands.cs new file mode 100644 index 0000000000..5e7aff8368 --- /dev/null +++ b/src/Main/Base/Project/Src/TextEditor/Commands/PasteAsCommands.cs @@ -0,0 +1,174 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.AstBuilder; +using System; +using System.IO; +using System.Text; +using ICSharpCode.Core; +using ICSharpCode.Core.WinForms; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.Refactoring; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Actions; +using ICSharpCode.TextEditor.Document; + +namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands +{ + public abstract class PasteAsCommand : AbstractMenuCommand + { + public override void Run() + { + string clipboardText = ClipboardWrapper.GetText(); + if (string.IsNullOrEmpty(clipboardText)) + return; + + IViewContent viewContent = WorkbenchSingleton.Workbench.ActiveViewContent; + if (viewContent == null || !(viewContent is ITextEditorControlProvider)) { + return; + } + + TextEditorControl textEditor = ((ITextEditorControlProvider)viewContent).TextEditorControl; + if (textEditor == null) { + return; + } + + textEditor.BeginUpdate(); + textEditor.Document.UndoStack.StartUndoGroup(); + try { + Run(textEditor, clipboardText); + } finally { + textEditor.Document.UndoStack.EndUndoGroup(); + textEditor.EndUpdate(); + } + textEditor.Refresh(); + } + + protected abstract void Run(TextEditorControl editor, string clipboardText); + + protected string GetIndentation(ICSharpCode.TextEditor.Document.IDocument document, int line) + { + string lineText = document.GetText(document.GetLineSegment(line)); + return lineText.Substring(0, lineText.Length - lineText.TrimStart().Length); + } + } + + /// + /// Pastes the clipboard text as a comment. + /// + /// Does the following: + /// - Take clipboard text + /// - Get current indentation + /// - Wrap first line using 'IAmbience.WrapComment' + /// - If it's too long (according to the column ruler position), word-break + /// - Insert it + /// + public class PasteAsCommentCommand : PasteAsCommand + { + protected override void Run(TextEditorControl editor, string clipboardText) + { + TextArea textArea = editor.ActiveTextAreaControl.TextArea; + string indentation = GetIndentation(editor.Document, textArea.Caret.Line); + IAmbience ambience = AmbienceService.GetCurrentAmbience(); + int maxLineLength = textArea.TextEditorProperties.VerticalRulerRow - VisualIndentationLength(textArea, indentation); + StringBuilder insertedText = new StringBuilder(); + using (StringReader reader = new StringReader(clipboardText)) { + string line; + while ((line = reader.ReadLine()) != null) { + AppendTextLine(indentation, ambience, maxLineLength, insertedText, line); + } + } + var document = textArea.Document; + int insertionPos = document.GetLineSegment(textArea.Caret.Line).Offset + indentation.Length; + document.Insert(insertionPos, insertedText.ToString()); + } + + void AppendTextLine(string indentation, IAmbience ambience, int maxLineLength, StringBuilder insertedText, string line) + { + const int minimumLineLength = 10; + string commentedLine; + while (true) { + commentedLine = ambience.WrapComment(line); + int commentingOverhead = commentedLine.Length - line.Length; + if (commentingOverhead < 0 || (maxLineLength - commentingOverhead) < minimumLineLength) + break; + if (commentedLine.Length > maxLineLength) { + int pos = FindWrapPositionBefore(line, maxLineLength - commentingOverhead); + if (pos < minimumLineLength) + break; + insertedText.AppendLine(ambience.WrapComment(line.Substring(0, pos))); + insertedText.Append(indentation); + line = line.Substring(pos + 1); + } else { + break; + } + } + insertedText.AppendLine(commentedLine); + insertedText.Append(indentation); // indentation for next line + } + + int FindWrapPositionBefore(string line, int pos) + { + return line.LastIndexOf(' ', pos); + } + + int VisualIndentationLength(TextArea textArea, string indentation) + { + int length = 0; + foreach (char c in indentation) { + if (c == '\t') + length += textArea.TextEditorProperties.TabIndent; + else + length += 1; + } + return length; + } + } + + /// + /// Pastes the clipboard text as a string. + /// + /// Does the following: + /// - Take clipboard text + /// - Convert to string literal using CodeGenerator + /// - Insert it + /// + public class PasteAsStringCommand : PasteAsCommand + { + protected override void Run(TextEditorControl editor, string clipboardText) + { + CodeGenerator codeGenerator = ParserService.CurrentProjectContent.Language.CodeGenerator; + if (codeGenerator == null) + codeGenerator = LanguageProperties.CSharp.CodeGenerator; + Expression expression = null; + using (StringReader reader = new StringReader(clipboardText)) { + string line; + while ((line = reader.ReadLine()) != null) { + Expression newExpr = new PrimitiveExpression(line); + if (expression == null) { + expression = newExpr; + } else { + expression = expression + .Operator(BinaryOperatorType.Concat, + ExpressionBuilder.Identifier("Environment").Member("NewLine")) + .Operator(BinaryOperatorType.Concat, + newExpr); + } + } + } + if (expression == null) + return; + TextArea textArea = editor.ActiveTextAreaControl.TextArea; + string indentation = GetIndentation(editor.Document, textArea.Caret.Line); + textArea.InsertString(codeGenerator.GenerateCode(expression, indentation).Trim()); + } + } +}