Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 2d5cf8f

Browse files
committed
[Ide] Fix code duplication in MonoDevelopWorkspace
Code for the ApplyAnalyzerConfigDocumentTextChanged and the ApplyAnalyzerConfigDocumentAdded method was very similar to the existing ApplyDocumentTextChanged and ApplyDocumentAdded since the new analyer config methods were based on the original document methods. Refactored the code and shared it where possible.
1 parent c1999b9 commit 2d5cf8f

File tree

1 file changed

+87
-173
lines changed

1 file changed

+87
-173
lines changed

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs

Lines changed: 87 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,9 @@ protected override void ApplyDocumentTextChanged (DocumentId id, SourceText text
728728
tryApplyState_documentTextChangedTasks.Add (ApplyDocumentTextChangedCore (id, text));
729729
}
730730

731-
async Task ApplyDocumentTextChangedCore (DocumentId id, SourceText text)
731+
async Task ApplyDocumentTextChangedCore (DocumentId id, SourceText text, bool isAnalyzerConfigFile = false)
732732
{
733-
var document = GetDocument (id);
733+
TextDocument document = isAnalyzerConfigFile ? GetAnalyzerConfigDocument (id) : GetDocument (id);
734734
if (document == null)
735735
return;
736736

@@ -747,12 +747,21 @@ async Task ApplyDocumentTextChangedCore (DocumentId id, SourceText text)
747747
return;
748748
}
749749
}
750-
var (projection, filePath) = Projections.Get (document.FilePath);
751-
var data = TextFileProvider.Instance.GetTextEditorData (filePath, out bool isOpen);
752-
// Guard against already done changes in linked files.
753-
// This shouldn't happen but the roslyn merging seems not to be working correctly in all cases :/
754-
if (document.GetLinkedDocumentIds ().Length > 0 && isOpen && !(text.GetType ().FullName == "Microsoft.CodeAnalysis.Text.ChangedText")) {
755-
return;
750+
Projection projection = null;
751+
FilePath filePath;
752+
ITextDocument data = null;
753+
bool isOpen;
754+
if (isAnalyzerConfigFile) {
755+
filePath = document.FilePath;
756+
data = TextFileProvider.Instance.GetTextEditorData (filePath, out isOpen);
757+
} else {
758+
(projection, filePath) = Projections.Get (document.FilePath);
759+
data = TextFileProvider.Instance.GetTextEditorData (filePath, out isOpen);
760+
// Guard against already done changes in linked files.
761+
// This shouldn't happen but the roslyn merging seems not to be working correctly in all cases :/
762+
if (((Document)document).GetLinkedDocumentIds ().Length > 0 && isOpen && !(text.GetType ().FullName == "Microsoft.CodeAnalysis.Text.ChangedText")) {
763+
return;
764+
}
756765
}
757766

758767
lock (tryApplyState_documentTextChangedContents) {
@@ -796,20 +805,29 @@ async Task ApplyDocumentTextChangedCore (DocumentId id, SourceText text)
796805
}
797806
data.Save ();
798807
if (projection != null) {
799-
await UpdateProjectionsDocuments (document, data);
808+
await UpdateProjectionsDocuments ((Document)document, data);
809+
} else if (isAnalyzerConfigFile) {
810+
OnAnalyzerConfigDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
800811
} else {
801812
OnDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
802813
}
803814
} else {
804815
var formatter = CodeFormatterService.GetFormatter (data.MimeType);
805816
var documentContext = documentManager.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0)?.DocumentContext;
806-
var root = await projectChanges.NewProject.GetDocument (id).GetSyntaxRootAsync ();
807-
var annotatedNode = root.DescendantNodesAndSelf ().FirstOrDefault (n => n.HasAnnotation (typeSystemService.InsertionModeAnnotation));
808-
SyntaxToken? renameTokenOpt = root.GetAnnotatedNodesAndTokens (Microsoft.CodeAnalysis.CodeActions.RenameAnnotation.Kind)
809-
.Where (s => s.IsToken)
810-
.Select (s => s.AsToken ())
811-
.Cast<SyntaxToken?> ()
812-
.FirstOrDefault ();
817+
818+
SyntaxNode root = null;
819+
SyntaxNode annotatedNode = null;
820+
SyntaxToken? renameTokenOpt = null;
821+
822+
if (!isAnalyzerConfigFile) {
823+
root = await projectChanges.NewProject.GetDocument (id).GetSyntaxRootAsync ();
824+
annotatedNode = root.DescendantNodesAndSelf ().FirstOrDefault (n => n.HasAnnotation (typeSystemService.InsertionModeAnnotation));
825+
renameTokenOpt = root.GetAnnotatedNodesAndTokens (Microsoft.CodeAnalysis.CodeActions.RenameAnnotation.Kind)
826+
.Where (s => s.IsToken)
827+
.Select (s => s.AsToken ())
828+
.Cast<SyntaxToken?> ()
829+
.FirstOrDefault ();
830+
}
813831

