index.html 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Debug</title>
  5. <link rel="stylesheet" href="codemirror.css">
  6. <link rel="stylesheet" href="codemirror-additions.css">
  7. <script src="codemirror.js"></script>
  8. <script src="javascript.js"></script>
  9. <script src="css.js"></script>
  10. <script src="Utilities.js"></script>
  11. <script src="Formatter.js"></script>
  12. <script src="FormatterDebug.js"></script>
  13. <script src="FormatterContentBuilder.js"></script>
  14. <script src="CodeMirrorFormatters.js"></script>
  15. </head>
  16. <body>
  17. <h1>Debug Pretty Printing</h1>
  18. <!-- FIXME: There should be a "save" button that saves the mode and content, so reloading will restore that state -->
  19. <!-- Controls -->
  20. <select id="mode">
  21. <option selected value="text/javascript">JavaScript</option>
  22. <option value="text/css">CSS</option>
  23. </select>
  24. <button id="populate">Populate</button>
  25. <button id="run-tests">Run Tests</button>
  26. <button id="clear">Clear</button>
  27. <button id="select-output">Select Output</button>
  28. <button id="run-again">Run Again</button>
  29. <small id="time"></small>
  30. <br><br>
  31. <!-- Editor -->
  32. <textarea id="code" name="code"></textarea>
  33. <!-- Output -->
  34. <pre id="pretty"></pre>
  35. <pre id="debug"></pre>
  36. <script>
  37. // Editor.
  38. var cm = CodeMirror.fromTextArea(document.getElementById("code"), {
  39. lineNumbers: true,
  40. });
  41. // Initial value.
  42. var str = "(function() { var a=1; return a+1; })();";
  43. cm.setValue(str);
  44. // Setup and changing the mode.
  45. cm.setOption("mode", "text/javascript");
  46. var modePicker = document.getElementById("mode");
  47. modePicker.addEventListener("change", function(event) {
  48. cm.setValue("");
  49. cm.setOption("mode", modePicker.value);
  50. refresh();
  51. });
  52. // Populate button to populate with some canned content.
  53. document.getElementById("populate").addEventListener("click", function(event) {
  54. switch (modePicker.value) {
  55. case "text/javascript":
  56. var url = "populate/jquery.min.js";
  57. break;
  58. case "text/css":
  59. var url = "populate/apple.css";
  60. break;
  61. }
  62. var xhr = new XMLHttpRequest;
  63. xhr.open("GET", url, true);
  64. xhr.onload = function() {
  65. cm.setValue(xhr.responseText);
  66. setTimeout(refresh);
  67. }
  68. xhr.send();
  69. });
  70. // Run Tests button.
  71. document.getElementById("run-tests").addEventListener("click", function(event) {
  72. cm.setValue("Running Tests...");
  73. refresh();
  74. runTests();
  75. });
  76. // Clear button.
  77. document.getElementById("clear").addEventListener("click", function(event) {
  78. cm.setValue("");
  79. refresh();
  80. });
  81. // Select output button.
  82. document.getElementById("select-output").addEventListener("click", function(event) {
  83. var range = document.createRange();
  84. range.selectNodeContents(document.getElementById("pretty"));
  85. var selection = window.getSelection();
  86. selection.removeAllRanges();
  87. selection.addRange(range);
  88. });
  89. // Run again button.
  90. document.getElementById("run-again").addEventListener("click", function(event) {
  91. refresh();
  92. });
  93. // Button helpers.
  94. var buttons = ["mode", "populate", "run-tests", "clear", "select-output", "run-again"];
  95. function disableButtons() {
  96. console.log("disableButtons");
  97. buttons.forEach(function(id) {
  98. document.getElementById(id).disabled = true;
  99. });
  100. }
  101. function enableButtons() {
  102. console.log("enableButtons");
  103. buttons.forEach(function(id) {
  104. document.getElementById(id).disabled = false;
  105. });
  106. }
  107. // Refresh after changes after a short delay.
  108. var timer = null;
  109. cm.on("change", function(codeMirror, change) {
  110. if (timer)
  111. clearTimeout(timer)
  112. timer = setTimeout(function() {
  113. clearTimeout(timer);
  114. timer = null;
  115. refresh();
  116. }, 500);
  117. });
  118. // Output elements.
  119. var timeOutput = document.getElementById("time");
  120. var prettyPre = document.getElementById("pretty");
  121. var debugPre = document.getElementById("debug");
  122. function refresh() {
  123. if (timer)
  124. clearTimeout(timer);
  125. const start = {line: 0, ch: 0};
  126. const end = {line: cm.lineCount() - 1};
  127. // Setup.
  128. const indentString = " ";
  129. var originalLineEndings = [];
  130. var formattedLineEndings = [];
  131. var mapping = {original: [0], formatted: [0]};
  132. var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
  133. var formatter = new Formatter(cm, builder);
  134. // Time the formatter.
  135. var startTime = Date.now();
  136. formatter.format(start, end);
  137. var endTime = Date.now();
  138. // Gather debug information.
  139. var debug = formatter.debug(start, end);
  140. // Output the results.
  141. timeOutput.innerText = (endTime - startTime) + "ms";
  142. prettyPre.innerText = builder.formattedContent;
  143. debugPre.innerText = debug;
  144. }
  145. setTimeout(refresh);
  146. // Tests.
  147. function runTests() {
  148. disableButtons();
  149. function completedCallback() {
  150. enableButtons();
  151. }
  152. if (modePicker.value === "text/javascript")
  153. runJavaScriptTests(completedCallback);
  154. else
  155. runCSSTests(completedCallback);
  156. }
  157. function runJavaScriptTests(callback) {
  158. _runTests(callback, [
  159. "js-tests/block-comment.js",
  160. "js-tests/single-statement-blocks.js",
  161. "js-tests/switch-case-default.js",
  162. ]);
  163. }
  164. function runCSSTests(callback) {
  165. _runTests(callback, []);
  166. }
  167. function _runTests(callback, manifest) {
  168. var index = -1;
  169. var results = [];
  170. setTimeout(runNextTest, 0);
  171. function runNextTest() {
  172. // Next test.
  173. index++;
  174. // Done.
  175. if (index >= manifest.length) {
  176. if (!index)
  177. results.push("/* No tests for mode: " + modePicker.value);
  178. printResults();
  179. return;
  180. }
  181. // Load test and expected results.
  182. var test = manifest[index];
  183. var expected = test.replace(/\.js$/, "-expected.js");
  184. var xhr1 = new XMLHttpRequest;
  185. xhr1.open("GET", test, false);
  186. xhr1.send();
  187. var testData = xhr1.responseText;
  188. var xhr2 = new XMLHttpRequest;
  189. xhr2.open("GET", expected, false);
  190. xhr2.send();
  191. var expectedData = xhr2.responseText;
  192. // Run the test.
  193. var editor = CodeMirror(document.createElement("div"));
  194. editor.setOption("mode", modePicker.value);
  195. editor.setValue(testData);
  196. const start = {line: 0, ch: 0};
  197. const end = {line: editor.lineCount() - 1};
  198. const indentString = " ";
  199. var originalLineEndings = [];
  200. var formattedLineEndings = [];
  201. var mapping = {original: [0], formatted: [0]};
  202. var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
  203. var formatter = new Formatter(editor, builder);
  204. formatter.format(start, end);
  205. // Compare results.
  206. var pass = builder.formattedContent === expectedData;
  207. results.push("/* " + (pass ? "PASS" : "FAIL") + ": " + test + " */");
  208. runNextTest();
  209. }
  210. function printResults() {
  211. cm.setValue(results.join("\n"));
  212. cm.refresh();
  213. callback();
  214. }
  215. }
  216. </script>
  217. </body>
  218. </html>