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
path: root/main/src
diff options
context:
space:
mode:
authorMike Krüger <mikkrg@microsoft.com>2018-04-17 16:00:07 +0300
committerGitHub <noreply@github.com>2018-04-17 16:00:07 +0300
commit345cfd1a81eb0bb1536e5b67e1bbade2fd2f78ef (patch)
treebbf1544cee46f964c1deddb386a4c1db2ac31c1c /main/src
parent680ba9d12caf2d4bfe0d331ba80f4333124016ed (diff)
parent5730bffe5c619077afbec5cb245591b9d8fe891d (diff)
Merge pull request #4586 from mono/master-roslynfolding
[Ide] Switched to roslyn folding infrastructure.
Diffstat (limited to 'main/src')
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs176
-rw-r--r--main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml1
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/BlockStructureFoldingTextEditorExtension.cs140
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj1
4 files changed, 144 insertions, 174 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs
index faff647bc7..4787f4e22d 100644
--- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs
@@ -306,181 +306,9 @@ namespace MonoDevelop.CSharp.Parser
}
}
- IReadOnlyList<FoldingRegion> foldings;
- SemaphoreSlim foldingsSemaphore = new SemaphoreSlim (1, 1);
+ static readonly Task<IReadOnlyList<FoldingRegion>> foldings = Task.FromResult((IReadOnlyList<FoldingRegion>)new FoldingRegion[0]);
- public override Task<IReadOnlyList<FoldingRegion>> GetFoldingsAsync (CancellationToken cancellationToken = default(CancellationToken))
- {
- if (foldings == null) {
- return Task.Run (async delegate {
- bool locked = false;
- try {
- locked = await foldingsSemaphore.WaitAsync (Timeout.Infinite, cancellationToken);
- if (foldings == null)
- foldings = (await GenerateFoldings (cancellationToken)).ToList ();
- } catch (OperationCanceledException) {
- return new List<FoldingRegion> ();
- } finally {
- if (locked)
- foldingsSemaphore.Release ();
- }
- return foldings;
- });
- }
-
- return Task.FromResult (foldings);
- }
-
- async Task<IEnumerable<FoldingRegion>> GenerateFoldings (CancellationToken cancellationToken)
- {
- return GenerateFoldingsInternal (await GetCommentsAsync (cancellationToken), cancellationToken);
- }
-
- IEnumerable<FoldingRegion> GenerateFoldingsInternal (IReadOnlyList<Comment> comments, CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- yield break;
-
- foreach (var fold in comments.ToFolds ())
- yield return fold;
-
- if (cancellationToken.IsCancellationRequested)
- yield break;
-
- var visitor = new FoldingVisitor (cancellationToken);
- if (Unit != null) {
- try {
- visitor.Visit (Unit.GetRoot (cancellationToken));
- } catch (Exception) { }
- }
-
- if (cancellationToken.IsCancellationRequested)
- yield break;
- foreach (var fold in visitor.Foldings)
- yield return fold;
- }
-
- class FoldingVisitor : CSharpSyntaxWalker
- {
- public readonly List<FoldingRegion> Foldings = new List<FoldingRegion> ();
- CancellationToken cancellationToken;
-
- public FoldingVisitor (CancellationToken cancellationToken) : base(SyntaxWalkerDepth.Trivia)
- {
- this.cancellationToken = cancellationToken;
- }
-
- void AddUsings (SyntaxNode parent)
- {
- SyntaxNode firstChild = null, lastChild = null;
- foreach (var child in parent.ChildNodes ()) {
- cancellationToken.ThrowIfCancellationRequested ();
- if (child is UsingDirectiveSyntax) {
- if (firstChild == null) {
- firstChild = child;
- }
- lastChild = child;
- continue;
- }
- if (firstChild != null)
- break;
- }
-
- if (firstChild != null && firstChild != lastChild) {
- var first = firstChild.GetLocation ().GetLineSpan ();
- var last = lastChild.GetLocation ().GetLineSpan ();
-
- Foldings.Add (new FoldingRegion (new DocumentRegion (first.StartLinePosition, last.EndLinePosition), FoldType.Undefined));
- }
- }
-
- public override void VisitCompilationUnit (Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddUsings (node);
- base.VisitCompilationUnit (node);
- }
-
- void AddFolding (SyntaxToken openBrace, SyntaxToken closeBrace, FoldType type)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- openBrace = openBrace.GetPreviousToken (false, false, true, true);
-
- try {
- var first = openBrace.GetLocation ().GetLineSpan ();
- var last = closeBrace.GetLocation ().GetLineSpan ();
-
- if (first.EndLinePosition.Line != last.EndLinePosition.Line)
- Foldings.Add (new FoldingRegion (new DocumentRegion (first.EndLinePosition, last.EndLinePosition), type));
- } catch (ArgumentOutOfRangeException) {}
- }
-
- Stack<SyntaxTrivia> regionStack = new Stack<SyntaxTrivia> ();
- public override void VisitTrivia (SyntaxTrivia trivia)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- base.VisitTrivia (trivia);
- if (trivia.IsKind (SyntaxKind.RegionDirectiveTrivia)) {
- regionStack.Push (trivia);
- } else if (trivia.IsKind (SyntaxKind.EndRegionDirectiveTrivia)) {
- if (regionStack.Count == 0)
- return;
- var regionStart = regionStack.Pop ();
- try {
- var first = regionStart.GetLocation ().GetLineSpan ();
- var last = trivia.GetLocation ().GetLineSpan ();
- var v = regionStart.ToString ();
- v = v.Substring ("#region".Length).Trim ();
- if (v.Length == 0)
- v = "...";
- Foldings.Add (new FoldingRegion(v, new DocumentRegion(first.StartLinePosition, last.EndLinePosition), FoldType.UserRegion, true));
- } catch (ArgumentOutOfRangeException) { }
- }
- }
-
- public override void VisitNamespaceDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddUsings (node);
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, FoldType.Undefined);
- base.VisitNamespaceDeclaration (node);
- }
-
- public override void VisitClassDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, FoldType.Type);
- base.VisitClassDeclaration (node);
- }
-
- public override void VisitStructDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, FoldType.Type);
- base.VisitStructDeclaration (node);
- }
-
- public override void VisitInterfaceDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.InterfaceDeclarationSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, FoldType.Type);
- base.VisitInterfaceDeclaration (node);
- }
-
- public override void VisitEnumDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.EnumDeclarationSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, FoldType.Type);
- base.VisitEnumDeclaration (node);
- }
-
- public override void VisitBlock (Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax node)
- {
- cancellationToken.ThrowIfCancellationRequested ();
- AddFolding (node.OpenBraceToken, node.CloseBraceToken, node.Parent is MemberDeclarationSyntax ? FoldType.Member : FoldType.Undefined);
- base.VisitBlock (node);
- }
- }
+ public override Task<IReadOnlyList<FoldingRegion>> GetFoldingsAsync (CancellationToken cancellationToken = default (CancellationToken)) => foldings;
SemaphoreSlim errorLock = new SemaphoreSlim (1, 1);
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
index e881821723..3424347b8d 100644
--- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
+++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml
@@ -318,6 +318,7 @@
<Class class = "MonoDevelop.Ide.Editor.Extension.BraceMatcherTextEditorExtension" />
<Class class = "MonoDevelop.Ide.Editor.Extension.DefaultCommandTextEditorExtension" />
<Class class = "MonoDevelop.Ide.Editor.Extension.FoldingTextEditorExtension" />
+ <Class class = "MonoDevelop.Ide.Editor.Extension.BlockStructureFoldingTextEditorExtension" />
<Class class = "MonoDevelop.Ide.Editor.Extension.ErrorHandlerTextEditorExtension" />
<Class class = "MonoDevelop.Ide.Editor.Extension.AutoInsertBracketTextEditorExtension" />
<Class class = "MonoDevelop.Ide.Editor.Extension.HighlightUrlExtension" />
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/BlockStructureFoldingTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/BlockStructureFoldingTextEditorExtension.cs
new file mode 100644
index 0000000000..6727ea5c80
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/BlockStructureFoldingTextEditorExtension.cs
@@ -0,0 +1,140 @@
+//
+// BlockStructureFoldingTextEditorExtension.cs
+//
+// Author:
+// Mike Krüger <mikkrg@microsoft.com>
+//
+// Copyright (c) 2018 Microsoft Corporation. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// 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 System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Gtk;
+using MonoDevelop.Core;
+using MonoDevelop.Core.Text;
+using MonoDevelop.Ide.Editor.Highlighting;
+using MonoDevelop.Ide.TypeSystem;
+using Microsoft.CodeAnalysis.Structure;
+using System.Collections.Immutable;
+
+namespace MonoDevelop.Ide.Editor.Extension
+{
+ class BlockStructureFoldingTextEditorExtension : TextEditorExtension
+ {
+ CancellationTokenSource src = new CancellationTokenSource ();
+ bool isDisposed;
+
+ protected override void Initialize ()
+ {
+ DocumentContext.DocumentParsed += DocumentContext_DocumentParsed;
+ }
+
+ public override void Dispose ()
+ {
+ if (isDisposed)
+ return;
+ isDisposed = true;
+ CancelDocumentParsedUpdate ();
+ DocumentContext.DocumentParsed -= DocumentContext_DocumentParsed;
+ base.Dispose ();
+ }
+
+ void CancelDocumentParsedUpdate ()
+ {
+ src.Cancel ();
+ src = new CancellationTokenSource ();
+ }
+
+ async void DocumentContext_DocumentParsed (object sender, EventArgs e)
+ {
+ CancelDocumentParsedUpdate ();
+ var analysisDocument = DocumentContext.AnalysisDocument;
+ if (analysisDocument == null || !Editor.Options.ShowFoldMargin)
+ return;
+ var caretLocation = Editor.CaretOffset;
+
+ var outliningService = BlockStructureService.GetService (analysisDocument);
+ if (outliningService == null)
+ return;
+ var token = src.Token;
+ var blockStructure = await outliningService.GetBlockStructureAsync (analysisDocument, token).ConfigureAwait (false);
+ UpdateFoldings (Editor, blockStructure.Spans, caretLocation, false, token);
+ }
+
+ static void UpdateFoldings (TextEditor Editor, ImmutableArray<BlockSpan> spans, int caretOffset, bool firstTime = false, CancellationToken token = default (CancellationToken))
+ {
+ try {
+ var foldSegments = new List<IFoldSegment> ();
+
+ foreach (var blockSpan in spans) {
+ if (token.IsCancellationRequested)
+ return;
+ if (!blockSpan.IsCollapsible)
+ continue;
+ var type = FoldingType.Unknown;
+ switch (blockSpan.Type) {
+ case BlockTypes.Member:
+ type = FoldingType.TypeMember;
+ break;
+ case BlockTypes.Type:
+ type = FoldingType.TypeDefinition;
+ break;
+ case BlockTypes.Comment:
+ type = FoldingType.Comment;
+ break;
+ default:
+ type = FoldingType.Unknown;
+ break;
+ }
+ var start = blockSpan.TextSpan.Start;
+ var end = blockSpan.TextSpan.End;
+ var marker = Editor.CreateFoldSegment (start, end - start);
+ if (marker == null)
+ continue;
+ foldSegments.Add (marker);
+ marker.CollapsedText = blockSpan.BannerText;
+ marker.FoldingType = type;
+ //and, if necessary, set its fold state
+ if (firstTime) {
+ // only fold on document open, later added folds are NOT folded by default.
+ marker.IsCollapsed = blockSpan.IsDefaultCollapsed;
+ continue;
+ }
+ if (blockSpan.TextSpan.Contains (caretOffset))
+ marker.IsCollapsed = false;
+ }
+ if (firstTime) {
+ Editor.SetFoldings (foldSegments);
+ } else {
+ Application.Invoke ((o, args) => {
+ if (!token.IsCancellationRequested)
+ Editor.SetFoldings (foldSegments);
+ });
+ }
+ } catch (OperationCanceledException) {
+ } catch (Exception ex) {
+ LoggingService.LogError ("Unhandled exception in ParseInformationUpdaterWorkerThread", ex);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
index b21db9d955..750687104d 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj
@@ -9646,6 +9646,7 @@
<Compile Include="Gui\MonoDevelop.Ide.Projects.SelectReferenceDialog.cs" />
<Compile Include="Gui\MonoDevelop.Ide.SelectEncodingsDialog.cs" />
<Compile Include="Gui\MonoDevelop.Ide.StandardHeader.StandardHeaderPolicyPanelWidget.cs" />
+ <Compile Include="MonoDevelop.Ide.Editor.Extension\BlockStructureFoldingTextEditorExtension.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Makefile.am" />