워드프레스에 많은 syntexhighligher 플러그인들이 있는데, glsl shading 언어를 지원하는 건 그리 많지 않다. crayon syntax hightlighter가 이를 지원해서 써 왔는데, 썩 맘에 들지 않는 디자인과 시스템 전체에 부하가 걸리는 느낌이 싫어 prism.js를 쓰게 되었다.
Prism.js는 요즘 많이 사용되는 javascript syntexhighligher인데 깔끔한 디자인과 crayon에 비해 비교적 빠른 로딩속도로 인해 사용하고 싶은 마음은 있었는데, 지난번에도 역시 glsl을 지원하지 않아서 쓰지 못했던 기억이 났다. 이참에 방법을 알아보려고 이리저리 애를 쓰다 기존에 있던 구문강조 들 중 가장 glsl과 비슷한 것이 c-like 인 것을 알아내서, 이를 이용해서 glsl 랭귀지를 만들기로 했다. 워드프레스 플러그인을 설치하고 c문법에서 몇가지 구문을 추가하기로 했다. 방법은 다음과 같다.
문제
- prism.js에서 "language-glsl" class를 인식하지 못한다.
해결방법
- 가장 비슷한 language-clike 를 복사하여, glsl의 구문 몇가지를 추가하고 language-glsl을 추가한다.
순서
- prism.js를 지원하는 워드프레스 플러그인을 설치한다.
- 플러그인에서 참고하는 prism.js를 수정해서 c-like랭귀지 부분을 찾는다.
- c-like부분이 없는 경우 prismjs.com에 들어가서 c-like를 추가해서 js와 css를 download받는다.
- c-like부분 다음에 아래 소스를 추가해서 ‘language-glsl’구문을 입력받을 수 있게 만든다.
일단 워드프레스 플러그인은 몇가지가 있는데 그중에서도 WordPress › WP Prism Syntax Highlighter « WordPress Plugins 을 사용했는데, 마음에 드는 것을 사용하면 될 것 같다.
플러그인 디렉토리 안에 있는 prism.js파일을 열고 c-like부분을 찾아서 아래 구문을 추가한다.
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+php+coffeescript+scss+bash+c+markdown&plugins=show-invisibles+show-language */ | |
self = (typeof window !== 'undefined') | |
? window // if in browser | |
: ( | |
(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) | |
? self // if in worker | |
: {} // if in node js | |
); | |
/** | |
* Prism: Lightweight, robust, elegant syntax highlighting | |
* MIT license http://www.opensource.org/licenses/mit-license.php/ | |
* @author Lea Verou http://lea.verou.me | |
*/ | |
var Prism = (function(){ | |
// Private helper vars | |
var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i; | |
var _ = self.Prism = { | |
util: { | |
encode: function (tokens) { | |
if (tokens instanceof Token) { | |
return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); | |
} else if (_.util.type(tokens) === 'Array') { | |
return tokens.map(_.util.encode); | |
} else { | |
return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); | |
} | |
}, | |
type: function (o) { | |
return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1]; | |
}, | |
// Deep clone a language definition (e.g. to extend it) | |
clone: function (o) { | |
var type = _.util.type(o); | |
switch (type) { | |
case 'Object': | |
var clone = {}; | |
for (var key in o) { | |
if (o.hasOwnProperty(key)) { | |
clone[key] = _.util.clone(o[key]); | |
} | |
} | |
return clone; | |
case 'Array': | |
return o.map(function(v) { return _.util.clone(v); }); | |
} | |
return o; | |
} | |
}, | |
languages: { | |
extend: function (id, redef) { | |
var lang = _.util.clone(_.languages[id]); | |
for (var key in redef) { | |
lang[key] = redef[key]; | |
} | |
return lang; | |
}, | |
/** | |
* Insert a token before another token in a language literal | |
* As this needs to recreate the object (we cannot actually insert before keys in object literals), | |
* we cannot just provide an object, we need anobject and a key. | |
* @param inside The key (or language id) of the parent | |
* @param before The key to insert before. If not provided, the function appends instead. | |
* @param insert Object with the key/value pairs to insert | |
* @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted. | |
*/ | |
insertBefore: function (inside, before, insert, root) { | |
root = root || _.languages; | |
var grammar = root[inside]; | |
if (arguments.length == 2) { | |
insert = arguments[1]; | |
for (var newToken in insert) { | |
if (insert.hasOwnProperty(newToken)) { | |
grammar[newToken] = insert[newToken]; | |
} | |
} | |
return grammar; | |
} | |
var ret = {}; | |
for (var token in grammar) { | |
if (grammar.hasOwnProperty(token)) { | |
if (token == before) { | |
for (var newToken in insert) { | |
if (insert.hasOwnProperty(newToken)) { | |
ret[newToken] = insert[newToken]; | |
} | |
} | |
} | |
ret[token] = grammar[token]; | |
} | |
} | |
// Update references in other language definitions | |
_.languages.DFS(_.languages, function(key, value) { | |
if (value === root[inside] && key != inside) { | |
this[key] = ret; | |
} | |
}); | |
return root[inside] = ret; | |
}, | |
// Traverse a language definition with Depth First Search | |
DFS: function(o, callback, type) { | |
for (var i in o) { | |
if (o.hasOwnProperty(i)) { | |
callback.call(o, i, o[i], type || i); | |
if (_.util.type(o[i]) === 'Object') { | |
_.languages.DFS(o[i], callback); | |
} | |
else if (_.util.type(o[i]) === 'Array') { | |
_.languages.DFS(o[i], callback, i); | |
} | |
} | |
} | |
} | |
}, | |
highlightAll: function(async, callback) { | |
var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'); | |
for (var i=0, element; element = elements[i++];) { | |
_.highlightElement(element, async === true, callback); | |
} | |
}, | |
highlightElement: function(element, async, callback) { | |
// Find language | |
var language, grammar, parent = element; | |
while (parent && !lang.test(parent.className)) { | |
parent = parent.parentNode; | |
} | |
if (parent) { | |
language = (parent.className.match(lang) || [,''])[1]; | |
grammar = _.languages[language]; | |
} | |
if (!grammar) { | |
return; | |
} | |
// Set language on the element, if not present | |
element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; | |
// Set language on the parent, for styling | |
parent = element.parentNode; | |
if (/pre/i.test(parent.nodeName)) { | |
parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; | |
} | |
var code = element.textContent; | |
if(!code) { | |
return; | |
} | |
code = code.replace(/^(?:\r?\n|\r)/,''); | |
var env = { | |
element: element, | |
language: language, | |
grammar: grammar, | |
code: code | |
}; | |
_.hooks.run('before-highlight', env); | |
if (async && self.Worker) { | |
var worker = new Worker(_.filename); | |
worker.onmessage = function(evt) { | |
env.highlightedCode = Token.stringify(JSON.parse(evt.data), language); | |
_.hooks.run('before-insert', env); | |
env.element.innerHTML = env.highlightedCode; | |
callback && callback.call(env.element); | |
_.hooks.run('after-highlight', env); | |
}; | |
worker.postMessage(JSON.stringify({ | |
language: env.language, | |
code: env.code | |
})); | |
} | |
else { | |
env.highlightedCode = _.highlight(env.code, env.grammar, env.language); | |
_.hooks.run('before-insert', env); | |
env.element.innerHTML = env.highlightedCode; | |
callback && callback.call(element); | |
_.hooks.run('after-highlight', env); | |
} | |
}, | |
highlight: function (text, grammar, language) { | |
var tokens = _.tokenize(text, grammar); | |
return Token.stringify(_.util.encode(tokens), language); | |
}, | |
tokenize: function(text, grammar, language) { | |
var Token = _.Token; | |
var strarr = [text]; | |
var rest = grammar.rest; | |
if (rest) { | |
for (var token in rest) { | |
grammar[token] = rest[token]; | |
} | |
delete grammar.rest; | |
} | |
tokenloop: for (var token in grammar) { | |
if(!grammar.hasOwnProperty(token) || !grammar[token]) { | |
continue; | |
} | |
var patterns = grammar[token]; | |
patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns]; | |
for (var j = 0; j < patterns.length; ++j) { | |
var pattern = patterns[j], | |
inside = pattern.inside, | |
lookbehind = !!pattern.lookbehind, | |
lookbehindLength = 0, | |
alias = pattern.alias; | |
pattern = pattern.pattern || pattern; | |
for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop | |
var str = strarr[i]; | |
if (strarr.length > text.length) { | |
// Something went terribly wrong, ABORT, ABORT! | |
break tokenloop; | |
} | |
if (str instanceof Token) { | |
continue; | |
} | |
pattern.lastIndex = 0; | |
var match = pattern.exec(str); | |
if (match) { | |
if(lookbehind) { | |
lookbehindLength = match[1].length; | |
} | |
var from = match.index - 1 + lookbehindLength, | |
match = match[0].slice(lookbehindLength), | |
len = match.length, | |
to = from + len, | |
before = str.slice(0, from + 1), | |
after = str.slice(to + 1); | |
var args = [i, 1]; | |
if (before) { | |
args.push(before); | |
} | |
var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias); | |
args.push(wrapped); | |
if (after) { | |
args.push(after); | |
} | |
Array.prototype.splice.apply(strarr, args); | |
} | |
} | |
} | |
} | |
return strarr; | |
}, | |
hooks: { | |
all: {}, | |
add: function (name, callback) { | |
var hooks = _.hooks.all; | |
hooks[name] = hooks[name] || []; | |
hooks[name].push(callback); | |
}, | |
run: function (name, env) { | |
var callbacks = _.hooks.all[name]; | |
if (!callbacks || !callbacks.length) { | |
return; | |
} | |
for (var i=0, callback; callback = callbacks[i++];) { | |
callback(env); | |
} | |
} | |
} | |
}; | |
var Token = _.Token = function(type, content, alias) { | |
this.type = type; | |
this.content = content; | |
this.alias = alias; | |
}; | |
Token.stringify = function(o, language, parent) { | |
if (typeof o == 'string') { | |
return o; | |
} | |
if (Object.prototype.toString.call(o) == '[object Array]') { | |
return o.map(function(element) { | |
return Token.stringify(element, language, o); | |
}).join(''); | |
} | |
var env = { | |
type: o.type, | |
content: Token.stringify(o.content, language, parent), | |
tag: 'span', | |
classes: ['token', o.type], | |
attributes: {}, | |
language: language, | |
parent: parent | |
}; | |
if (env.type == 'comment') { | |
env.attributes['spellcheck'] = 'true'; | |
} | |
if (o.alias) { | |
var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; | |
Array.prototype.push.apply(env.classes, aliases); | |
} | |
_.hooks.run('wrap', env); | |
var attributes = ''; | |
for (var name in env.attributes) { | |
attributes += name + '="' + (env.attributes[name] || '') + '"'; | |
} | |
return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>'; | |
}; | |
if (!self.document) { | |
if (!self.addEventListener) { | |
// in Node.js | |
return self.Prism; | |
} | |
// In worker | |
self.addEventListener('message', function(evt) { | |
var message = JSON.parse(evt.data), | |
lang = message.language, | |
code = message.code; | |
self.postMessage(JSON.stringify(_.util.encode(_.tokenize(code, _.languages[lang])))); | |
self.close(); | |
}, false); | |
return self.Prism; | |
} | |
// Get current script and highlight | |
var script = document.getElementsByTagName('script'); | |
script = script[script.length - 1]; | |
if (script) { | |
_.filename = script.src; | |
if (document.addEventListener && !script.hasAttribute('data-manual')) { | |
document.addEventListener('DOMContentLoaded', _.highlightAll); | |
} | |
} | |
return self.Prism; | |
})(); | |
if (typeof module !== 'undefined' && module.exports) { | |
module.exports = Prism; | |
} | |
; | |
Prism.languages.markup = { | |
'comment': /<!--[\w\W]*?-->/g, | |
'prolog': /<\?.+?\?>/, | |
'doctype': /<!DOCTYPE.+?>/, | |
'cdata': /<!\[CDATA\[[\w\W]*?]]>/i, | |
'tag': { | |
pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi, | |
inside: { | |
'tag': { | |
pattern: /^<\/?[\w:-]+/i, | |
inside: { | |
'punctuation': /^<\/?/, | |
'namespace': /^[\w-]+?:/ | |
} | |
}, | |
'attr-value': { | |
pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi, | |
inside: { | |
'punctuation': /=|>|"/g | |
} | |
}, | |
'punctuation': /\/?>/g, | |
'attr-name': { | |
pattern: /[\w:-]+/g, | |
inside: { | |
'namespace': /^[\w-]+?:/ | |
} | |
} | |
} | |
}, | |
'entity': /&#?[\da-z]{1,8};/gi | |
}; | |
// Plugin to make entity title show the real entity, idea by Roman Komarov | |
Prism.hooks.add('wrap', function(env) { | |
if (env.type === 'entity') { | |
env.attributes['title'] = env.content.replace(/&/, '&'); | |
} | |
}); | |
; | |
Prism.languages.css = { | |
'comment': /\/\*[\w\W]*?\*\//g, | |
'atrule': { | |
pattern: /@[\w-]+?.*?(;|(?=\s*\{))/gi, | |
inside: { | |
'punctuation': /[;:]/g | |
} | |
}, | |
'url': /url\((?:(["'])(\\\n|\\?.)*?\1|.*?)\)/gi, | |
'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g, | |
'string': /("|')(\\\n|\\?.)*?\1/g, | |
'property': /(\b|\B)[\w-]+(?=\s*:)/ig, | |
'important': /\B!important\b/gi, | |
'punctuation': /[\{\};:]/g, | |
'function': /[-a-z0-9]+(?=\()/ig | |
}; | |
if (Prism.languages.markup) { | |
Prism.languages.insertBefore('markup', 'tag', { | |
'style': { | |
pattern: /<style[\w\W]*?>[\w\W]*?<\/style>/ig, | |
inside: { | |
'tag': { | |
pattern: /<style[\w\W]*?>|<\/style>/ig, | |
inside: Prism.languages.markup.tag.inside | |
}, | |
rest: Prism.languages.css | |
}, | |
alias: 'language-css' | |
} | |
}); | |
Prism.languages.insertBefore('inside', 'attr-value', { | |
'style-attr': { | |
pattern: /\s*style=("|').+?\1/ig, | |
inside: { | |
'attr-name': { | |
pattern: /^\s*style/ig, | |
inside: Prism.languages.markup.tag.inside | |
}, | |
'punctuation': /^\s*=\s*['"]|['"]\s*$/, | |
'attr-value': { | |
pattern: /.+/gi, | |
inside: Prism.languages.css | |
} | |
}, | |
alias: 'language-css' | |
} | |
}, Prism.languages.markup.tag); | |
}; | |
Prism.languages.clike = { | |
'comment': [ | |
{ | |
pattern: /(^|[^\\])\/\*[\w\W]*?\*\//g, | |
lookbehind: true | |
}, | |
{ | |
pattern: /(^|[^\\:])\/\/.*?(\r?\n|$)/g, | |
lookbehind: true | |
} | |
], | |
'string': /("|')(\\\n|\\?.)*?\1/g, | |
'class-name': { | |
pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig, | |
lookbehind: true, | |
inside: { | |
punctuation: /(\.|\\)/ | |
} | |
}, | |
'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g, | |
'boolean': /\b(true|false)\b/g, | |
'function': { | |
pattern: /[a-z0-9_]+\(/ig, | |
inside: { | |
punctuation: /\(/ | |
} | |
}, | |
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g, | |
'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/g, | |
'ignore': /&(lt|gt|amp);/gi, | |
'punctuation': /[{}[\];(),.:]/g | |
}; | |
; | |
Prism.languages.javascript = Prism.languages.extend('clike', { | |
'keyword': /\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g, | |
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/g, | |
'function': /(?!\d)[a-z0-9_$]+(?=\()/ig | |
}); | |
Prism.languages.insertBefore('javascript', 'keyword', { | |
'regex': { | |
pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g, | |
lookbehind: true | |
} | |
}); | |
if (Prism.languages.markup) { | |
Prism.languages.insertBefore('markup', 'tag', { | |
'script': { | |
pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/ig, | |
inside: { | |
'tag': { | |
pattern: /<script[\w\W]*?>|<\/script>/ig, | |
inside: Prism.languages.markup.tag.inside | |
}, | |
rest: Prism.languages.javascript | |
}, | |
alias: 'language-javascript' | |
} | |
}); | |
} | |
; | |
/** | |
* Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/ | |
* Modified by Miles Johnson: http://milesj.me | |
* | |
* Supports the following: | |
* - Extends clike syntax | |
* - Support for PHP 5.3+ (namespaces, traits, generators, etc) | |
* - Smarter constant and function matching | |
* | |
* Adds the following new token classes: | |
* constant, delimiter, variable, function, package | |
*/ | |
Prism.languages.php = Prism.languages.extend('clike', { | |
'keyword': /\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/ig, | |
'constant': /\b[A-Z0-9_]{2,}\b/g, | |
'comment': { | |
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])(\/\/|#).*?(\r?\n|$))/g, | |
lookbehind: true | |
} | |
}); | |
Prism.languages.insertBefore('php', 'keyword', { | |
'delimiter': /(\?>|<\?php|<\?)/ig, | |
'variable': /(\$\w+)\b/ig, | |
'package': { | |
pattern: /(\\|namespace\s+|use\s+)[\w\\]+/g, | |
lookbehind: true, | |
inside: { | |
punctuation: /\\/ | |
} | |
} | |
}); | |
// Must be defined after the function pattern | |
Prism.languages.insertBefore('php', 'operator', { | |
'property': { | |
pattern: /(->)[\w]+/g, | |
lookbehind: true | |
} | |
}); | |
// Add HTML support of the markup language exists | |
if (Prism.languages.markup) { | |
// Tokenize all inline PHP blocks that are wrapped in <?php ?> | |
// This allows for easy PHP + markup highlighting | |
Prism.hooks.add('before-highlight', function(env) { | |
if (env.language !== 'php') { | |
return; | |
} | |
env.tokenStack = []; | |
env.backupCode = env.code; | |
env.code = env.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/ig, function(match) { | |
env.tokenStack.push(match); | |
return '{{{PHP' + env.tokenStack.length + '}}}'; | |
}); | |
}); | |
// Restore env.code for other plugins (e.g. line-numbers) | |
Prism.hooks.add('before-insert', function(env) { | |
if (env.language === 'php') { | |
env.code = env.backupCode; | |
delete env.backupCode; | |
} | |
}); | |
// Re-insert the tokens after highlighting | |
Prism.hooks.add('after-highlight', function(env) { | |
if (env.language !== 'php') { | |
return; | |
} | |
for (var i = 0, t; t = env.tokenStack[i]; i++) { | |
env.highlightedCode = env.highlightedCode.replace('{{{PHP' + (i + 1) + '}}}', Prism.highlight(t, env.grammar, 'php')); | |
} | |
env.element.innerHTML = env.highlightedCode; | |
}); | |
// Wrap tokens in classes that are missing them | |
Prism.hooks.add('wrap', function(env) { | |
if (env.language === 'php' && env.type === 'markup') { | |
env.content = env.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g, "<span class=\"token php\">$1</span>"); | |
} | |
}); | |
// Add the rules before all others | |
Prism.languages.insertBefore('php', 'comment', { | |
'markup': { | |
pattern: /<[^?]\/?(.*?)>/g, | |
inside: Prism.languages.markup | |
}, | |
'php': /\{\{\{PHP[0-9]+\}\}\}/g | |
}); | |
} | |
; | |
(function(Prism) { | |
// Ignore comments starting with { to privilege string interpolation highlighting | |
var comment = /#(?!\{).+/g, | |
interpolation = { | |
pattern: /#\{[^}]+\}/g, | |
alias: 'variable' | |
}; | |
Prism.languages.coffeescript = Prism.languages.extend('javascript', { | |
'comment': comment, | |
'string': [ | |
// Strings are multiline | |
/'(?:\\?[\s\S])*?'/g, | |
{ | |
// Strings are multiline | |
pattern: /"(?:\\?[\s\S])*?"/g, | |
inside: { | |
'interpolation': interpolation | |
} | |
} | |
], | |
'keyword': /\b(and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/g, | |
'class-member': { | |
pattern: /@(?!\d)\w+/, | |
alias: 'variable' | |
} | |
}); | |
Prism.languages.insertBefore('coffeescript', 'comment', { | |
'multiline-comment': { | |
pattern: /###[\s\S]+?###/g, | |
alias: 'comment' | |
}, | |
// Block regexp can contain comments and interpolation | |
'block-regex': { | |
pattern: /\/{3}[\s\S]*?\/{3}/, | |
alias: 'regex', | |
inside: { | |
'comment': comment, | |
'interpolation': interpolation | |
} | |
} | |
}); | |
Prism.languages.insertBefore('coffeescript', 'string', { | |
'inline-javascript': { | |
pattern: /`(?:\\?[\s\S])*?`/g, | |
inside: { | |
'delimiter': { | |
pattern: /^`|`$/g, | |
alias: 'punctuation' | |
}, | |
rest: Prism.languages.javascript | |
} | |
}, | |
// Block strings | |
'multiline-string': [ | |
{ | |
pattern: /'''[\s\S]*?'''/, | |
alias: 'string' | |
}, | |
{ | |
pattern: /"""[\s\S]*?"""/, | |
alias: 'string', | |
inside: { | |
interpolation: interpolation | |
} | |
} | |
] | |
}); | |
Prism.languages.insertBefore('coffeescript', 'keyword', { | |
// Object property | |
'property': /(?!\d)\w+(?=\s*:(?!:))/g | |
}); | |
}(Prism));; | |
Prism.languages.scss = Prism.languages.extend('css', { | |
'comment': { | |
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g, | |
lookbehind: true | |
}, | |
// aturle is just the @***, not the entire rule (to highlight var & stuffs) | |
// + add ability to highlight number & unit for media queries | |
'atrule': /@[\w-]+(?=\s+(\(|\{|;))/gi, | |
// url, compassified | |
'url': /([-a-z]+-)*url(?=\()/gi, | |
// CSS selector regex is not appropriate for Sass | |
// since there can be lot more things (var, @ directive, nesting..) | |
// a selector must start at the end of a property or after a brace (end of other rules or nesting) | |
// it can contain some caracters that aren't used for defining rules or end of selector, & (parent selector), or interpolated variable | |
// the end of a selector is found when there is no rules in it ( {} or {\s}) or if there is a property (because an interpolated var | |
// can "pass" as a selector- e.g: proper#{$erty}) | |
// this one was ard to do, so please be careful if you edit this one 🙂 | |
'selector': /([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm | |
}); | |
Prism.languages.insertBefore('scss', 'atrule', { | |
'keyword': /@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i | |
}); | |
Prism.languages.insertBefore('scss', 'property', { | |
// var and interpolated vars | |
'variable': /((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i | |
}); | |
Prism.languages.insertBefore('scss', 'function', { | |
'placeholder': /%[-_\w]+/i, | |
'statement': /\B!(default|optional)\b/gi, | |
'boolean': /\b(true|false)\b/g, | |
'null': /\b(null)\b/g, | |
'operator': /\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|%)\s+/g | |
}); | |
; | |
Prism.languages.bash = Prism.languages.extend('clike', { | |
'comment': { | |
pattern: /(^|[^"{\\])(#.*?(\r?\n|$))/g, | |
lookbehind: true | |
}, | |
'string': { | |
//allow multiline string | |
pattern: /("|')(\\?[\s\S])*?\1/g, | |
inside: { | |
//'property' class reused for bash variables | |
'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g | |
} | |
}, | |
'keyword': /\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g | |
}); | |
Prism.languages.insertBefore('bash', 'keyword', { | |
//'property' class reused for bash variables | |
'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g | |
}); | |
Prism.languages.insertBefore('bash', 'comment', { | |
//shebang must be before comment, 'important' class from css reused | |
'important': /(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g | |
}); | |
Prism.languages.c = Prism.languages.extend('clike', { | |
// allow for c multiline strings | |
'string': /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g, | |
'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g, | |
'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g | |
}); | |
Prism.languages.insertBefore('c', 'string', { | |
// property class reused for macro statements | |
'property': { | |
// allow for multiline macro definitions | |
// spaces after the # character compile fine with gcc | |
pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi, | |
lookbehind: true, | |
inside: { | |
// highlight the path of the include statement as a string | |
'string': { | |
pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g, | |
lookbehind: true | |
} | |
} | |
} | |
}); | |
// prism-glsl : start | |
Prism.languages.glsl = Prism.languages.extend('clike', { | |
'string': /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g, | |
'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|vec2|vec3|vec4)\b/g, | |
'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g | |
}); | |
Prism.languages.insertBefore('glsl', 'string', { | |
// property class reused for macro statements | |
'property': { | |
// allow for multiline macro definitions | |
// spaces after the # character compile fine with gcc | |
pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi, | |
lookbehind: true, | |
inside: { | |
// highlight the path of the include statement as a string | |
'string': { | |
pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g, | |
lookbehind: true | |
} | |
} | |
} | |
}); | |
// prism-glsl : end | |
delete Prism.languages.c['class-name']; | |
delete Prism.languages.c['boolean'];; | |
Prism.languages.markdown = Prism.languages.extend('markup', {}); | |
Prism.languages.insertBefore('markdown', 'prolog', { | |
'blockquote': { | |
// > ... | |
pattern: /(^|\n)>(?:[\t ]*>)*/, | |
lookbehind: true, | |
alias: 'punctuation' | |
}, | |
'code': [ | |
{ | |
// Prefixed by 4 spaces or 1 tab | |
pattern: /(^|\n)(?: {4}|\t).+/, | |
lookbehind: true, | |
alias: 'keyword' | |
}, | |
{ | |
// `code` | |
// ``code`` | |
pattern: /``.+?``|`[^`\n]+`/, | |
alias: 'keyword' | |
} | |
], | |
'title': [ | |
{ | |
// title 1 | |
// ======= | |
// title 2 | |
// ------- | |
pattern: /\w+.*\n(?:==+|--+)/, | |
alias: 'important', | |
inside: { | |
punctuation: /==+$|--+$/ | |
} | |
}, | |
{ | |
// # title 1 | |
// ###### title 6 | |
pattern: /((?:^|\n)\s*)#+.+/, | |
lookbehind: true, | |
alias: 'important', | |
inside: { | |
punctuation: /^#+|#+$/ | |
} | |
} | |
], | |
'hr': { | |
// *** | |
// --- | |
// * * * | |
// ----------- | |
pattern: /((?:^|\n)\s*)([*-])([\t ]*\2){2,}(?=\s*(?:\n|$))/, | |
lookbehind: true, | |
alias: 'punctuation' | |
}, | |
'list': { | |
// * item | |
// + item | |
// - item | |
// 1. item | |
pattern: /((?:^|\n)\s*)(?:[*+-]|\d+\.)(?=[\t ].)/, | |
lookbehind: true, | |
alias: 'punctuation' | |
}, | |
'url-reference': { | |
// [id]: http://example.com "Optional title" | |
// [id]: http://example.com 'Optional title' | |
// [id]: http://example.com (Optional title) | |
// [id]: <http://example.com> "Optional title" | |
pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:[^>]|\\>)+>)(?:[\t ]+(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\)))?/, | |
inside: { | |
'variable': { | |
pattern: /^(!?\[)[^\]]+/, | |
lookbehind: true | |
}, | |
'string': /(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\))$/, | |
'punctuation': /[[\]\(\)<>:]/ | |
}, | |
alias: 'url' | |
}, | |
'bold': { | |
// **strong** | |
// __strong__ | |
// Allow only one line break | |
pattern: /(^|[^\\])(\*\*|__)(?:\n(?!\n)|.)+?\2/, | |
lookbehind: true, | |
inside: { | |
'punctuation': /^\*\*|^__|\*\*\s*$|__\s*$/ | |
} | |
}, | |
'italic': { | |
// *em* | |
// _em_ | |
// Allow only one line break | |
pattern: /(^|[^\\])(?:\*(?:\n(?!\n)|.)+?\*|_(?:\n(?!\n)|.)+?_)/, | |
lookbehind: true, | |
inside: { | |
'punctuation': /^[*_]|[*_]$/ | |
} | |
}, | |
'url': { | |
// [example](http://example.com "Optional title") | |
// [example] [id] | |
pattern: /!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:[^"]|\\")*")?\)| ?\[[^\]\n]*\])/, | |
inside: { | |
'variable': { | |
pattern: /(!?\[)[^\]]+(?=\]$)/, | |
lookbehind: true | |
}, | |
'string': { | |
pattern: /"(?:[^"]|\\")*"(?=\)$)/ | |
} | |
} | |
} | |
}); | |
Prism.languages.markdown['bold'].inside['url'] = Prism.util.clone(Prism.languages.markdown['url']); | |
Prism.languages.markdown['italic'].inside['url'] = Prism.util.clone(Prism.languages.markdown['url']); | |
Prism.languages.markdown['bold'].inside['italic'] = Prism.util.clone(Prism.languages.markdown['italic']); | |
Prism.languages.markdown['italic'].inside['bold'] = Prism.util.clone(Prism.languages.markdown['bold']);; | |
(function(){ | |
if(!window.Prism) { | |
return; | |
} | |
for (var language in Prism.languages) { | |
var tokens = Prism.languages[language]; | |
tokens.tab = /\t/g; | |
tokens.crlf = /\r\n/g; | |
tokens.lf = /\n/g; | |
tokens.cr = /\r/g; | |
} | |
})(); | |
; | |
(function(){ | |
if (!self.Prism) { | |
return; | |
} | |
var Languages = { | |
'csharp': 'C#', | |
'cpp': 'C++' | |
}; | |
Prism.hooks.add('before-highlight', function(env) { | |
var language = Languages[env.language] || env.language; | |
env.element.setAttribute('data-language', language); | |
}); | |
})(); | |
; |
<pre><code class="language-glsl">
code..
</code></pre>
구문이 잘 동작하는지 확인한다.