Przeglądaj źródła

ENH: Make hyperlinks in documentation active when generated into HTML documents. This addresses bug#3906.

Brad King 19 lat temu
rodzic
commit
49bf0b9e3d
1 zmienionych plików z 74 dodań i 9 usunięć
  1. 74 9
      Source/cmDocumentation.cxx

+ 74 - 9
Source/cmDocumentation.cxx

@@ -969,8 +969,20 @@ void cmDocumentation::PrintColumn(std::ostream& os, const char* text)
 }
 
 //----------------------------------------------------------------------------
-void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
+static bool cmDocumentationIsHyperlinkChar(char c)
+{
+  // This is not a complete list but works for CMake documentation.
+  return ((c >= 'A' && c <= 'Z') ||
+          (c >= 'a' && c <= 'z') ||
+          (c >= '0' && c <= '9') ||
+          c == '-' || c == '.' || c == '/' || c == '~' || c == '@' ||
+          c == ':' || c == '_' || c == '&' || c == '?' || c == '=');
+}
+
+//----------------------------------------------------------------------------
+static void cmDocumentationPrintHTMLChar(std::ostream& os, char c)
 {
+  // Use an escape sequence if necessary.
   static cmDocumentationEntry escapes[] =
   {
     {"<", "&lt;", 0},
@@ -979,20 +991,73 @@ void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
     {"\n", "<br>", 0},
     {0,0,0}
   };
-  for(const char* p = text; *p; ++p)
+  for(const cmDocumentationEntry* op = escapes; op->name; ++op)
+    {
+    if(op->name[0] == c)
+      {
+      os << op->brief;
+      return;
+      }
+    }
+
+  // No escape sequence is needed.
+  os << c;
+}
+
+//----------------------------------------------------------------------------
+const char* cmDocumentationPrintHTMLLink(std::ostream& os, const char* begin)
+{
+  // Look for the end of the link.
+  const char* end = begin;
+  while(cmDocumentationIsHyperlinkChar(*end))
+    {
+    ++end;
+    }
+
+  // Print the hyperlink itself.
+  os << "<a href=\"";
+  for(const char* c = begin; c != end; ++c)
+    {
+    cmDocumentationPrintHTMLChar(os, *c);
+    }
+  os << "\">";
+
+  // The name of the hyperlink is the text itself.
+  for(const char* c = begin; c != end; ++c)
     {
-    bool found = false;
-    for(const cmDocumentationEntry* op = escapes; !found && op->name; ++op)
+    cmDocumentationPrintHTMLChar(os, *c);
+    }
+  os << "</a>";
+
+  // Return the position at which to continue scanning the input
+  // string.
+  return end;
+}
+
+//----------------------------------------------------------------------------
+void cmDocumentation::PrintHTMLEscapes(std::ostream& os, const char* text)
+{
+  // Hyperlink prefixes.
+  static const char* hyperlinks[] = {"http://", "ftp://", "mailto:", 0};
+
+  // Print each character.
+  for(const char* p = text; *p;)
+    {
+    // Handle hyperlinks specially to make them active.
+    bool found_hyperlink = false;
+    for(const char** h = hyperlinks; !found_hyperlink && *h; ++h)
       {
-      if(op->name[0] == *p)
+      if(strncmp(p, *h, strlen(*h)) == 0)
         {
-        os << op->brief;
-        found = true;
+        p = cmDocumentationPrintHTMLLink(os, p);
+        found_hyperlink = true;
         }
       }
-    if(!found)
+
+    // Print other characters normally.
+    if(!found_hyperlink)
       {
-      os << *p;
+      cmDocumentationPrintHTMLChar(os, *p++);
       }
     }
 }