コード例 #1
0
ファイル: HTMLTopic.cs プロジェクト: pks-os/NaturalDocs
        /* Function: BuildBody
         */
        protected void BuildBody()
        {
            htmlOutput.Append("<div class=\"CBody\">");

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(topic.Body);

            bool   underParameterHeading = false;
            string parameterListSymbol   = null;

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:
                    if (topic.Body.IndexOf("  ", iterator.RawTextIndex, iterator.Length) == -1)
                    {
                        iterator.AppendTo(htmlOutput);
                    }
                    else
                    {
                        htmlOutput.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    break;

                case NDMarkup.Iterator.ElementType.ParagraphTag:
                case NDMarkup.Iterator.ElementType.BulletListTag:
                case NDMarkup.Iterator.ElementType.BulletListItemTag:
                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:
                    iterator.AppendTo(htmlOutput);
                    break;

                case NDMarkup.Iterator.ElementType.HeadingTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<div class=\"CHeading\">");
                        underParameterHeading = (iterator.Property("type") == "parameters");
                    }
                    else
                    {
                        htmlOutput.Append("</div>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.PreTag:

                    string preType         = iterator.Property("type");
                    string preLanguageName = iterator.Property("language");

                    iterator.Next();
                    NDMarkup.Iterator startOfCode = iterator;

                    // Because we can assume the NDMarkup is valid, we can assume we were on an opening tag and that we will
                    // run into a closing tag before the end of the text.  We can also assume the next pre tag is a closing tag.

                    while (iterator.Type != NDMarkup.Iterator.ElementType.PreTag)
                    {
                        iterator.Next();
                    }

                    string ndMarkupCode = topic.Body.Substring(startOfCode.RawTextIndex, iterator.RawTextIndex - startOfCode.RawTextIndex);
                    string textCode     = NDMarkupCodeToText(ndMarkupCode);

                    htmlOutput.Append("<pre>");

                    if (preType == "code")
                    {
                        Languages.Language preLanguage = null;

                        if (preLanguageName != null)
                        {
                            // This can return null if the language name is unrecognized.
                            preLanguage = EngineInstance.Languages.FromName(preLanguageName);
                        }

                        if (preLanguage == null)
                        {
                            preLanguage = EngineInstance.Languages.FromID(topic.LanguageID);
                        }

                        Tokenizer code = new Tokenizer(textCode, tabWidth: EngineInstance.Config.TabWidth);
                        preLanguage.SyntaxHighlight(code);
                        BuildSyntaxHighlightedText(code.FirstToken, code.LastToken);
                    }
                    else
                    {
                        string htmlCode = textCode.EntityEncode();
                        htmlCode = StringExtensions.LineBreakRegex.Replace(htmlCode, "<br />");
                        htmlOutput.Append(htmlCode);
                    }

                    htmlOutput.Append("</pre>");
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<table class=\"CDefinitionList\">");
                    }
                    else
                    {
                        htmlOutput.Append("</table>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListEntryTag:
                case NDMarkup.Iterator.ElementType.DefinitionListSymbolTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<tr><td class=\"CDLEntry\">");
                        parameterListSymbol = null;

                        // Create anchors for symbols.  We are assuming there are enough embedded topics for each <ds>
                        // tag and that they follow their parent topic in order.
                        if (iterator.Type == NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                        {
                                                                #if DEBUG
                            if (embeddedTopics == null || embeddedTopicIndex >= embeddedTopics.Count ||
                                embeddedTopics[embeddedTopicIndex].IsEmbedded == false)
                            {
                                throw new Exception("There are not enough embedded topics to build the definition list.");
                            }
                                                                #endif

                            string topicHashPath = HTMLBuilder.Source_TopicHashPath(embeddedTopics[embeddedTopicIndex], topicPage.IncludeClassInTopicHashPaths);

                            if (topicHashPath != null)
                            {
                                htmlOutput.Append("<a name=\"" + topicHashPath.EntityEncode() + "\"></a>");
                            }

                            htmlOutput.Append("<a name=\"Topic" + embeddedTopics[embeddedTopicIndex].TopicID + "\"></a>");

                            embeddedTopicIndex++;
                        }

                        // If we're using a Parameters: heading, store the entry symbol in parameterListSymbol
                        if (underParameterHeading)
                        {
                            NDMarkup.Iterator temp = iterator;
                            temp.Next();

                            StringBuilder symbol = new StringBuilder();

                            while (temp.IsInBounds &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListEntryTag &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                            {
                                if (temp.Type == NDMarkup.Iterator.ElementType.Text)
                                {
                                    temp.AppendTo(symbol);
                                }

                                temp.Next();
                            }

                            // If the entry name starts with any combination of $, @, or % characters, strip them off.
                            int firstNonSymbolIndex = 0;
                            while (firstNonSymbolIndex < symbol.Length)
                            {
                                char charAtIndex = symbol[firstNonSymbolIndex];

                                if (charAtIndex != '$' && charAtIndex != '@' && charAtIndex != '%')
                                {
                                    break;
                                }

                                firstNonSymbolIndex++;
                            }

                            if (firstNonSymbolIndex > 0)
                            {
                                symbol.Remove(0, firstNonSymbolIndex);
                            }

                            if (symbol.Length > 0)
                            {
                                parameterListSymbol = symbol.ToString();
                            }
                        }
                    }
                    else                             // closing tag
                    {
                        // See if parameterListSymbol matches any of the prototype parameter names
                        if (parameterListSymbol != null && topic.Prototype != null)
                        {
                            TokenIterator start, end;
                            int           matchedParameter = -1;

                            for (int i = 0; i < topic.ParsedPrototype.NumberOfParameters; i++)
                            {
                                topic.ParsedPrototype.GetParameterName(i, out start, out end);

                                if (topic.ParsedPrototype.Tokenizer.EqualsTextBetween(parameterListSymbol, true, start, end))
                                {
                                    matchedParameter = i;
                                    break;
                                }
                            }

                            // If so, include the type under the entry in the HTML
                            if (matchedParameter != -1)
                            {
                                TokenIterator extraModifierStart, extraModifierEnd, prefixStart, prefixEnd, suffixStart, suffixEnd;
                                topic.ParsedPrototype.GetFullParameterType(matchedParameter, out start, out end,
                                                                           out extraModifierStart, out extraModifierEnd,
                                                                           out prefixStart, out prefixEnd,
                                                                           out suffixStart, out suffixEnd);

                                if (start < end &&
                                    // Don't include single symbol types
                                    (end.RawTextIndex - start.RawTextIndex > 1 ||
                                     (start.Character != '$' && start.Character != '@' && start.Character != '%')))
                                {
                                    htmlOutput.Append("<div class=\"CDLParameterType\">");

                                    if (extraModifierStart < extraModifierEnd)
                                    {
                                        BuildTypeLinkedAndSyntaxHighlightedText(extraModifierStart, extraModifierEnd);
                                        htmlOutput.Append(' ');
                                    }

                                    BuildTypeLinkedAndSyntaxHighlightedText(start, end);
                                    BuildTypeLinkedAndSyntaxHighlightedText(prefixStart, prefixEnd);
                                    BuildTypeLinkedAndSyntaxHighlightedText(suffixStart, suffixEnd);

                                    htmlOutput.Append("</div>");
                                }
                            }
                        }

                        htmlOutput.Append("</td>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.DefinitionListDefinitionTag:
                    if (iterator.IsOpeningTag)
                    {
                        htmlOutput.Append("<td class=\"CDLDefinition\">");
                    }
                    else
                    {
                        htmlOutput.Append("</td></tr>");
                    }
                    break;

                case NDMarkup.Iterator.ElementType.LinkTag:
                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        BuildEMailLink(iterator);
                    }
                    else if (linkType == "url")
                    {
                        BuildURLLink(iterator);
                    }
                    else                             // type == "naturaldocs"
                    {
                        BuildNaturalDocsLink(iterator);
                    }

                    break;

                case NDMarkup.Iterator.ElementType.ImageTag:                         // xxx
                    if (iterator.Property("type") == "standalone")
                    {
                        htmlOutput.Append("<p>");
                    }

                    htmlOutput.Append(iterator.Property("originaltext").ToHTML());

                    if (iterator.Property("type") == "standalone")
                    {
                        htmlOutput.Append("</p>");
                    }
                    break;
                }

                iterator.Next();
            }

            htmlOutput.Append("</div>");
        }
