private void HostReferences(object sender, ReferencesEventArgs e) { var proj = _state.Workspace.Projects.SingleOrDefault(p => p.Id == e.ContextId); if (proj == null) { return; } UpdateNode <ProjectEntry>(proj.RelativePath, (p, c) => p.WithReferences(e, c)); _compilations.AddOrUpdate(proj.Id, id => ProjectCompilation.Create(proj.Name, proj.Id), (id, old) => old.InvalidateReferences()); }
private void HostConfigurations(object sender, ConfigurationsEventArgs e) { var proj = _state.Workspace.Projects.SingleOrDefault(p => p.Id == e.ContextId); if (proj == null) { return; } // TODO: Keep commands UpdateNode <ProjectEntry>(proj.RelativePath, (p, c) => p.WithConfigurations(e.ProjectName, e.Configurations)); _compilations.AddOrUpdate(proj.Id, id => ProjectCompilation.Create(proj.Name, proj.Id), (id, old) => old.InvalidateConfiguration()); }
public void UpdateCode(string contentId, string text) { Task.Run(() => { // updates needs to be processed in the same order they are generated // this method might wait for the next update, thus running in background // thread Content content, old; var dict = _contentDictionary; lock (dict) { if (!_contentDictionary.TryGetValue(contentId, out content)) { throw new Exception("Content wasn't in dictionary. Illegal code::update sent"); } old = content; content = content.WithText(text); if (!_contentDictionary.TryUpdate(contentId, content, old)) { throw new Exception("Content has been updated by other method. State inconclusive."); } } // mark dirty if (old.ContentString == content.ContentString) { return; } var workspace = _state.Workspace; if (workspace == null) { return; } var proj = workspace.Projects.SingleOrDefault(p => content.RelativePath.StartsWith(p.RelativePath, StringComparison.OrdinalIgnoreCase)); if (proj == null) { return; } _compilations.AddOrUpdate(proj.Id, id => ProjectCompilation.Create(proj.Name, proj.Id), (i, p) => p.InvalidateSources()); MarkTab(contentId, dirty: true); }); }
public void UpdateCode(string contentId, TextDiff update, bool highlight) { Task.Run(() => { // updates needs to be processed in the same order they are generated // this method might wait for the next update, thus running in background // thread Content content; var dict = _contentDictionary; lock (dict) { while (update.Update != Volatile.Read(ref _nextUpdate)) { Monitor.Wait(dict); } Interlocked.Increment(ref _nextUpdate); if (!_contentDictionary.TryGetValue(contentId, out content)) { throw new Exception("Content wasn't in dictionary. Illegal code::update sent"); } if (update.Start == 0 && update.Added == content.ContentString.Length && update.Text == content.ContentString) { goto highlight; // editor sends updates when files are opened } var text = content.ContentString; var sb = new StringBuilder().Append(text, 0, update.Start); sb.Append(update.Text); sb.Append(text, update.Start + update.Removed, text.Length - update.Start - update.Removed); text = sb.ToString(); Content old = content; content = content.WithText(text); if (!_contentDictionary.TryUpdate(contentId, content, old)) { throw new Exception("Content has been updated by other method. State inconclusive."); } } // mark dirty MarkTab(contentId, dirty: true); var workspace = _state.Workspace; if (workspace == null) { return; } var proj = workspace.Projects.SingleOrDefault(p => content.RelativePath.StartsWith(p.RelativePath, StringComparison.OrdinalIgnoreCase)); if (proj == null) { return; } _compilations.AddOrUpdate(proj.Id, id => ProjectCompilation.Create(proj.Name, proj.Id), (i, p) => p.InvalidateSources()); highlight: if (highlight) { Highlight(content); } }); }
ProjectCompilation GetCompilation(int id) { Contract.Ensures(Contract.Result <ProjectCompilation>().IsValid); var state = _state; var compilation = _compilations.GetOrAdd(id, i => ProjectCompilation.Create(_state.Workspace.Projects.Single(p => p.Id == i).Name, i)); List <MetadataReference> references = null; Dictionary <int, int> projRefs = null; List <SyntaxTree> sources = null; ProjectEntry proj = null; ConfigurationData configData = null; CSharpParseOptions config = null; ProjectCompilation refComp; if (compilation.IsValid) { foreach (var projectRef in compilation.ProjectReferences) { refComp = GetCompilation(projectRef.Key); if (refComp.Version == projectRef.Value) { continue; } if (references == null) { references = new List <MetadataReference>(); } if (projRefs == null) { projRefs = new Dictionary <int, int>(); } references.Add(refComp.GetMetadataReference()); projRefs.Add(refComp.Id, refComp.Version); } if (references == null) { return(compilation); } } Workspace workspace = state.Workspace; proj = workspace.Projects.Single(p => p.Id == id); // TODO: Use "current configuration" configData = proj.Configurations.Single(c => c.FrameworkName == "net45"); Action <string> addAssembly = path => { if (!File.Exists(path)) { return; } DocumentationProvider doc = null; var docFile = Path.ChangeExtension(path, ".xml"); if (File.Exists(docFile)) { doc = XmlDocumentationProvider.Create(docFile); } references.Add(new MetadataFileReference(path, documentation: doc)); }; if (references != null || compilation.NeedsReferences) { if (references == null) { references = new List <MetadataReference>(); } if (projRefs == null) { projRefs = new Dictionary <int, int>(); } foreach (var package in proj.References) { if (package.Unresolved) { continue; } switch (package.Type) { case "Package": var path = Path.Combine(package.Path, "lib", proj.Configurations.Single(c => c.LongFrameworkName == package.Framework).FrameworkName); if (Directory.Exists(path)) { foreach (var file in Directory.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly)) { addAssembly(file); } foreach (var file in Directory.EnumerateFiles(path, "*.exe", SearchOption.TopDirectoryOnly)) { addAssembly(file); } } break; case "Assembly": if (File.Exists(package.Path)) { addAssembly(package.Path); } else { // TODO: Implement assemblyneutral types } break; case "Project": // path is dir/project.json var pid = _projectLookup[Path.GetDirectoryName(package.Path)]; if (!projRefs.ContainsKey(pid)) { refComp = GetCompilation(pid); references.Add(refComp.GetMetadataReference()); projRefs.Add(pid, refComp.Version); } break; default: throw new ArgumentException("Unknown reference type"); } } } if (sources != null || compilation.NeedsSources) { if (config == null) { config = CSharpParseOptions.Default .WithLanguageVersion((LanguageVersion)configData.CompilationSettings.LanguageVersion) .WithPreprocessorSymbols(configData.CompilationSettings.Defines) .WithDocumentationMode(DocumentationMode.Parse); } if (sources == null) { sources = new List <SyntaxTree>(); } // TODO: Support generated files foreach (var source in proj.Sources) { var content = _contentDictionary.Values.SingleOrDefault(c => Path.Combine(workspace.Path, c.RelativePath) == source); if (content != null) { sources.Add(CSharpSyntaxTree.ParseText(content.ContentString, path: source, options: config)); } else { sources.Add(CSharpSyntaxTree.ParseFile(source, options: config)); } } } var newComp = compilation.Update(projRefs, references, sources); _compilations.TryUpdate(id, newComp, compilation); return(newComp); }