179 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // TODO why is `this` in use at all?
 | |
| var self = this;
 | |
| 
 | |
| (function () {
 | |
|   "use strict";
 | |
|   /* node-highlight is based on highlight.js (see vendor/highlight.js)       */
 | |
|   /* usage: html = require("highlight").Highlight(code_string);              */
 | |
|   /* NB! You also need to include a CSS file from vendor/highlight.js/styles */
 | |
| 
 | |
|   // load syntax highlighter
 | |
|   // TODO create private instances of highlighter 
 | |
|   // (with fewer langs) for greater accuracy
 | |
|   var Highlight = module.exports
 | |
|     , fs = require('fs')
 | |
|     , hljs = require('./vendor/highlight.js/highlight').hljs
 | |
|     , langRelPath = "vendor/highlight.js/languages/"
 | |
|     , langPath = __dirname + "/" + langRelPath
 | |
|     , reEndsWithJs = /\.js$/i
 | |
|     , loadedMap = {}
 | |
|     , availableMap = {}
 | |
|     ;
 | |
| 
 | |
|   // TODO this should move to init in a newer api
 | |
|   Highlight.loadedLanguages = [];
 | |
| 
 | |
|   function acceptJsFiles(lang) {
 | |
|     if (lang.match(reEndsWithJs)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function preRequireModules(lang, i, arr) {
 | |
|     arr[i] = lang = lang.replace(reEndsWithJs, '');
 | |
| 
 | |
|     try {
 | |
|       availableMap[lang] = require('./' + langRelPath + lang);
 | |
|     } catch(e) {
 | |
|       console.error("[ERROR] could not preload language pack for '" + lang + "'");
 | |
|       console.error(e.message);
 | |
|       console.error(e.stack);
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // find languages from list of fsnodes
 | |
|   function preloadLanguages(err, fsnodes) {
 | |
| 
 | |
|     if (err) {
 | |
|       console.error("[ERROR] langPath '" + langPath + "'");
 | |
|       console.error(err.message);
 | |
|       console.error(err.stack);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     Highlight.languages = fsnodes.filter(acceptJsFiles).sort(function (a, b) {
 | |
|       // xml must be first (others depend on it)
 | |
|       if ('xml' === a) {
 | |
|         return -100000000;
 | |
|       }
 | |
|       // django should be after xml
 | |
|       if ('django.js' === a) {
 | |
|         return 1000000000;
 | |
|       }
 | |
|       
 | |
|       if (a === b) {
 | |
|         return 0;
 | |
|       }
 | |
| 
 | |
|       if (a < b) {
 | |
|         return -1;
 | |
|       } else if (a > b) {
 | |
|         return 1;
 | |
|       } else {
 | |
|         // NaN vs string
 | |
|         return 0;
 | |
|       }
 | |
|     });
 | |
|     Highlight.languages.forEach(preRequireModules);
 | |
|   }
 | |
| 
 | |
|   function loadLangs(cb, langs) {
 | |
|     var err
 | |
|       ;
 | |
| 
 | |
|     if ('string' === typeof langs) {
 | |
|       langs = [langs];
 | |
|     }
 | |
| 
 | |
|     if (!Array.isArray(langs)) {
 | |
|       cb(new Error("no array of languages given"));
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     langs.some(function (lang) {
 | |
|       var addLangToHighlightInstance
 | |
|         ;
 | |
| 
 | |
|       if (loadedMap[lang]) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       addLangToHighlightInstance = availableMap[lang];
 | |
| 
 | |
|       if (!addLangToHighlightInstance) {
 | |
|         err = new Error("No language pack available for '" + lang + "'");
 | |
|         return true;
 | |
|       }
 | |
| 
 | |
|       try {
 | |
|         addLangToHighlightInstance(hljs);
 | |
|       } catch(e) {
 | |
|         // TODO fix django and html-xml
 | |
|         console.warn('[WARN] failed to load', lang);
 | |
|         console.warn(e.message);
 | |
|         console.warn(e.stack);
 | |
|         Highlight.languages = Highlight.languages.filter(function (l) {
 | |
|           return l !== lang;
 | |
|         });
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       loadedMap[lang] = true;
 | |
|       Highlight.loadedLanguages.push(lang);
 | |
|     });
 | |
| 
 | |
|     // future-proofing for async api
 | |
|     cb(err);
 | |
|   }
 | |
| 
 | |
|   function init(cb, langs, opts) {
 | |
|     if (!Array.isArray(langs)) {
 | |
|       langs = Highlight.languages.slice();
 | |
|     }
 | |
| 
 | |
|     loadLangs(cb, langs);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * highlight(text, tabReplace, useCodeBlocks) -> HTML
 | |
|    * - text (String): text to be highlighted
 | |
|    * - tabReplace (String): defaults to 4 spaces if none, replaces \t chars
 | |
|    * - useCodeBlocks (Boolean): If TRUE use only text between <code> and </code>
 | |
|    *
 | |
|    * Highlights program code inside a string by setting appropriate CSS class
 | |
|    * elements.
 | |
|    **/
 | |
|   function highlight(text, tabReplace, useCodeBlocks){
 | |
|     tabReplace = tabReplace || '    ';
 | |
|     text = text.replace(/\r\n|\r|\n/g, '\n'); // remove \r
 | |
|     if (!!useCodeBlocks) {
 | |
|       // JS regexpes have some multiline issues, so we temporarily remove them
 | |
|       return text
 | |
|         .replace(/\n/g,'\uffff')
 | |
|         .replace(/<code([^>]*)>(.*?)<\/code>/gm, function(original, attrs, source){
 | |
|           return '<code'+attrs+'>'+hljs.highlightText(source.replace(/\uffff/g,"\n"), tabReplace)+'</code>';
 | |
|         })
 | |
|         .replace(/&(\w+;)/g,'&$1').replace(/\uffff/g,"\n");
 | |
|     } else {
 | |
|       return hljs.highlightText(text, tabReplace);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //fs.readdir(langPath, preloadLanguages);
 | |
|   // using readdirSync To avoid API Change
 | |
|   preloadLanguages(null, fs.readdirSync(langPath));
 | |
| 
 | |
|   Highlight.init = init;
 | |
|   Highlight.highlight = highlight;
 | |
| 
 | |
|   // Maintain current api:
 | |
|   // TODO why is `this` in use at all?
 | |
|   function backwardsCompat() {
 | |
|     // currently synchronous
 | |
|     Highlight.init(function () {}, ['php']);
 | |
|     return Highlight.highlight.apply(null, arguments);
 | |
|   }
 | |
|   Highlight.Highlight = self.Highlight = backwardsCompat;
 | |
| }());
 |