コード例 #2
0
        /* Function: AppendBody
         */
        protected void AppendBody(StringBuilder output)
        {
            output.Append("<div class=\"CBody\">");

            string body = context.Topic.Body;

            NDMarkup.Iterator iterator = new NDMarkup.Iterator(body);

            bool   underParameterHeading  = false;
            string parameterListSymbol    = null;
            string altParameterListSymbol = null;

            StringBuilder inlineImageContent = null;
            int           imageNumber        = 1;

            while (iterator.IsInBounds)
            {
                switch (iterator.Type)
                {
                case NDMarkup.Iterator.ElementType.Text:

                    // Preserve multiple whitespace chars, but skip the extra processing if there aren't any
                    if (body.IndexOf("  ", iterator.RawTextIndex, iterator.Length) != -1)
                    {
                        output.Append(iterator.String.ConvertMultipleWhitespaceChars());
                    }
                    else
                    {
                        iterator.AppendTo(output);
                    }
                    break;


                case NDMarkup.Iterator.ElementType.ParagraphTag:

                    iterator.AppendTo(output);

                    if (iterator.IsClosingTag && inlineImageContent != null && inlineImageContent.Length > 0)
                    {
                        output.Append(inlineImageContent.ToString());
                        inlineImageContent.Remove(0, inlineImageContent.Length);
                    }

                    break;


                case NDMarkup.Iterator.ElementType.BulletListTag:
                case NDMarkup.Iterator.ElementType.BulletListItemTag:
                case NDMarkup.Iterator.ElementType.BoldTag:
                case NDMarkup.Iterator.ElementType.ItalicsTag:
                case NDMarkup.Iterator.ElementType.UnderlineTag:
                case NDMarkup.Iterator.ElementType.LTEntityChar:
                case NDMarkup.Iterator.ElementType.GTEntityChar:
                case NDMarkup.Iterator.ElementType.AmpEntityChar:
                case NDMarkup.Iterator.ElementType.QuoteEntityChar:

                    // These the NDMarkup directly matches the HTML tags
                    iterator.AppendTo(output);
                    break;


                case NDMarkup.Iterator.ElementType.HeadingTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<div class=\"CHeading\">");
                        underParameterHeading = (iterator.Property("type") == "parameters");
                    }
                    else
                    {
                        output.Append("</div>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.PreTag:

                    string preType         = iterator.Property("type");
                    string preLanguageName = iterator.Property("language");

                    iterator.Next();
                    NDMarkup.Iterator startOfCode = iterator;

                    // Because we can assume the NDMarkup is valid, we can assume we were on an opening tag and that we will
                    // run into a closing tag before the end of the text.  We can also assume the next pre tag is a closing tag.

                    while (iterator.Type != NDMarkup.Iterator.ElementType.PreTag)
                    {
                        iterator.Next();
                    }

                    string ndMarkupCode = body.Substring(startOfCode.RawTextIndex, iterator.RawTextIndex - startOfCode.RawTextIndex);
                    string textCode     = NDMarkupCodeToText(ndMarkupCode);

                    output.Append("<pre>");

                    if (preType == "code")
                    {
                        Languages.Language preLanguage = null;

                        if (preLanguageName != null)
                        {
                            // This can return null if the language name is unrecognized.
                            preLanguage = EngineInstance.Languages.FromName(preLanguageName);
                        }

                        if (preLanguage == null)
                        {
                            preLanguage = EngineInstance.Languages.FromID(context.Topic.LanguageID);
                        }

                        Tokenizer code = new Tokenizer(textCode, tabWidth: EngineInstance.Config.TabWidth);
                        preLanguage.SyntaxHighlight(code);
                        AppendSyntaxHighlightedText(code.FirstToken, code.LastToken, output);
                    }
                    else
                    {
                        string htmlCode = textCode.EntityEncode();
                        htmlCode = StringExtensions.LineBreakRegex.Replace(htmlCode, "<br />");
                        output.Append(htmlCode);
                    }

                    output.Append("</pre>");
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<table class=\"CDefinitionList\">");
                    }
                    else
                    {
                        output.Append("</table>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListEntryTag:
                case NDMarkup.Iterator.ElementType.DefinitionListSymbolTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<tr><td class=\"CDLEntry\">");
                        parameterListSymbol = null;

                        // Create anchors for symbols.  We are assuming there are enough embedded topics for each <ds>
                        // tag and that they follow their parent topic in order.
                        if (iterator.Type == NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                        {
                                                                #if DEBUG
                            if (embeddedTopics == null || embeddedTopicIndex >= embeddedTopics.Count ||
                                embeddedTopics[embeddedTopicIndex].IsEmbedded == false)
                            {
                                throw new Exception("There are not enough embedded topics to build the definition list.");
                            }
                                                                #endif

                            var embeddedTopic = embeddedTopics[embeddedTopicIndex];

                            Context embeddedTopicContext = context;
                            embeddedTopicContext.Topic = embeddedTopic;

                            string embeddedTopicHashPath = embeddedTopicContext.TopicOnlyHashPath;

                            if (embeddedTopicHashPath != null)
                            {
                                output.Append("<a name=\"" + embeddedTopicHashPath.EntityEncode() + "\"></a>");
                            }

                            output.Append("<a name=\"Topic" + embeddedTopic.TopicID + "\"></a>");

                            embeddedTopicIndex++;
                        }

                        // If we're using a Parameters: heading, store the entry symbol in parameterListSymbol
                        if (underParameterHeading)
                        {
                            NDMarkup.Iterator temp = iterator;
                            temp.Next();

                            StringBuilder symbol = new StringBuilder();

                            while (temp.IsInBounds &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListEntryTag &&
                                   temp.Type != NDMarkup.Iterator.ElementType.DefinitionListSymbolTag)
                            {
                                if (temp.Type == NDMarkup.Iterator.ElementType.Text)
                                {
                                    temp.AppendTo(symbol);
                                }

                                temp.Next();
                            }

                            // If the entry name starts with any combination of $, @, or % characters, strip them off.
                            int firstNonSymbolIndex = 0;
                            while (firstNonSymbolIndex < symbol.Length)
                            {
                                char charAtIndex = symbol[firstNonSymbolIndex];

                                if (charAtIndex != '$' && charAtIndex != '@' && charAtIndex != '%')
                                {
                                    break;
                                }

                                firstNonSymbolIndex++;
                            }

                            if (symbol.Length > 0)
                            {
                                parameterListSymbol = symbol.ToString();
                            }
                            else
                            {
                                parameterListSymbol = null;
                            }

                            if (firstNonSymbolIndex > 0)
                            {
                                symbol.Remove(0, firstNonSymbolIndex);
                                altParameterListSymbol = symbol.ToString();
                            }
                            else
                            {
                                altParameterListSymbol = null;
                            }
                        }
                    }
                    else                             // closing tag
                    {
                        // See if parameterListSymbol matches any of the prototype parameter names
                        if ((parameterListSymbol != null || altParameterListSymbol != null) && context.Topic.Prototype != null)
                        {
                            var           parsedPrototype = context.Topic.ParsedPrototype;
                            TokenIterator start, end;
                            int           matchedParameter = -1;

                            for (int i = 0; i < parsedPrototype.NumberOfParameters; i++)
                            {
                                parsedPrototype.GetParameterName(i, out start, out end);

                                if ((parameterListSymbol != null && parsedPrototype.Tokenizer.EqualsTextBetween(parameterListSymbol, true, start, end)) ||
                                    (altParameterListSymbol != null && parsedPrototype.Tokenizer.EqualsTextBetween(altParameterListSymbol, true, start, end)))
                                {
                                    matchedParameter = i;
                                    break;
                                }
                            }

                            // If so, include the type under the entry in the HTML
                            if (matchedParameter != -1)
                            {
                                parsedPrototype.BuildFullParameterType(matchedParameter, out start, out end);

                                if (start < end &&
                                    // Don't include single symbol types
                                    !(end.RawTextIndex - start.RawTextIndex == 1 &&
                                      (start.Character == '$' || start.Character == '@' || start.Character == '%')))
                                {
                                    output.Append("<div class=\"CDLParameterType\">");
                                    AppendSyntaxHighlightedTextWithTypeLinks(start, end, output, links, linkTargets);
                                    output.Append("</div>");
                                }
                            }
                        }

                        output.Append("</td>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.DefinitionListDefinitionTag:

                    if (iterator.IsOpeningTag)
                    {
                        output.Append("<td class=\"CDLDefinition\">");
                    }
                    else
                    {
                        output.Append("</td></tr>");
                    }
                    break;


                case NDMarkup.Iterator.ElementType.LinkTag:

                    string linkType = iterator.Property("type");

                    if (linkType == "email")
                    {
                        AppendEMailLink(iterator, output);
                    }
                    else if (linkType == "url")
                    {
                        AppendURLLink(iterator, output);
                    }
                    else                             // type == "naturaldocs"
                    {
                        AppendNaturalDocsLink(iterator, output);
                    }

                    break;


                case NDMarkup.Iterator.ElementType.ImageTag:

                    if (iterator.Property("type") == "standalone")
                    {
                        AppendStandaloneImageLink(iterator, output);
                    }

                    else if (iterator.Property("type") == "inline")
                    {
                        if (inlineImageContent == null)
                        {
                            inlineImageContent = new StringBuilder();
                        }

                        AppendInlineImageLink(iterator, output, inlineImageContent, imageNumber);

                        imageNumber++;
                    }

                    else
                    {
                        throw new NotImplementedException();
                    }

                    break;
                }

                iterator.Next();
            }

            output.Append("</div>");
        }