814832
if (documentContext != null) {
815833
var editor = (TextEditor)data;
@@ -933,7 +951,9 @@ await Runtime.RunInMainThread (async () => {
933951
}
934952

935953
if (projection != null) {
936-
await UpdateProjectionsDocuments (document, data);
954+
await UpdateProjectionsDocuments ((Document)document, data);
955+
} else if (isAnalyzerConfigFile) {
956+
OnAnalyzerConfigDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
937957
} else {
938958
OnDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
939959
}
@@ -943,100 +963,8 @@ await Runtime.RunInMainThread (async () => {
943963
protected override void ApplyAnalyzerConfigDocumentTextChanged (DocumentId id, SourceText text)
944964
{
945965
lock (projectModifyLock)
946-
tryApplyState_documentTextChangedTasks.Add (ApplyAnalyzerConfigDocumentTextChangedCore (id, text));
966+
tryApplyState_documentTextChangedTasks.Add (ApplyDocumentTextChangedCore (id, text, isAnalyzerConfigFile: true));
947967
}
948-
949-
/// <summary>
950-
/// TODO: Fix code duplication with ApplyDocumentTextChangedCore
951-
/// </summary>
952-
async Task ApplyAnalyzerConfigDocumentTextChangedCore (DocumentId id, SourceText text)
953-
{
954-
var document = GetAnalyzerConfigDocument (id);
955-
if (document == null)
956-
return;
957-
958-
var hostDocument = MonoDevelopHostDocumentRegistration.FromDocument (document);
959-
if (hostDocument != null) {
960-
hostDocument.UpdateText (text);
961-
return;
962-
}
963-
if (IsDocumentOpen (id)) {
964-
var textBuffer = (await document.GetTextAsync (CancellationToken.None)).Container.TryGetTextBuffer ();
965-
966-
if (textBuffer != null) {
967-
UpdateText (text, textBuffer, Microsoft.VisualStudio.Text.EditOptions.DefaultMinimalChange);
968-
return;
969-
}
970-
}
971-
var filePath = document.FilePath;
972-
var data = TextFileProvider.Instance.GetTextEditorData (filePath, out bool isOpen);
973-
974-
lock (tryApplyState_documentTextChangedContents) {
975-
if (tryApplyState_documentTextChangedContents.TryGetValue (filePath, out SourceText formerText)) {
976-
if (formerText.Length == text.Length && formerText.ToString () == text.ToString ())
977-
return;
978-
}
979-
tryApplyState_documentTextChangedContents [filePath] = text;
980-
}
981-
982-
if (!isOpen || !document.TryGetText (out SourceText oldFile)) {
983-
oldFile = await document.GetTextAsync ();
984-
}
985-
var changes = text.GetTextChanges (oldFile).OrderByDescending (c => c.Span.Start).ToList ();
986-
int delta = 0;
987-
988-
if (!isOpen) {
989-
delta = ApplyChanges (null, data, changes);
990-
var formatter = CodeFormatterService.GetFormatter (data.MimeType);
991-
if (formatter != null && formatter.SupportsPartialDocumentFormatting) {
992-
var mp = GetMonoProject (CurrentSolution.GetProject (id.ProjectId));
993-
string currentText = data.Text;
994-
995-
foreach (var change in changes) {
996-
delta -= change.Span.Length - change.NewText.Length;
997-
var startOffset = change.Span.Start - delta;
998-
999-
string str;
1000-
if (change.NewText.Length == 0) {
1001-
str = formatter.FormatText (mp.Policies, currentText, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
1002-
} else {
1003-
str = formatter.FormatText (mp.Policies, currentText, new TextSegment (startOffset, change.NewText.Length));
1004-
}
1005-
data.ReplaceText (startOffset, change.NewText.Length, str);
1006-
}
1007-
}
1008-
data.Save ();
1009-
OnAnalyzerConfigDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
1010-
} else {
1011-
var formatter = CodeFormatterService.GetFormatter (data.MimeType);
1012-
var documentContext = documentManager.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0)?.DocumentContext;
1013-
1014-
if (documentContext != null) {
1015-
var editor = (TextEditor)data;
1016-
await Runtime.RunInMainThread (async () => {
1017-
using (var undo = editor.OpenUndoGroup ()) {
1018-
var oldVersion = editor.Version;
1019-
delta = ApplyChanges (null, data, changes);
1020-
var versionBeforeFormat = editor.Version;
1021-
1022-
if (formatter != null && formatter.SupportsOnTheFlyFormatting) {
1023-
foreach (var change in changes) {
1024-
delta -= change.Span.Length - change.NewText.Length;
1025-
var startOffset = change.Span.Start - delta;
1026-
if (change.NewText.Length == 0) {
1027-
formatter.OnTheFlyFormat (editor, documentContext, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
1028-
} else {
1029-
formatter.OnTheFlyFormat (editor, documentContext, new TextSegment (startOffset, change.NewText.Length));
1030-
}
1031-
}
1032-
}
1033-
}
1034-
});
1035-
}
1036-
1037-
OnAnalyzerConfigDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
1038-
}
1039-
}
1040968

1041969
internal static Func<TextEditor, int, Task<List<InsertionPoint>>> GetInsertionPoints;
1042970
internal static Action<TextEditor, DocumentContext, ITextSourceVersion, SyntaxToken?> StartRenameSession;
@@ -1184,99 +1112,66 @@ protected override void ApplyProjectChanges (ProjectChanges projectChanges)
11841112

11851113
protected override void ApplyDocumentAdded (DocumentInfo info, SourceText text)
11861114
{
1187-
var id = info.Id;
1188-
MonoDevelop.Projects.Project mdProject = null;
1189-
1190-
if (id.ProjectId != null) {
1191-
var project = CurrentSolution.GetProject (id.ProjectId);
1192-
mdProject = GetMonoProject (project);
1193-
if (mdProject == null)
1194-
LoggingService.LogWarning ("Couldn't find project for newly generated file {0} (Project {1}).", info.Name, info.Id.ProjectId);
1195-
}
1115+
var mdProject = GetMonoProject (info);
11961116

1197-
var path = DetermineFilePath (info.Id, info.Name, info.FilePath, info.Folders, mdProject?.FileName.ParentDirectory, true);
1117+
var path = DetermineFilePath (info, mdProject, true);
11981118
// If file is already part of project don't re-add it, example of this is .cshtml
11991119
if (mdProject?.IsFileInProject (path) == true) {
12001120
this.OnDocumentAdded (info);
12011121
return;
12021122
}
12031123
info = info.WithFilePath (path).WithTextLoader (new MonoDevelopTextLoader (path));
12041124

1205-
string formattedText;
1206-
var formatter = CodeFormatterService.GetFormatter (desktopService.GetMimeTypeForUri (path));
1207-
if (formatter != null && mdProject != null) {
1208-
formattedText = formatter.FormatText (mdProject.Policies, text.ToString ());
1209-
} else {
1210-
formattedText = text.ToString ();
1211-
}
1212-
1213-
var textSource = new StringTextSource (formattedText, text.Encoding ?? System.Text.Encoding.UTF8);
1214-
try {
1215-
textSource.WriteTextTo (path);
1216-
} catch (Exception e) {
1217-
LoggingService.LogError ("Exception while saving file to " + path, e);
1218-
}
1125+
FormatFile (text, mdProject, path);
12191126

12201127
if (mdProject != null) {
1221-
var data = ProjectMap.GetData (id.ProjectId);
1128+
var data = ProjectMap.GetData (info.Id.ProjectId);
12221129
data.DocumentData.Add (info.Id, path);
12231130
var file = new MonoDevelop.Projects.ProjectFile (path);
12241131
mdProject.Files.Add (file);
12251132
tryApplyState_changedProjects.Add (mdProject);
12261133
}
12271134

12281135
this.OnDocumentAdded (info);
1229-
}
1230-
1231-
/// <summary>
1232-
/// TODO: Code is similar to ApplyDocumentAdded. Can we share code similar to VisualStudioWorkspaceImpl?
1233-
/// https://github.com/dotnet/roslyn/blob/3149ba26d3ea5949532028c71b9533658a8cab8b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs#L719-L732
1234-
/// </summary>
1235-
protected override void ApplyAnalyzerConfigDocumentAdded (DocumentInfo info, SourceText text)
1236-
{
1237-
var id = info.Id;
1238-
MonoDevelop.Projects.Project mdProject = null;
1136+
}
12391137

1138+
MonoDevelop.Projects.Project GetMonoProject (DocumentInfo info)
1139+
{
1140+
var id = info.Id;
12401141
if (id.ProjectId != null) {
12411142
var project = CurrentSolution.GetProject (id.ProjectId);
1242-
mdProject = GetMonoProject (project);
1143+
var mdProject = GetMonoProject (project);
12431144
if (mdProject == null)
1244-
LoggingService.LogWarning ("Couldn't find project for newly generated file {0} (Project {1}).", info.Name, info.Id.ProjectId);
1145+
LoggingService.LogWarning ("Couldn't find project for document {0} (Project {1}).", info.Name, id.ProjectId);
1146+
return mdProject;
12451147
}
1148+
return null;
1149+
}
1150+
1151+
protected override void ApplyAnalyzerConfigDocumentAdded (DocumentInfo info, SourceText text)
1152+
{
1153+
var mdProject = GetMonoProject (info);
12461154

1247-
var path = DetermineFilePath (info.Id, info.Name, info.FilePath, info.Folders, mdProject?.FileName.ParentDirectory, true);
1248-
// If file is already part of project don't re-add it, example of this is .cshtml
1155+
var path = DetermineFilePath (info, mdProject, true);
1156+
// If file is already part of project don't re-add it unless it does not exist.
12491157
if (mdProject?.IsFileInProject (path) == true && File.Exists (path)) {
12501158
OnAnalyzerConfigDocumentAdded (info);
12511159
return;
12521160
}
1253-
info = info.WithFilePath (path).WithTextLoader (new MonoDevelopTextLoader (path));
1254-
1255-
string formattedText;
1256-
var formatter = CodeFormatterService.GetFormatter (desktopService.GetMimeTypeForUri (path));
1257-
if (formatter != null && mdProject != null) {
1258-
formattedText = formatter.FormatText (mdProject.Policies, text.ToString ());
1259-
} else {
1260-
formattedText = text.ToString ();
1261-
}
1262-
1263-
var textSource = new StringTextSource (formattedText, text.Encoding ?? System.Text.Encoding.UTF8);
1264-
try {
1265-
textSource.WriteTextTo (path);
1266-
} catch (Exception e) {
1267-
LoggingService.LogError ("Exception while saving file to " + path, e);
1268-
}
1161+
info = info.WithFilePath (path).WithTextLoader (new MonoDevelopTextLoader (path));
1162+
1163+
FormatFile (text, mdProject, path);
12691164

12701165
if (mdProject != null) {
1271-
var data = ProjectMap.GetData (id.ProjectId);
1166+
var data = ProjectMap.GetData (info.Id.ProjectId);
12721167
data.DocumentData.Add (info.Id, path);
12731168

12741169
var file = new MonoDevelop.Projects.ProjectFile (path, MonoDevelop.Projects.BuildAction.None);
1275-
if (!file.FilePath.IsChildPathOf (mdProject.BaseDirectory)) {
1170+
if (!file.FilePath.IsChildPathOf (mdProject.BaseDirectory)) {
12761171
// Outside project directory - add it as a solution folder item.
12771172
var solutionFolder = GetSolutionItemsFolder (mdProject);
12781173
if (!solutionFolder.Files.Contains (path)) {
1279-
solutionFolder.Files.Add (path);
1174+
solutionFolder.Files.Add (path);
12801175
mdProject.ParentSolution.SaveAsync (new ProgressMonitor ()).Ignore ();
12811176
}
12821177
}
@@ -1294,6 +1189,24 @@ protected override void ApplyAnalyzerConfigDocumentAdded (DocumentInfo info, Sou
12941189
OnAnalyzerConfigDocumentAdded (info);
12951190
}
12961191

1192+
void FormatFile (SourceText text, MonoDevelop.Projects.Project mdProject, string path)
1193+
{
1194+
string formattedText;
1195+
var formatter = CodeFormatterService.GetFormatter (desktopService.GetMimeTypeForUri (path));
1196+
if (formatter != null && mdProject != null) {
1197+
formattedText = formatter.FormatText (mdProject.Policies, text.ToString ());
1198+
} else {
1199+
formattedText = text.ToString ();
1200+
}
1201+
1202+
var textSource = new StringTextSource (formattedText, text.Encoding ?? System.Text.Encoding.UTF8);
1203+
try {
1204+
textSource.WriteTextTo (path);
1205+
} catch (Exception e) {
1206+
LoggingService.LogError ("Exception while saving file to " + path, e);
1207+
}
1208+
}
1209+
12971210
MonoDevelop.Projects.SolutionFolder GetSolutionItemsFolder (MonoDevelop.Projects.Project project)
12981211
{
12991212
string name = GettextCatalog.GetString ("Solution Items");
@@ -1343,16 +1256,17 @@ protected override void ApplyAnalyzerConfigDocumentRemoved (DocumentId documentI
13431256
base.ApplyAnalyzerConfigDocumentRemoved (documentId);
13441257
}
13451258

1346-
string DetermineFilePath (DocumentId id, string name, string filePath, IReadOnlyList<string> docFolders, string defaultFolder, bool createDirectory = false)
1259+
string DetermineFilePath (DocumentInfo info, MonoDevelop.Projects.Project mdProject, bool createDirectory = false)
13471260
{
1348-
var path = filePath;
1261+
var path = info.FilePath;
13491262

13501263
if (string.IsNullOrEmpty (path)) {
1351-
var monoProject = GetMonoProject (id.ProjectId);
1264+
var monoProject = GetMonoProject (info.Id.ProjectId);
13521265

13531266
// If the first namespace name matches the name of the project, then we don't want to
13541267
// generate a folder for that. The project is implicitly a folder with that name.
13551268
IEnumerable<string> folders;
1269+
var docFolders = info.Folders;
13561270
if (docFolders != null && monoProject != null && docFolders.FirstOrDefault () == monoProject.Name) {
13571271
folders = docFolders.Skip (1);
13581272
} else {
@@ -1367,9 +1281,9 @@ string DetermineFilePath (DocumentId id, string name, string filePath, IReadOnly
13671281
} catch (Exception e) {
13681282
LoggingService.LogError ("Error while creating directory for a new file : " + baseDirectory, e);
13691283
}
1370-
path = Path.Combine (baseDirectory, name);
1284+
path = Path.Combine (baseDirectory, info.Name);
13711285
} else {
1372-
path = Path.Combine (defaultFolder, name);
1286+
path = Path.Combine (mdProject?.FileName.ParentDirectory, info.Name);
13731287
}
13741288
}
13751289
return path;

0 commit comments

Comments
 (0)