Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs')
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs274
1 files changed, 68 insertions, 206 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs
index e8bb9b6b7d..239b50ce89 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/OnTheFlyFormatter.cs
@@ -23,244 +23,106 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-using Mono.TextEditor;
+
using MonoDevelop.Ide;
using System;
using System.Collections.Generic;
using MonoDevelop.Projects.Policies;
-using ICSharpCode.NRefactory.CSharp;
-using System.Text;
-using ICSharpCode.NRefactory;
-using ICSharpCode.NRefactory.TypeSystem;
-using ICSharpCode.NRefactory.CSharp.TypeSystem;
+using System.Linq;
using MonoDevelop.CSharp.Completion;
using MonoDevelop.CSharp.Refactoring;
using MonoDevelop.CSharp.Parser;
using MonoDevelop.Core;
-using ICSharpCode.NRefactory.CSharp.Completion;
+using MonoDevelop.Ide.Editor;
+using Microsoft.CodeAnalysis.Formatting;
+using Microsoft.CodeAnalysis.Text;
+using MonoDevelop.Ide.Gui.Content;
+using Microsoft.CodeAnalysis.CSharp;
namespace MonoDevelop.CSharp.Formatting
{
static class OnTheFlyFormatter
{
- public static void Format (MonoDevelop.Ide.Gui.Document data)
- {
- Format (data, 0, data.Editor.Length);
- }
-
- public static void Format (MonoDevelop.Ide.Gui.Document data, TextLocation location)
+ public static void Format (TextEditor editor, DocumentContext context)
{
- Format (data, location, location, false);
- }
-
- public static void Format (MonoDevelop.Ide.Gui.Document data, TextLocation startLocation, TextLocation endLocation, bool exact = true)
+ Format (editor, context, 0, editor.Length);
+ }
+
+ // public static void Format (TextEditor editor, DocumentContext context, TextLocation location)
+ // {
+ // Format (editor, context, location, location, false);
+ // }
+ //
+ // public static void Format (TextEditor editor, DocumentContext context, TextLocation startLocation, TextLocation endLocation, bool exact = true)
+ // {
+ // Format (editor, context, editor.LocationToOffset (startLocation), editor.LocationToOffset (endLocation), exact);
+ // }
+
+ public static void Format (TextEditor editor, DocumentContext context, int startOffset, int endOffset, bool exact = true)
{
- Format (data, data.Editor.LocationToOffset (startLocation), data.Editor.LocationToOffset (endLocation), exact);
- }
-
- public static void Format (MonoDevelop.Ide.Gui.Document data, int startOffset, int endOffset, bool exact = true)
- {
- var policyParent = data.Project != null ? data.Project.Policies : PolicyService.DefaultPolicies;
+ var policyParent = context.Project != null ? context.Project.Policies : PolicyService.DefaultPolicies;
var mimeTypeChain = DesktopService.GetMimeTypeInheritanceChain (CSharpFormatter.MimeType);
- Format (policyParent, mimeTypeChain, data, startOffset, endOffset, exact);
+ Format (policyParent, mimeTypeChain, editor, context, startOffset, endOffset, exact);
}
- public static void FormatStatmentAt (MonoDevelop.Ide.Gui.Document data, DocumentLocation location)
+ public static void FormatStatmentAt (TextEditor editor, DocumentContext context, MonoDevelop.Ide.Editor.DocumentLocation location)
{
- var offset = data.Editor.LocationToOffset (location);
- var policyParent = data.Project != null ? data.Project.Policies : PolicyService.DefaultPolicies;
+ var offset = editor.LocationToOffset (location);
+ var policyParent = context.Project != null ? context.Project.Policies : PolicyService.DefaultPolicies;
var mimeTypeChain = DesktopService.GetMimeTypeInheritanceChain (CSharpFormatter.MimeType);
- Format (policyParent, mimeTypeChain, data, offset, offset, false, true);
- }
-
-
- static string BuildStub (MonoDevelop.Ide.Gui.Document data, CSharpCompletionTextEditorExtension.TypeSystemTreeSegment seg, int endOffset, out int memberStartOffset)
- {
- var pf = data.ParsedDocument.ParsedFile as CSharpUnresolvedFile;
- if (pf == null) {
- memberStartOffset = 0;
- return null;
- }
-
- var sb = new StringBuilder ();
-
- int closingBrackets = 0;
- // use the member start location to determine the using scope, because this information is in sync, the position in
- // the file may have changed since last parse run (we have up 2 date locations from the type segment tree).
- var scope = pf.GetUsingScope (seg.Entity.Region.Begin);
-
- while (scope != null && !string.IsNullOrEmpty (scope.NamespaceName)) {
- // Hack: some syntax errors lead to invalid namespace names.
- if (scope.NamespaceName.EndsWith ("<invalid>", StringComparison.Ordinal)) {
- scope = scope.Parent;
- continue;
- }
- sb.Append ("namespace Stub {");
- sb.Append (data.Editor.EolMarker);
- closingBrackets++;
- while (scope.Parent != null && scope.Parent.Region == scope.Region)
- scope = scope.Parent;
- scope = scope.Parent;
- }
-
- var parent = seg.Entity.DeclaringTypeDefinition;
- while (parent != null) {
- sb.Append ("class " + parent.Name + " {");
- sb.Append (data.Editor.EolMarker);
- closingBrackets++;
- parent = parent.DeclaringTypeDefinition;
- }
-
- var segmentLine = data.Editor.GetLineByOffset (seg.Offset);
- memberStartOffset = sb.Length + seg.Offset - segmentLine.Offset;
- var text = data.Editor.GetTextBetween (Math.Max (0, segmentLine.Offset), endOffset);
- sb.Append (text);
- var lex = new CSharpCompletionEngineBase.MiniLexer (text);
- lex.Parse ((ch,i) => {
- if (lex.IsInString || lex.IsInChar || lex.IsInVerbatimString || lex.IsInSingleComment || lex.IsInMultiLineComment || lex.IsInPreprocessorDirective)
- return false;
- if (ch =='{') {
- closingBrackets++;
- } else if (ch =='}') {
- closingBrackets--;
- }
- return false;
- });
-
-
- // Insert at least caret column eol markers otherwise the reindent of the generated closing bracket
- // could interfere with the current indentation.
- var endLocation = data.Editor.OffsetToLocation (endOffset);
- for (int i = 0; i <= endLocation.Column; i++) {
- sb.Append (data.Editor.EolMarker);
- }
- sb.Append (data.Editor.EolMarker);
- sb.Append (new string ('}', closingBrackets));
- return sb.ToString ();
+ Format (policyParent, mimeTypeChain, editor, context, offset, offset, false, true);
}
-
- static FormattingChanges GetFormattingChanges (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, MonoDevelop.Ide.Gui.Document document, string input, DomRegion formattingRegion, ref int formatStartOffset, ref int formatLength, bool formatLastStatementOnly)
- {
- using (var stubData = TextEditorData.CreateImmutable (input)) {
- stubData.Document.FileName = document.FileName;
- var parser = document.HasProject ? new CSharpParser (TypeSystemParser.GetCompilerArguments (document.Project)) : new CSharpParser ();
- var compilationUnit = parser.Parse (stubData);
- bool hadErrors = parser.HasErrors;
- if (hadErrors) {
- using (var stubData2 = TextEditorData.CreateImmutable (input + "}")) {
- compilationUnit = parser.Parse (stubData2);
- hadErrors = parser.HasErrors;
- }
- }
- // try it out, if the behavior is better when working only with correct code.
- if (hadErrors) {
- return null;
- }
-
- var policy = policyParent.Get<CSharpFormattingPolicy> (mimeTypeChain);
-
- var formattingVisitor = new ICSharpCode.NRefactory.CSharp.CSharpFormatter (policy.CreateOptions (), document.Editor.CreateNRefactoryTextEditorOptions ());
- formattingVisitor.FormattingMode = FormattingMode.Intrusive;
- formattingVisitor.AddFormattingRegion (formattingRegion);
-
- var changes = formattingVisitor.AnalyzeFormatting (stubData.Document, compilationUnit);
-
- if (formatLastStatementOnly) {
- AstNode node = compilationUnit.GetAdjacentNodeAt<Statement> (stubData.OffsetToLocation (formatStartOffset + formatLength - 1));
- if (node != null) {
- while (node.Role == Roles.EmbeddedStatement || node.Role == IfElseStatement.TrueRole || node.Role == IfElseStatement.FalseRole)
- node = node.Parent;
- // include indentation if node starts in new line
- var formatNode = node.GetPrevNode ();
- if (formatNode.Role != Roles.NewLine)
- formatNode = node;
- var start = stubData.LocationToOffset (formatNode.StartLocation);
- if (start > formatStartOffset) {
- var end = stubData.LocationToOffset (node.EndLocation);
- formatStartOffset = start;
- formatLength = end - start;
- }
- }
- }
- return changes;
- }
- }
-
- public static void Format (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, MonoDevelop.Ide.Gui.Document data, int startOffset, int endOffset, bool exact, bool formatLastStatementOnly = false)
+ static void Format (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, TextEditor editor, DocumentContext context, int startOffset, int endOffset, bool exact, bool formatLastStatementOnly = false)
{
- if (data.ParsedDocument == null)
- return;
- var ext = data.GetContent<CSharpCompletionTextEditorExtension> ();
- if (ext == null)
- return;
- string text;
- int formatStartOffset, formatLength, realTextDelta;
- DomRegion formattingRegion;
- int startDelta = 1;
+ TextSpan span;
if (exact) {
- text = data.Editor.Text;
- var seg = ext.GetMemberSegmentAt (startOffset);
- var seg2 = ext.GetMemberSegmentAt (endOffset);
- if (seg != null && seg == seg2) {
- var member = seg.Entity;
- if (member == null || member.Region.IsEmpty || member.BodyRegion.End.IsEmpty)
- return;
-
- text = BuildStub (data, seg, endOffset, out formatStartOffset);
- startDelta = startOffset - seg.Offset;
- formatLength = endOffset - startOffset + startDelta;
- realTextDelta = seg.Offset - formatStartOffset;
- formattingRegion = new DomRegion (data.Editor.OffsetToLocation (formatStartOffset), data.Editor.OffsetToLocation (endOffset));
- } else {
- formatStartOffset = startOffset;
- formatLength = endOffset - startOffset;
- realTextDelta = 0;
- formattingRegion = new DomRegion (data.Editor.OffsetToLocation (startOffset), data.Editor.OffsetToLocation (endOffset));
- }
+ span = new TextSpan (startOffset, endOffset - startOffset);
} else {
- var seg = ext.GetMemberSegmentAt (startOffset - 1);
- if (seg == null) {
- return;
- }
- var member = seg.Entity;
- if (member == null)
- return;
-
- // Build stub
- text = BuildStub (data, seg, startOffset, out formatStartOffset);
- formattingRegion = new DomRegion (data.Editor.OffsetToLocation (formatStartOffset), data.Editor.OffsetToLocation (endOffset));
-
- formatLength = endOffset - seg.Offset;
- realTextDelta = seg.Offset - formatStartOffset;
+ span = new TextSpan (0, endOffset);
}
- // Get changes from formatting visitor
- var changes = GetFormattingChanges (policyParent, mimeTypeChain, data, text, formattingRegion, ref formatStartOffset, ref formatLength, formatLastStatementOnly);
- if (changes == null)
- return;
- // Do the actual formatting
-// var originalVersion = data.Editor.Document.Version;
+ var analysisDocument = context.AnalysisDocument;
+ if (analysisDocument == null)
+ return;
- using (var undo = data.Editor.OpenUndoGroup (OperationType.Format)) {
+ using (var undo = editor.OpenUndoGroup (/*OperationType.Format*/)) {
try {
- changes.ApplyChanges (formatStartOffset + startDelta, Math.Max (0, formatLength - startDelta - 1), delegate (int replaceOffset, int replaceLength, string insertText) {
- int translatedOffset = realTextDelta + replaceOffset;
- data.Editor.Document.CommitLineUpdate (data.Editor.OffsetToLineNumber (translatedOffset));
- data.Editor.Replace (translatedOffset, replaceLength, insertText);
- }, (replaceOffset, replaceLength, insertText) => {
- int translatedOffset = realTextDelta + replaceOffset;
- if (translatedOffset < 0 || translatedOffset + replaceLength > data.Editor.Length || replaceLength < 0)
- return true;
- return data.Editor.GetTextAt (translatedOffset, replaceLength) == insertText;
- });
+ var syntaxTree = analysisDocument.GetSyntaxTreeAsync ().Result;
+
+ if (formatLastStatementOnly) {
+ var root = syntaxTree.GetRoot ();
+ var token = root.FindToken (endOffset);
+ var tokens = ICSharpCode.NRefactory6.CSharp.FormattingRangeHelper.FindAppropriateRange (token);
+ if (tokens.HasValue) {
+ span = new TextSpan (tokens.Value.Item1.SpanStart, tokens.Value.Item2.Span.End - tokens.Value.Item1.SpanStart);
+ } else {
+ var parent = token.Parent;
+ if (parent != null)
+ span = parent.FullSpan;
+ }
+ }
+
+ var policy = policyParent.Get<CSharpFormattingPolicy> (mimeTypeChain);
+ var textPolicy = policyParent.Get<TextStylePolicy> (mimeTypeChain);
+
+ var doc = Formatter.FormatAsync (analysisDocument, span, policy.CreateOptions (textPolicy)).Result;
+ var newTree = doc.GetSyntaxTreeAsync ().Result;
+ var caretOffset = editor.CaretOffset;
+ foreach (var change in newTree.GetChanges (syntaxTree).OrderByDescending (c => c.Span.Start) ) {
+ if (!exact && change.Span.Start >= caretOffset)
+ continue;
+ var newText = change.NewText;
+ if (editor.EolMarker != "\r\n")
+ newText = newText.Replace ("\r", "");
+ editor.ReplaceText (change.Span.Start, change.Span.Length, newText);
+ }
+ if (editor.CaretColumn == 1)
+ editor.CaretColumn = editor.GetVirtualIndentationColumn (editor.CaretLine);
} catch (Exception e) {
LoggingService.LogError ("Error in on the fly formatter", e);
}
-
-// var currentVersion = data.Editor.Document.Version;
-// data.Editor.Caret.Offset = originalVersion.MoveOffsetTo (currentVersion, caretOffset, ICSharpCode.NRefactory.Editor.AnchorMovementType.Default);
}
}
}
-} \ No newline at end of file
+}