public void OnUpdatePrefix(string prefix, CodeDB.EventAccessor accessor) { lock (accessLock) { buildState.SearchPrefixesToRebuild.Add(prefix); } }
// Group: CodeDB.IChangeWatcher Functions // __________________________________________________________________________ public void OnAddTopic(Topic topic, CodeDB.EventAccessor eventAccessor) { // If this topic defines a class, it's possible it's now the best definition and thus we have to update the class prototypes // of all its parents. We don't have to worry about updating children because that will be taken care of by OnLinkChange // since there would be a class parent link pointing to it. IDObjects.NumberSet parentClassIDs = null; IDObjects.NumberSet parentClassFileIDs = null; if (topic.DefinesClass) { eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs); } lock (accessLock) { buildState.SourceFilesToRebuild.Add(topic.FileID); if (topic.ClassID != 0) { buildState.ClassFilesToRebuild.Add(topic.ClassID); } if (parentClassIDs != null) { buildState.ClassFilesToRebuild.Add(parentClassIDs); } if (parentClassFileIDs != null) { buildState.SourceFilesToRebuild.Add(parentClassFileIDs); } } }
public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, CodeDB.EventAccessor eventAccessor) { // We'll wait for OnChangeLinkTarget to handle linksAffected IDObjects.NumberSet parentClassIDs = null; IDObjects.NumberSet parentClassFileIDs = null; if (topic.DefinesClass) { eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs); } lock (accessLock) { buildState.SourceFilesToRebuild.Add(topic.FileID); if (topic.ClassID != 0) { buildState.ClassFilesToRebuild.Add(topic.ClassID); } if (parentClassIDs != null) { buildState.ClassFilesToRebuild.Add(parentClassIDs); } if (parentClassFileIDs != null) { buildState.SourceFilesToRebuild.Add(parentClassFileIDs); } } }
public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, CodeDB.EventAccessor eventAccessor) { // We'll wait for OnChangeLinkTarget to handle linksAffected IDObjects.NumberSet parentClassIDs = null; IDObjects.NumberSet parentClassFileIDs = null; if (topic.DefinesClass) { eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs); } unprocessedChanges.Lock(); try { unprocessedChanges.AddSourceFile(topic.FileID); if (topic.ClassID != 0) { unprocessedChanges.AddClass(topic.ClassID); } if (parentClassIDs != null) { unprocessedChanges.AddClasses(parentClassIDs); } if (parentClassFileIDs != null) { unprocessedChanges.AddSourceFiles(parentClassFileIDs); } } finally { unprocessedChanges.Unlock(); } }
public void OnDeleteTopic(Topic topic, CodeDB.EventAccessor eventAccessor) { IDObjects.NumberSet parentClassIDs = null; IDObjects.NumberSet parentClassFileIDs = null; if (topic.DefinesClass) { eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs); } lock (accessLock) { buildState.SourceFilesToRebuild.Add(topic.FileID); if (topic.ClassID != 0) { buildState.ClassFilesToRebuild.Add(topic.ClassID); } if (parentClassIDs != null) { buildState.ClassFilesToRebuild.Add(parentClassIDs); } if (parentClassFileIDs != null) { buildState.SourceFilesToRebuild.Add(parentClassFileIDs); } } }
public void OnDeletePrefix(string prefix, CodeDB.EventAccessor accessor) { lock (accessLock) { buildState.NeedToBuildSearchPrefixIndex = true; buildState.SearchPrefixesToRebuild.Add(prefix); } }
public void OnDeleteImageLink(ImageLink imageLink, CodeDB.EventAccessor eventAccessor) { // We don't have to force any HTML to be rebuilt here. This can only happen if the containing topic was // changed so we can rely on the topic code to handle that. // However, this could change whether the image file is used or unused, so we have to add it to the list. if (imageLink.TargetFileID != 0) { unprocessedChanges.AddImageFileUseCheck(imageLink.TargetFileID); } }
public void OnAddLink(Link link, CodeDB.EventAccessor eventAccessor) { // If a class parent link was added we have to rebuild all source files that define that class as the class prototype // may have changed. IDObjects.NumberSet filesThatDefineClass = null; if (link.Type == LinkType.ClassParent) { filesThatDefineClass = eventAccessor.GetFileIDsThatDefineClassID(link.ClassID); // If it's resolved we have to rebuild all source files that define the target as well so its children get updated. if (link.TargetClassID != 0) { IDObjects.NumberSet filesThatDefineTarget = eventAccessor.GetFileIDsThatDefineClassID(link.TargetClassID); if (filesThatDefineClass == null) { filesThatDefineClass = filesThatDefineTarget; } else if (filesThatDefineTarget != null) { filesThatDefineClass.Add(filesThatDefineTarget); } } } unprocessedChanges.Lock(); try { // Even if it's not a class parent link we still need to rebuild the source and class files that contain it. We can't // rely on the topic events picking it up because it's possible to change links without changing topics. How? By // changing a using statement, which causes all the links to change. unprocessedChanges.AddSourceFile(link.FileID); if (link.ClassID != 0) { unprocessedChanges.AddClass(link.ClassID); } if (link.Type == LinkType.ClassParent && link.TargetClassID != 0) { unprocessedChanges.AddClass(link.TargetClassID); } if (filesThatDefineClass != null) { unprocessedChanges.AddSourceFiles(filesThatDefineClass); } } finally { unprocessedChanges.Unlock(); } }
public void OnDeleteLink(Link link, CodeDB.EventAccessor eventAccessor) { IDObjects.NumberSet filesThatDefineClass = null; if (link.Type == LinkType.ClassParent) { filesThatDefineClass = eventAccessor.GetFileIDsThatDefineClassID(link.ClassID); if (link.TargetClassID != 0) { IDObjects.NumberSet filesThatDefineTarget = eventAccessor.GetFileIDsThatDefineClassID(link.TargetClassID); if (filesThatDefineClass == null) { filesThatDefineClass = filesThatDefineTarget; } else if (filesThatDefineTarget != null) { filesThatDefineClass.Add(filesThatDefineTarget); } } } unprocessedChanges.Lock(); try { unprocessedChanges.AddSourceFile(link.FileID); if (link.ClassID != 0) { unprocessedChanges.AddClass(link.ClassID); } if (link.Type == LinkType.ClassParent && link.TargetClassID != 0) { unprocessedChanges.AddClass(link.TargetClassID); } if (filesThatDefineClass != null) { unprocessedChanges.AddSourceFiles(filesThatDefineClass); } } finally { unprocessedChanges.Unlock(); } }
public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, CodeDB.EventAccessor eventAccessor) { if (!IncludeInIndex(topic)) { return; } TopicEntry entry = new TopicEntry(topic, this); accessLock.EnterWriteLock(); try { foreach (string keyword in entry.Keywords) { string prefix = KeywordPrefix(keyword); var numberSet = prefixTopicIDs[prefix]; if (numberSet != null) { numberSet.Remove(topic.TopicID); if (numberSet.IsEmpty) { prefixTopicIDs.Remove(prefix); foreach (var changeWatcher in changeWatchers) { changeWatcher.OnDeletePrefix(prefix, eventAccessor); } } else { foreach (var changeWatcher in changeWatchers) { changeWatcher.OnUpdatePrefix(prefix, eventAccessor); } } } } } finally { accessLock.ExitWriteLock(); } }
public void OnDeleteLink(Link link, CodeDB.EventAccessor eventAccessor) { IDObjects.NumberSet filesThatDefineClass = null; if (link.Type == LinkType.ClassParent) { filesThatDefineClass = eventAccessor.GetFileIDsThatDefineClassID(link.ClassID); if (link.TargetClassID != 0) { IDObjects.NumberSet filesThatDefineTarget = eventAccessor.GetFileIDsThatDefineClassID(link.TargetClassID); if (filesThatDefineClass == null) { filesThatDefineClass = filesThatDefineTarget; } else if (filesThatDefineTarget != null) { filesThatDefineClass.Add(filesThatDefineTarget); } } } lock (accessLock) { buildState.SourceFilesToRebuild.Add(link.FileID); if (link.ClassID != 0) { buildState.ClassFilesToRebuild.Add(link.ClassID); } if (link.Type == LinkType.ClassParent && link.TargetClassID != 0) { buildState.ClassFilesToRebuild.Add(link.TargetClassID); } if (filesThatDefineClass != null) { buildState.SourceFilesToRebuild.Add(filesThatDefineClass); } } }
// Group: CodeDB.IChangeWatcher Functions // __________________________________________________________________________ public void OnAddTopic(Topic topic, CodeDB.EventAccessor eventAccessor) { if (!IncludeInIndex(topic)) { return; } TopicEntry entry = new TopicEntry(topic, this); accessLock.EnterWriteLock(); try { foreach (string keyword in entry.Keywords) { string prefix = KeywordPrefix(keyword); var topicIDs = prefixTopicIDs[prefix]; if (topicIDs == null) { topicIDs = new IDObjects.NumberSet(); topicIDs.Add(topic.TopicID); prefixTopicIDs[prefix] = topicIDs; foreach (var changeWatcher in changeWatchers) { changeWatcher.OnAddPrefix(prefix, eventAccessor); } } else { topicIDs.Add(topic.TopicID); foreach (var changeWatcher in changeWatchers) { changeWatcher.OnUpdatePrefix(prefix, eventAccessor); } } } } finally { accessLock.ExitWriteLock(); } }
public void OnChangeLinkTarget(Link link, int oldTargetTopicID, int oldTargetClassID, CodeDB.EventAccessor eventAccessor) { IDObjects.NumberSet filesThatDefineClass = null; if (link.Type == LinkType.ClassParent) { filesThatDefineClass = eventAccessor.GetFileIDsThatDefineClassID(link.ClassID); if (link.TargetClassID != 0) { IDObjects.NumberSet filesThatDefineTarget = eventAccessor.GetFileIDsThatDefineClassID(link.TargetClassID); if (filesThatDefineClass == null) { filesThatDefineClass = filesThatDefineTarget; } else if (filesThatDefineTarget != null) { filesThatDefineClass.Add(filesThatDefineTarget); } } if (oldTargetClassID != 0) { IDObjects.NumberSet filesThatDefineOldTarget = eventAccessor.GetFileIDsThatDefineClassID(oldTargetClassID); if (filesThatDefineClass == null) { filesThatDefineClass = filesThatDefineOldTarget; } else if (filesThatDefineOldTarget != null) { filesThatDefineClass.Add(filesThatDefineOldTarget); } } } lock (accessLock) { buildState.SourceFilesToRebuild.Add(link.FileID); if (link.ClassID != 0) { buildState.ClassFilesToRebuild.Add(link.ClassID); } if (link.Type == LinkType.ClassParent) { if (link.TargetClassID != 0) { buildState.ClassFilesToRebuild.Add(link.TargetClassID); } if (oldTargetClassID != 0) { buildState.ClassFilesToRebuild.Add(oldTargetClassID); } } if (filesThatDefineClass != null) { buildState.SourceFilesToRebuild.Add(filesThatDefineClass); } } // If this is a Natural Docs link, see if it appears in the summary for any topics. This would mean that it appears in // these topics' tooltips, so we have to find any links to these topics and rebuild the files those links appear in. // Why do we have to do this if links aren't added to tooltips? Because how it's resolved can affect it's appearance. // It will show up as "link" versus "<link>" if it's resolved or not, and "a at b" versus "a" depending on if it resolves to // the topic "a at b" or the topic "b". // Why don't we do this for type links? Because unlike Natural Docs links, type links don't change in appearance // based on whether they're resolved or not. Therefore the logic that we don't have to worry about it because links // don't appear in tooltips holds true. if (link.Type == LinkType.NaturalDocs) { IDObjects.NumberSet fileIDs, classIDs; eventAccessor.GetInfoOnLinksToTopicsWithNDLinkInSummary(link, out fileIDs, out classIDs); if (fileIDs != null || classIDs != null) { lock (accessLock) { if (fileIDs != null) { buildState.SourceFilesToRebuild.Add(fileIDs); } if (classIDs != null) { buildState.ClassFilesToRebuild.Add(classIDs); } } } } }
public void OnDeleteImageLink(ImageLink imageLink, CodeDB.EventAccessor eventAccessor) { unprocessedChanges.DeleteImageLink(imageLink); }
public void OnUpdateTopic(Topic oldTopic, Topic newTopic, Topic.ChangeFlags changeFlags, CodeDB.EventAccessor eventAccessor) { // We don't care about line number changes. They don't affect the output. We also don't care about context // changes. They might affect links but if they do it will be handled in OnChangeLinkTarget(). changeFlags &= ~(Topic.ChangeFlags.CommentLineNumber | Topic.ChangeFlags.CodeLineNumber | Topic.ChangeFlags.PrototypeContext | Topic.ChangeFlags.BodyContext); if (changeFlags == 0) { return; } lock (accessLock) { buildState.SourceFilesToRebuild.Add(oldTopic.FileID); #if DEBUG if (newTopic.FileID != oldTopic.FileID) { throw new Exception("Called OnUpdateTopic() with topics that had different file IDs"); } #endif if (oldTopic.ClassID != 0) { buildState.ClassFilesToRebuild.Add(oldTopic.ClassID); } if (newTopic.ClassID != 0) { buildState.ClassFilesToRebuild.Add(newTopic.ClassID); } } // If the summary or prototype changed this means its tooltip changed. Rebuild any file that contains links // to this topic. if ((changeFlags & (Topic.ChangeFlags.Prototype | Topic.ChangeFlags.Summary | Topic.ChangeFlags.LanguageID | Topic.ChangeFlags.CommentTypeID)) != 0) { IDObjects.NumberSet linkFileIDs, linkClassIDs; eventAccessor.GetInfoOnLinksThatResolveToTopicID(oldTopic.TopicID, out linkFileIDs, out linkClassIDs); IDObjects.NumberSet oldParentClassIDs = null; IDObjects.NumberSet oldParentClassFileIDs = null; IDObjects.NumberSet newParentClassIDs = null; IDObjects.NumberSet newParentClassFileIDs = null; if (oldTopic.DefinesClass) { eventAccessor.GetInfoOnClassParents(oldTopic.ClassID, out oldParentClassIDs, out oldParentClassFileIDs); } if (newTopic.DefinesClass && (newTopic.ClassID != oldTopic.ClassID || oldTopic.DefinesClass == false)) { eventAccessor.GetInfoOnClassParents(newTopic.ClassID, out newParentClassIDs, out newParentClassFileIDs); } if (linkFileIDs != null || linkClassIDs != null || oldParentClassIDs != null || oldParentClassFileIDs != null || newParentClassIDs != null || newParentClassFileIDs != null) { lock (accessLock) { if (linkFileIDs != null) { buildState.SourceFilesToRebuild.Add(linkFileIDs); } if (linkClassIDs != null) { buildState.ClassFilesToRebuild.Add(linkClassIDs); } if (oldParentClassIDs != null) { buildState.ClassFilesToRebuild.Add(oldParentClassIDs); } if (oldParentClassFileIDs != null) { buildState.SourceFilesToRebuild.Add(oldParentClassFileIDs); } if (newParentClassIDs != null) { buildState.ClassFilesToRebuild.Add(newParentClassIDs); } if (newParentClassFileIDs != null) { buildState.SourceFilesToRebuild.Add(newParentClassFileIDs); } } } } }
public void OnUpdateTopic(Topic oldTopic, Topic newTopic, Topic.ChangeFlags changeFlags, CodeDB.EventAccessor eventAccessor) { #if DEBUG if (IncludeInIndex(newTopic) != IncludeInIndex(oldTopic)) { throw new Exception("SearchIndex incorrectly assumes IncludeInIndex() will be the same for both the old and new topics in OnUpdateTopic()."); } #endif if (!IncludeInIndex(newTopic)) { return; } if ((changeFlags & (Topic.ChangeFlags.Title | Topic.ChangeFlags.CommentTypeID | Topic.ChangeFlags.SymbolDefinitonNumber | Topic.ChangeFlags.Symbol | Topic.ChangeFlags.LanguageID | Topic.ChangeFlags.FileID | Topic.ChangeFlags.EffectiveAccessLevel | Topic.ChangeFlags.Class)) == 0) { return; } // We assume that if the topics are similar enough to use OnUpdateTopic() instead of OnAdd/RemoveTopic() then they'll generate the exact // same keyword list, and they'll even be in the same order. This allows for a nice optimization here, but test it in debug builds in case these // assumptions are wrong in the future. #if DEBUG if (newTopic.TopicID != oldTopic.TopicID) { throw new Exception("SearchIndex incorrectly assumes both the old and new topics in OnUpdateTopic() have the same topic IDs."); } TopicEntry newEntry = new TopicEntry(newTopic, this); TopicEntry oldEntry = new TopicEntry(oldTopic, this); if (newEntry.Keywords.Count != oldEntry.Keywords.Count) { throw new Exception("SearchIndex incorrectly assumes both the old and new topics in OnUpdateTopic() have the same keywords."); } for (int i = 0; i < newEntry.Keywords.Count; i++) { if (newEntry.Keywords[i] != oldEntry.Keywords[i]) { throw new Exception("SearchIndex incorrectly assumes both the old and new topics in OnUpdateTopic() have the same keywords."); } } #endif TopicEntry entry = new TopicEntry(newTopic, this); // We use upgradeable in case one of the change handlers needs to do something that requires a write lock. accessLock.EnterUpgradeableReadLock(); try { foreach (var keyword in entry.Keywords) { string prefix = KeywordPrefix(keyword); foreach (var changeWatcher in changeWatchers) { changeWatcher.OnUpdatePrefix(prefix, eventAccessor); } } } finally { // We don't have to test to see if it was upgraded because if it was the write lock should have been released // by the change handler and we should recursively be back to an upgradeable read lock. accessLock.ExitUpgradeableReadLock(); } }
public void OnDeletePrefix(string prefix, CodeDB.EventAccessor accessor) { unprocessedChanges.AddMainSearchFiles(); unprocessedChanges.AddSearchPrefix(prefix); }
public void OnChangeLinkTarget(Link link, int oldTargetTopicID, int oldTargetClassID, CodeDB.EventAccessor eventAccessor) { // We don't care about links. }
public void OnUpdatePrefix(string prefix, CodeDB.EventAccessor accessor) { unprocessedChanges.AddSearchPrefix(prefix); }
public void OnChangeImageLinkTarget(ImageLink imageLink, int oldTargetFileID, CodeDB.EventAccessor eventAccessor) { // We're going to be the one causing this event, not responding to it. No other code should be changing link definitions. }
public void OnChangeImageLinkTarget(ImageLink imageLink, int oldTargetFileID, CodeDB.EventAccessor eventAccessor) { // xxx placeholder }
public void OnDeleteLink(Link link, CodeDB.EventAccessor eventAccessor) { // We don't care about links. }
public void OnChangeImageLinkTarget(ImageLink imageLink, int oldTargetFileID, CodeDB.EventAccessor eventAccessor) { // We don't care about image links. }
public void OnDeleteImageLink(ImageLink imageLink, CodeDB.EventAccessor eventAccessor) { // We don't care about image links. }
public void OnDeleteImageLink(ImageLink imageLink, CodeDB.EventAccessor eventAccessor) { // xxx placeholder }
public void OnChangeImageLinkTarget(ImageLink imageLink, int oldTargetFileID, CodeDB.EventAccessor eventAccessor) { // Here we have to rebuild the HTML containing the link because this could happen without the containing // topic changing, such as if an image file was deleted or a new one served as a better target. unprocessedChanges.AddSourceFile(imageLink.FileID); unprocessedChanges.AddClass(imageLink.ClassID); // We also have to check both image files because they could have changed between used and unused. if (imageLink.TargetFileID != 0) { unprocessedChanges.AddImageFileUseCheck(imageLink.TargetFileID); } if (oldTargetFileID != 0) { unprocessedChanges.AddImageFileUseCheck(oldTargetFileID); } // We also have to see if it appears in the summary for any topics. This would mean that it appears in these topics' // tooltips, so we have to find any links to these topics and rebuild the files those links appear in. // Why do we have to do this if links aren't added to tooltips? Because how it's resolved can affect it's appearance. // It will show up as "(see diagram)" versus "(see images/diagram.jpg)" if it's resolved or not. IDObjects.NumberSet fileIDs, classIDs; eventAccessor.GetInfoOnLinksToTopicsWithImageLinkInSummary(imageLink, out fileIDs, out classIDs); if (fileIDs != null) { unprocessedChanges.AddSourceFiles(fileIDs); } if (classIDs != null) { unprocessedChanges.AddClasses(classIDs); } }