r321320 - [analyzer] Add Javascript to analyzer HTML output to allow keyboard navigation.

George Karpenkov via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 21 14:57:51 PST 2017


Author: george.karpenkov
Date: Thu Dec 21 14:57:51 2017
New Revision: 321320

URL: http://llvm.org/viewvc/llvm-project?rev=321320&view=rev
Log:
[analyzer] Add Javascript to analyzer HTML output to allow keyboard navigation.

Differential Revision: https://reviews.llvm.org/D41414

Modified:
    cfe/trunk/lib/Rewrite/HTMLRewrite.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp

Modified: cfe/trunk/lib/Rewrite/HTMLRewrite.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/HTMLRewrite.cpp?rev=321320&r1=321319&r2=321320&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/HTMLRewrite.cpp (original)
+++ cfe/trunk/lib/Rewrite/HTMLRewrite.cpp Thu Dec 21 14:57:51 2017
@@ -342,6 +342,7 @@ void html::AddHeaderFooterInternalBuilti
       " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n"
       " .CodeRemovalHint { background-color:#de1010 }\n"
       " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n"
+      " .selected{ background-color:orange !important; }\n"
       " table.simpletable {\n"
       "   padding: 5px;\n"
       "   font-size:12pt;\n"

Modified: cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp?rev=321320&r1=321319&r2=321320&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp Thu Dec 21 14:57:51 2017
@@ -91,6 +91,9 @@ public:
   // Rewrite the file specified by FID with HTML formatting.
   void RewriteFile(Rewriter &R, const SourceManager& SMgr,
                    const PathPieces& path, FileID FID);
+
+  /// \return Javascript for navigating the HTML report using j/k keys.
+  std::string generateKeyboardNavigationJavascript();
 };
 
 } // end anonymous namespace
@@ -337,6 +340,9 @@ void HTMLDiagnostics::FinalizeHTML(const
   int LineNumber = path.back()->getLocation().asLocation().getExpansionLineNumber();
   int ColumnNumber = path.back()->getLocation().asLocation().getExpansionColumnNumber();
 
+  R.InsertTextBefore(SMgr.getLocForStartOfFile(FID),
+                     generateKeyboardNavigationJavascript());
+
   // Add the name of the file as an <h1> tag.
   {
     std::string s;
@@ -378,8 +384,14 @@ void HTMLDiagnostics::FinalizeHTML(const
       os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
     }
 
-    os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
-          "<h3>Annotated Source Code</h3>\n";
+    os << R"<<<(
+</table>
+<!-- REPORTSUMMARYEXTRA -->
+<h3>Annotated Source Code</h3>
+<p><span class='macro'>[?]
+  <span class='expansion'>Use j/k keys for keyboard navigation</span>
+</span></p>
+)<<<";
 
     R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
   }
@@ -777,3 +789,82 @@ void HTMLDiagnostics::HighlightRange(Rew
 
   html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
 }
+
+std::string HTMLDiagnostics::generateKeyboardNavigationJavascript() {
+  return R"<<<(
+<script type='text/javascript'>
+var digitMatcher = new RegExp("[0-9]+");
+
+document.addEventListener("DOMContentLoaded", function() {
+    document.querySelectorAll(".PathNav > a").forEach(
+        function(currentValue, currentIndex) {
+            var hrefValue = currentValue.getAttribute("href");
+            currentValue.onclick = function() {
+                scrollTo(document.querySelector(hrefValue));
+                return false;
+            };
+        });
+});
+
+var findNum = function() {
+    var s = document.querySelector(".selected");
+    if (!s || s.id == "EndPath") {
+        return 0;
+    }
+    var out = parseInt(digitMatcher.exec(s.id)[0]);
+    return out;
+};
+
+var scrollTo = function(el) {
+    document.querySelectorAll(".selected").forEach(function(s) {
+        s.classList.remove("selected");
+    });
+    el.classList.add("selected");
+    window.scrollBy(0, el.getBoundingClientRect().top -
+        (window.innerHeight / 2));
+}
+
+var move = function(num, up, numItems) {
+  if (num == 1 && up || num == numItems - 1 && !up) {
+    return 0;
+  } else if (num == 0 && up) {
+    return numItems - 1;
+  } else if (num == 0 && !up) {
+    return 1 % numItems;
+  }
+  return up ? num - 1 : num + 1;
+}
+
+var numToId = function(num) {
+  if (num == 0) {
+    return document.getElementById("EndPath")
+  }
+  return document.getElementById("Path" + num);
+};
+
+var navigateTo = function(up) {
+  var numItems = document.querySelectorAll(".line > .msg").length;
+  var currentSelected = findNum();
+  var newSelected = move(currentSelected, up, numItems);
+  var newEl = numToId(newSelected, numItems);
+
+  // Scroll element into center.
+  scrollTo(newEl);
+};
+
+window.addEventListener("keydown", function (event) {
+  if (event.defaultPrevented) {
+    return;
+  }
+  if (event.key == "j") {
+    navigateTo(/*up=*/false);
+  } else if (event.key == "k") {
+    navigateTo(/*up=*/true);
+  } else {
+    return;
+  } 
+  event.preventDefault();
+}, true);
+</script>
+  )<<<";
+}




More information about the cfe-commits mailing list