Example #1
0
        /* Function: RemoveDuplicateTopics
         * Removes topics from the results which have the same letter for letter display names.  An exception is made if
         * they have different languages.
         */
        protected void RemoveDuplicateTopics(SearchIndex.Entries.Keyword keywordEntry)
        {
            List <SearchIndex.Entries.Topic> topicEntries = keywordEntry.TopicEntries;

            for (int i = 1; i < topicEntries.Count; /* no auto-increment */)
            {
                var current  = topicEntries[i];
                var previous = topicEntries[i - 1];

                if (current.DisplayName == previous.DisplayName &&
                    current.WrappedTopic.LanguageID == previous.WrappedTopic.LanguageID)
                {
                    topicEntries.RemoveAt(i);
                }
                else
                {
                    i++;
                }
            }
        }
Example #2
0
        /* Function: AppendKeyword
         * Appends the keyword entry as a JSON array.
         */
        protected void AppendKeyword(SearchIndex.Entries.Keyword keywordEntry, StringBuilder output)
        {
            bool addWhitespace = !EngineInstance.Config.ShrinkFiles;

            if (addWhitespace)
            {
                output.Append("\n\n   ");
            }

            string keywordHTMLName   = keywordEntry.DisplayName.ToHTML();
            string keywordSearchText = keywordEntry.SearchText;

            output.Append("[\"");
            output.StringEscapeAndAppend(keywordHTMLName);
            output.Append("\",");

            if (keywordSearchText != keywordHTMLName.ToLower())
            {
                output.Append('"');
                output.StringEscapeAndAppend(keywordSearchText);
                output.Append('"');
            }
            // Otherwise leave an empty spot before the comma.  We don't have to write out "undefined".

            output.Append(",[");

            for (int i = 0; i < keywordEntry.TopicEntries.Count; i++)
            {
                if (i > 0)
                {
                    output.Append(',');
                }

                if (addWhitespace)
                {
                    output.Append("\n      ");
                }

                var  topicEntry      = keywordEntry.TopicEntries[i];
                bool includeLanguage = false;

                if (i < keywordEntry.TopicEntries.Count - 1)
                {
                    var other = keywordEntry.TopicEntries[i + 1];

                    if (topicEntry.DisplayName == other.DisplayName &&
                        topicEntry.WrappedTopic.LanguageID != other.WrappedTopic.LanguageID)
                    {
                        includeLanguage = true;
                    }
                }

                if (i > 0 && !includeLanguage)
                {
                    var other = keywordEntry.TopicEntries[i - 1];

                    if (topicEntry.DisplayName == other.DisplayName &&
                        topicEntry.WrappedTopic.LanguageID != other.WrappedTopic.LanguageID)
                    {
                        includeLanguage = true;
                    }
                }

                AppendTopic(topicEntry, keywordHTMLName, includeLanguage, output);
            }

            if (addWhitespace)
            {
                output.Append("\n   ");
            }

            output.Append("]]");
        }
