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); } }); }
public void UpdateCode(string contentId, TextDiff update) { UpdateCode(contentId, update, true); }