Kiss me on GitHub
Prism Grammar
Build your own syntax-highlighter grammar for Prism
Prism v.
0
, PrismGrammar v.
0
Sample Code to be highlighted (see output below):
// this is part of the PrismGrammar code itself function get_mode( grammar, Prism ) { var prism_highlighter, is_hooked = 0, $Prism$ = Prism, highlighter$ = { 'before-highlight': function( env ) { // use the custom parser for the grammar to highlight // hook only if the language matches if ( prism_highlighter.$parser && (prism_highlighter.$lang === env.language) ) { // avoid double highlight work, set code to "" env._code = env.code; env.code = ""; } }, 'before-insert': function( env ) { if ( prism_highlighter.$parser && (prism_highlighter.$lang === env.language) ) { // re-set env.code = env._code; env._code = ""; // tokenize code and transform to prism-compatible tokens var tokens = prism_highlighter.$parser.parse(env.code, TOKENS|ERRORS|FLAT).tokens; // html-escape code if ( prism_highlighter.escapeHtml ) iterate( esc_token, 0, tokens.length-1, tokens ); env.highlightedCode = $Prism$.Token.stringify( tokens, env.language ); } } }; // return a plugin that can be hooked-unhooked to Prism under certain language conditions prism_highlighter = { $id: uuid("prism_grammar_highlighter") ,$parser: new PrismGrammar.Parser( parse_grammar( grammar ) ) ,$lang: null // have escapeHtml flag true by default ,escapeHtml: true // TODO: a way to highlight in worker (like default prism async flag) // post a request to prism repository????? ,$async: false ,hook: function( language, Prism ) { if ( is_hooked ) prism_highlighter.unhook(); if ( T_STR & get_type(Prism) ) { // arguments given in different order var tmp = language; language = Prism; Prism = tmp; } $Prism$ = Prism || $Prism$; prism_highlighter.$lang = language; for (var hook in highlighter$ ) { if ( highlighter$[HAS](hook) ) $Prism$.hooks.add( hook, highlighter$[hook] ); } is_hooked = 1; } ,unhook: function( ) { if ( is_hooked ) { var prism_hooks = $Prism$.hooks.all, hook, this_hook; for (hook in highlighter$) { if ( prism_hooks[HAS](hook) && highlighter$[HAS](hook) ) { this_hook = prism_hooks[hook].indexOf( highlighter$[hook] ); if ( this_hook > -1 ) prism_hooks[hook].splice(this_hook, 1); } } is_hooked = 0; prism_highlighter.$lang = null; $Prism$ = null; } } ,dispose: function( ) { prism_highlighter.unhook(); if ( prism_highlighter.$parser ) prism_highlighter.$parser.dispose( ); prism_highlighter.$parser = null; prism_highlighter.$lang = null; } }; return prism_highlighter; }
Grammar (JSON format):
// a partial javascript grammar in simple JSON format { // prefix ID for regular expressions used in the grammar "RegExpID" : "RE::", // Style model "Style" : { "comment" : "comment" ,"atom" : "entity" ,"keyword" : "keyword" ,"this" : "keyword" ,"builtin" : "builtin" ,"operator" : "operator" ,"identifier" : "symbol" ,"property" : "property" ,"number" : "number" ,"string" : "string" ,"regex" : "regex" }, // Lexical model "Lex" : { "comment" : {"type":"comment","tokens":[ // line comment // start, end delims (null matches end-of-line) [ "//", null ], // block comments // start, end delims [ "/*", "*/" ] ]} ,"identifier" : "RE::/[_A-Za-z$][_A-Za-z0-9$]*/" ,"this" : "RE::/this\\b/" ,"property" : "RE::/[_A-Za-z$][_A-Za-z0-9$]*/" ,"number" : [ // floats "RE::/\\d*\\.\\d+(e[\\+\\-]?\\d+)?/", "RE::/\\d+\\.\\d*/", "RE::/\\.\\d+/", // integers // hex "RE::/0x[0-9a-fA-F]+L?/", // binary "RE::/0b[01]+L?/", // octal "RE::/0o[0-7]+L?/", // decimal "RE::/[1-9]\\d*(e[\\+\\-]?\\d+)?L?/", // just zero "RE::/0(?![\\dx])/" ] ,"string" : {"type":"escaped-block","escape":"\\","tokens": // start, end of string (can be the matched regex group ie. 1 ) [ "RE::/(['\"])/", 1 ] } ,"regex" : {"type":"escaped-block","escape":"\\","tokens": // javascript literal regular expressions can be parsed similar to strings [ "/", "RE::#/[gimy]{0,4}#" ] } ,"operator" : {"tokens":[ "+", "-", "++", "--", "%", ">>", "<<", ">>>", "*", "/", "^", "|", "&", "!", "~", ">", "<", "<=", ">=", "!=", "!==", "=", "==", "===", "+=", "-=", "%=", ">>=", ">>>=", "<<=", "*=", "/=", "|=", "&=" ]} ,"delimiter" : {"tokens":[ "(", ")", "[", "]", "{", "}", ",", "=", ";", "?", ":", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "++", "--", ">>=", "<<=" ]} ,"atom" : {"autocomplete":true,"tokens":[ "true", "false", "null", "undefined", "NaN", "Infinity" ]} ,"keyword" : {"autocomplete":true,"tokens":[ "if", "while", "with", "else", "do", "try", "finally", "return", "break", "continue", "new", "delete", "throw", "var", "const", "let", "function", "catch", "void", "for", "switch", "case", "default", "class", "import", "yield", "in", "typeof", "instanceof" ]} ,"builtin" : {"autocomplete":true,"tokens":[ "Object", "Function", "Array", "String", "Date", "Number", "RegExp", "Math", "Exception", "setTimeout", "setInterval", "parseInt", "parseFloat", "isFinite", "isNan", "alert", "prompt", "console", "window", "global", "this" ]} }, // Syntax model (optional) "Syntax" : { "dot_property" : {"sequence":[".", "property"]} ,"js" : "comment | number | string | regex | keyword | operator | atom | (('}' | ')' | this | builtin | identifier | dot_property) dot_property*)" }, // what to parse and in what order "Parser" : [ ["js"] ] }
Output: