main.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // global function to set global options. see below.
  2. var JSCodeHighlight;
  3. (function(){
  4. // Options
  5. var gopts = {
  6. rootClass: 'js-code-highlight-root',
  7. inlineRootClass: 'inline',
  8. multilineRootClass: 'multiline',
  9. titleClass: 'title',
  10. lineClass: 'line',
  11. gutterClass: 'line-nums',
  12. codeBlockClass: 'code-block',
  13. font: "Courier New",
  14. multilineSelector: "foobar",
  15. inlineSelector: "ipre, c, m",
  16. bareSelector: "c",
  17. failsafe: 10000,
  18. defaultLanguage: 'c',
  19. defaultTagLanguage: { m: 'asm', c: 'c' },
  20. languageClassPrefix: 'lang-',
  21. };
  22. JSCodeHighlight = function(o) {
  23. for(var k in o) {
  24. gopts[k] = o[k];
  25. }
  26. };
  27. // Highlighting Rules
  28. // The only non-anonymous group is the one captured
  29. // name: "foo" will be added as a css class to the element.
  30. var rule_list = {
  31. none: [],
  32. c: [
  33. {name: 'whitespace', re: /^(\s+)/ },
  34. {name: 'preproc', re: /^(#[a-zA-Z]+.*)(?:\n|$)/ },
  35. {name: 'comment', re: /^(\/\/.*)(\n|$)/ },
  36. {name: 'comment', re: /^(\/\*(?:.|\n)*\*\/)/m },
  37. {name: 'type', re: /^((?:const|extern|int|inline|restrict|void|volatile|float|char|double|unsigned|signed|short|long|static|struct|union|enum|auto|register|[a-z_0-9]+_t)\**)(?:\W|$)/ },
  38. {name: 'keyword', re: /^(if|for|else|while|do|switch|return|break|continue|default|case|goto|typedef|sizeof|offsetof)(?:\W|$)/ },
  39. {name: 'string', re: /^("(?:[^"]*|\\.)*")/ },
  40. {name: 'charlit', re: /^('(?:[^']*|\\.)*')/ },
  41. {name: 'number', re: /^([-+]?[0-9]*\.?[0-9]+e?[0-9]*[ulfb]*)/i },
  42. {name: 'number', re: /^([-+]?0x[0-9a-fA-F]*\.?[0-9a-fA-F]+e?[0-9a-fA-F]*[ulfb]*)/i },
  43. {name: 'punct', re: /^((?:>|<|&)+|[\(\)\[\]{}\|\.,\+=\-?\/\\\*^%:;!~]+)/ },
  44. {name: 'ident', re: /^(?:([a-zA-Z_][a-zA-Z_0-9]*)(?:\W|$))/ },
  45. ],
  46. asm: [ // intel style
  47. {name: 'whitespace', re: /^(\s+)/ },
  48. {name: 'comment', re: /^(;.*)(\n|$)/ },
  49. {name: 'keyword', re: /^((?:(?:[qd]?word|byte)\s+(?:ptr))|(offset (?:flat)?))(?:\W|$)/i },
  50. {name: 'directive', re: /^(\.(?:align|ascii|bcd|bss|[248]?byte|comm|data|double|even|ext|file|float|glabl|group|hidden|ident|lcomm|local|long|popsection|previous|pushsection|quad|rel|section|set|size|skip|sleb128|string|symbolic|tbss|tcomm|tdata|text|type|uleb128|value|weak|zero))/i },
  51. {name: 'label', re: /^(\.?[a-z_][a-z0-9_]*:)/i },
  52. {name: 'label', re: /^(\.[a-z_][a-z0-9_]*:?)/i },
  53. {name: 'register', re: /^([RE]?[ABCD]X|[RE]?[SBI]P|[RE]?[SD]I|[ABCD][HL]|[SB]PL|[SD]IL|R[89][BWD]?|R1[0-5][BWD]?|EFLAGS|FLAGS)(?:\W|$)/i },
  54. {name: 'simd-register', re: /^([xyz]?mm\d\d?)(?:\W|$)/i },
  55. {name: 'string', re: /^("(?:[^"]*|\\.)*")/ },
  56. {name: 'number', re: /^([-+]?0[xb][0-9a-fA-F]*\.?[0-9a-fA-F]+e?[0-9a-fA-F]*[ulfb]*)/i },
  57. {name: 'number', re: /^([-+]?[0-9]*\.?[0-9]+e?[0-9]*[ulfb]*)/i },
  58. {name: 'punct', re: /^([\[\],\+\-:]+)/ },
  59. {name: 'ident', re: /^([a-zA-Z_][a-zA-Z_0-9]*)(?:\W|$)/ },
  60. ]
  61. };
  62. window.addEventListener('load', function() {
  63. // utility functions
  64. function min(a,b) {return a > b ? b : a }
  65. function leadingTabs(s) {
  66. for(var i = 0; i < s.length && s[i] == "\t"; i++);
  67. return i;
  68. }
  69. function eat(s, re, cl, out_lines) {
  70. var m = s.l.match(re);
  71. if(m) {
  72. // console.log(cl, m);
  73. var t = m[1];
  74. out_lines.push(
  75. t.split('\n')
  76. .map(function(x) { return '<span class="'+cl+'">'+x+'</span>'})
  77. .join('\n')
  78. );
  79. s.l = s.l.slice(t.length);
  80. return true;
  81. }
  82. return false;
  83. }
  84. function processLine(s, rules) {
  85. var k = {l: s};
  86. var j = 0;
  87. var ol = []
  88. while(k.l.length > 0) {
  89. if(j++ > gopts.failsafe) return;
  90. // preserve tags
  91. var m = k.l.match(/^<\/?[^>]*>/);
  92. if(m) {
  93. ol.push(m[0]);
  94. console.log(m[0]);
  95. k.l = k.l.slice(m[0].length);
  96. continue;
  97. }
  98. /*
  99. // preserve &..;
  100. var m = k.l.match(/^&[a-z]{1,4};/);
  101. if(m) {
  102. ol.push(m[0]);
  103. console.log(m[0]);
  104. k.l = k.l.slice(m[0].length);
  105. continue;
  106. }
  107. */
  108. // process the rules
  109. var br = false;
  110. for(var r of rules) {
  111. if(j++ > gopts.failsafe) return;
  112. if(eat(k, r.re, r.name, ol)) {
  113. br = true;
  114. break;
  115. }
  116. }
  117. if(br) continue;
  118. ol.push(k.l[0]);
  119. k.l = k.l.slice(1);
  120. }
  121. return ol;
  122. }
  123. // multiline pre's
  124. /*
  125. var pres = document.querySelectorAll(gopts.multilineSelector);
  126. for(var pre of pres) {
  127. var text = pre.innerHTML;
  128. var lines = text.split("\n");
  129. var lang = pre.getAttribute('lang') || gopts.defaultLanguage;
  130. var rules = rule_list[lang];
  131. if(!rules) rules = rule_list['none'];
  132. var start_line = parseFloat(pre.getAttribute('ln') || 1);
  133. // find out how many tabs to trim on the left
  134. var least_tabs = 999999999;
  135. var trailing_empty = 0;
  136. for(var l of lines) {
  137. var n = leadingTabs(l);
  138. if(l[n] !== undefined) {
  139. least_tabs = min(least_tabs, n);
  140. if(l[n] != ' ') {
  141. trailing_empty = 0;
  142. }
  143. }
  144. trailing_empty++;
  145. }
  146. lines = lines.slice(0, -trailing_empty+1);
  147. var out_lines = [];
  148. for(var l of lines) {
  149. l = l.slice(least_tabs);
  150. out_lines.push(l);
  151. }
  152. // all this messy joining and splitting is to handle multi-line matches like comments
  153. // but also put each code line inside its own span
  154. var txt = out_lines.join("\n");
  155. var hl = processLine(txt, rules);
  156. out_lines = hl.join("").split("\n");
  157. var parent = document.createElement('div');
  158. parent.classList.add(gopts.rootClass);
  159. parent.classList.add(gopts.multilineRootClass);
  160. parent.classList.add(gopts.languageClassPrefix + lang);
  161. parent.style.display = "block";
  162. parent.style.position = "relative";
  163. parent.style.overflowX = "auto";
  164. parent.style.overflowY = "auto";
  165. pre.replaceWith(parent);
  166. var title = pre.getAttribute('title')
  167. if(title) {
  168. var tn = document.createElement('div');
  169. tn.classList.add(gopts.titleClass);
  170. tn.innerHTML = title;
  171. parent.append(tn);
  172. }
  173. var scrollp = document.createElement('div');
  174. scrollp.style.clear = "both";
  175. parent.appendChild(scrollp);
  176. var line_nums = document.createElement('span');
  177. line_nums.classList.add(gopts.gutterClass);
  178. line_nums.style.display = "block";
  179. line_nums.style.float = "left";
  180. line_nums.style.fontFamily = gopts.font;
  181. line_nums.style.whiteSpace = "pre";
  182. line_nums.style.userSelect = "none";
  183. for(var i = 0; i < lines.length; i++) {
  184. var nl = document.createElement('span');
  185. nl.classList.add(gopts.lineClass);
  186. nl.innerHTML = (i + start_line) + "\n";
  187. line_nums.append(nl);
  188. }
  189. scrollp.append(line_nums);
  190. var code_block = document.createElement('div');
  191. code_block.classList.add(gopts.codeBlockClass);
  192. code_block.style.position = "absolute";
  193. code_block.style.fontFamily = gopts.font;
  194. code_block.style.whiteSpace = "pre";
  195. code_block.style.left = line_nums.offsetWidth;
  196. // getComputedStyle
  197. for(var l of out_lines) {
  198. var nl = document.createElement('span');
  199. nl.classList.add(gopts.lineClass);
  200. nl.innerHTML = l + "\n";
  201. code_block.append(nl);
  202. }
  203. scrollp.append(code_block);
  204. }
  205. */
  206. // inline pre's
  207. /*
  208. var pres = document.querySelectorAll(gopts.inlineSelector);
  209. for(var pre of pres) {
  210. var extra = "";
  211. var src = pre.innerHTML.replace(/^\s+/, '').replace(/\s+$/, '')
  212. var lang = pre.getAttribute('lang') || gopts.defaultLanguage;
  213. var rules = rule_list[lang];
  214. if(!rules) rules = rule_list['none'];
  215. var line_num = pre.getAttribute('ln');
  216. if(line_num) {
  217. extra = '<span class="line-nums">'+line_num+'</span>';
  218. }
  219. var parent = document.createElement('span');
  220. parent.style.display = "inline-block";
  221. parent.style.whiteSpace = "pre";
  222. parent.style.fontFamily = gopts.font;
  223. parent.classList.add(gopts.rootClass);
  224. parent.classList.add(gopts.inlineRootClass);
  225. parent.classList.add(gopts.languageClassPrefix + lang);
  226. parent.innerHTML = extra + processLine(src, rules).join('');
  227. pre.replaceWith(parent);
  228. }
  229. */
  230. // bare lines
  231. var bare = document.querySelectorAll(gopts.bareSelector);
  232. for(var pre of bare) {
  233. var extra = "";
  234. var src = pre.innerHTML;//.replace(/^\s+/, '').replace(/\s+$/, '')
  235. var lang = pre.getAttribute('lang') || gopts.defaultLanguage;
  236. var rules = rule_list[lang];
  237. if(!rules) rules = rule_list['c'];
  238. /*
  239. var parent = document.createElement('span');
  240. parent.style.display = "inline-block";
  241. parent.style.whiteSpace = "pre";
  242. parent.style.fontFamily = gopts.font;
  243. parent.classList.add(gopts.rootClass);
  244. parent.classList.add(gopts.inlineRootClass);
  245. parent.classList.add(gopts.languageClassPrefix + lang);
  246. parent.innerHTML = extra + processLine(src, rules).join('');
  247. */
  248. pre.innerHTML = extra + processLine(src, rules).join('');
  249. // pre.replaceWith(parent);
  250. }
  251. });
  252. })();