Example #3
0
        /* Function: SortTopicEntries
         */
        protected void SortTopicEntries(SearchIndex.Entries.Keyword keywordEntry)
        {
            List <SearchIndex.Entries.Topic> topicEntries = keywordEntry.TopicEntries;

            topicEntries.Sort(
                delegate(SearchIndex.Entries.Topic a, SearchIndex.Entries.Topic b)
            {
                // Sort by the non-qualifier part first since they'll be displayed in "Name, Class" format.  The below code is just
                // an elaborate way of doing that without allocating intermediate strings for each comparison.

                int aNonQualifierLength       = a.DisplayName.Length - a.EndOfDisplayNameQualifiers;
                int bNonQualifierLength       = b.DisplayName.Length - b.EndOfDisplayNameQualifiers;
                int shorterNonQualifierLength = (aNonQualifierLength < bNonQualifierLength ?
                                                 aNonQualifierLength : bNonQualifierLength);


                // Compare non-qualifiers in a case-insensitive way first.

                int result = string.Compare(a.DisplayName, a.EndOfDisplayNameQualifiers,
                                            b.DisplayName, b.EndOfDisplayNameQualifiers, shorterNonQualifierLength, true);

                if (result != 0)
                {
                    return(result);
                }

                result = (aNonQualifierLength - bNonQualifierLength);

                if (result != 0)
                {
                    return(result);
                }


                // Before comparing in a case-sensitive way, compare based on hierarchy membership.  We want class "Token"
                // to appear before variable "token" even though normally we want lowercase to go first.

                var aCommentType = EngineInstance.CommentTypes.FromID(a.WrappedTopic.CommentTypeID);
                var bCommentType = EngineInstance.CommentTypes.FromID(b.WrappedTopic.CommentTypeID);

                if (aCommentType.InClassHierarchy != bCommentType.InClassHierarchy)
                {
                    return(aCommentType.InClassHierarchy ? -1 : 1);
                }

                if (aCommentType.InDatabaseHierarchy != bCommentType.InDatabaseHierarchy)
                {
                    return(aCommentType.InDatabaseHierarchy ? -1 : 1);
                }


                // Still equal, now compare the qualifiers in a case-sensitive way to break ties.

                result = string.Compare(a.DisplayName, a.EndOfDisplayNameQualifiers,
                                        b.DisplayName, b.EndOfDisplayNameQualifiers, shorterNonQualifierLength, false);

                if (result != 0)
                {
                    return(result);
                }

                int shorterQualifierLength = (a.EndOfDisplayNameQualifiers < b.EndOfDisplayNameQualifiers ?
                                              a.EndOfDisplayNameQualifiers : b.EndOfDisplayNameQualifiers);


                // Still equal so do a case-insensitive comparison of qualifiers, so "Name, ClassA" comes before "Name, ClassB".

                result = string.Compare(a.DisplayName, 0, b.DisplayName, 0, shorterQualifierLength, true);

                if (result != 0)
                {
                    return(result);
                }

                result = (a.EndOfDisplayNameQualifiers - b.EndOfDisplayNameQualifiers);

                if (result != 0)
                {
                    return(result);
                }


                // Case-sensitive comparison of qualifiers to break ties.

                result = string.Compare(a.DisplayName, 0, b.DisplayName, 0, shorterQualifierLength, false);

                if (result != 0)
                {
                    return(result);
                }


                // So now we have two symbols that are equal letter for letter.  Sort by language name first.

                if (a.WrappedTopic.LanguageID != b.WrappedTopic.LanguageID)
                {
                    return(string.Compare(EngineInstance.Languages.FromID(a.WrappedTopic.LanguageID).Name,
                                          EngineInstance.Languages.FromID(b.WrappedTopic.LanguageID).Name, true));
                }


                // and by file name next.

                if (a.WrappedTopic.FileID != b.WrappedTopic.FileID)
                {
                    return(string.Compare(EngineInstance.Files.FromID(a.WrappedTopic.FileID).FileName,
                                          EngineInstance.Files.FromID(b.WrappedTopic.FileID).FileName, true));
                }


                // If we're here then they're two overloaded functions in the same source file.  Go by symbol definition number.

                return(a.WrappedTopic.SymbolDefinitionNumber - b.WrappedTopic.SymbolDefinitionNumber);
            }
                );


            // We're not done yet.  Now reorder the sorted list so that topics that begin with the keyword appear before those that
            // don't, even if they're otherwise ahead of it in the sort order.  Right now we have this:
            //
            // Thread
            // - Not Thread Safe
            // - thread
            // - Thread
            // - Thread Safe
            // - Thread Safety Notes
            // - Window Threads
            //
            // but most of the time someone typing in "thread" will want the Thread class, so convert it into this:
            //
            // Thread
            // - thread
            // - Thread
            // - Thread Safe
            // - Thread Safety Notes
            // - Not Thread Safe
            // - Window Threads

            int firstKeywordStart = -1;

            for (int i = 0; i < topicEntries.Count; i++)
            {
                int keywordIndex = topicEntries[i].SearchText.IndexOf(keywordEntry.SearchText,
                                                                      topicEntries[i].EndOfSearchTextQualifiers);

                if (keywordIndex == topicEntries[i].EndOfSearchTextQualifiers)
                {
                    firstKeywordStart = i;
                    break;
                }
            }

            // If the first one already starts with the keyword, or none of them do, there's nothing we need to do.
            if (firstKeywordStart > 0)
            {
                int endOfKeywordStart = topicEntries.Count;

                for (int i = topicEntries.Count - 1; i >= 0; i--)
                {
                    int keywordIndex = topicEntries[i].SearchText.IndexOf(keywordEntry.SearchText,
                                                                          topicEntries[i].EndOfSearchTextQualifiers);

                    if (keywordIndex == topicEntries[i].EndOfSearchTextQualifiers)
                    {
                        break;
                    }
                    else
                    {
                        endOfKeywordStart = i;
                    }
                }

                var tempList = topicEntries.GetRange(0, firstKeywordStart);
                topicEntries.RemoveRange(0, firstKeywordStart);

                // end - first because it shifted down after we removed the range
                topicEntries.InsertRange(endOfKeywordStart - firstKeywordStart, tempList);
            }
        }