// ==UserScript==
// @name Blogger Hatena Syntax
// @namespace http://d.hatena.ne.jp/edvakf/
// @description Hatena syntax and code highlight for blogger
// @include http://www.blogger.com/post-create.g*
// @include http://www.blogger.com/post-edit.g*
// ==/UserScript==
//
// Copyright (C) 2010 edvakf
//
// The JavaScript code in this page is free software: you can
// redistribute it and/or modify it under the terms of the GNU
// General Public License (GNU GPL) as published by the Free Software
// Foundation, either version 3 of the License, or (at your option)
// any later version. The code is distributed WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
//
// As additional permission under GNU GPL version 3 section 7, you
// may distribute non-source (e.g., minimized or compacted) forms of
// that code without the copy of the GNU GPL normally required by
// section 4, provided you include this license notice and a URL
// through which recipients can access the Corresponding Source.
//
// This script makes use of:
// text-hatena.js
// http://tech.nitoyon.com/javascript/application/texthatena/download.html
// SHJS
// http://shjs.sourceforge.net/
//
// Syntax-highlightable languages:
// C (c), C++ (cpp), CSS (css), diff (diff), HTML (html), Java (java),
// JavaScript (javascript), Perl (perl), PHP (php), Python (python),
// Ruby (ruby), Scala (scala), Shell Script (sh), SQL (sql), XML (xml)
// main part
setTimeout(function() {
if (window.top !== window.self) return;
var box = document.getElementById("body");
var ta = document.getElementById("textarea");
var editor = document.createElement("textarea");
editor.setAttribute('style', [
'display:block;',
'float:left;',
'width:45%;',
'padding:0 0 0 5px;',
'minimum-height:300px;'
].join(''));
var preview = document.createElement("div");
preview.setAttribute('style', [
'float:right;',
'width:50%;',
'border:solid black 1px;',
'padding:5px;',
'minimum-height:300px;'
].join(''));
box.appendChild(editor);
box.appendChild(preview);
var sectionanchor = '\u25a0';
var hatena = new Hatena({sectionanchor: sectionanchor});
var m;
if (m = ta.value.match(/\n/)) {
setTimeout(function() { // to let variables below be defined
editor.value = m[1].replace(
/\{\{(\d+) hyphens\}\}/g,
function($0,$1) {return String.times('-', +$1);}
);
seePreview();
resize(editor);
}, 10);
}
var timer;
editor.addEventListener('input', function() {
resize(editor);
timer = clearTimeout(timer);
timer = setTimeout(seePreview, 500);
}, false);
function seePreview() {
hatena.parse(editor.value);
preview.innerHTML = hatena.html();
Array.prototype.forEach.call(
preview.getElementsByTagName("pre"),
function(pre) {
if ((m = pre.className.match(/sh_(\S*)/)) && sh_languages[m[1]]) {
sh_highlightElement(pre, sh_languages[m[1]]);
}
}
);
replaceTitles();
setTextArea();
fetchTitles();
}
function setTextArea() {
var clone = preview.cloneNode(true);
var h3 = clone.firstChild.firstElementChild;
if (h3 && /h3/i.test(h3.nodeName)) {
document.getElementById('f-title').value = h3.textContent.replace(sectionanchor, '');
h3.parentNode.removeChild(h3);
}
ta.value = clone.innerHTML + "\n";
}
function resize(el) {
var es = el.style;
var sh = el.scrollHeight;
var paddingTopAndBottom = 0 + 0;
if (this.opera) {
// http://orera.g.hatena.ne.jp/misttrap/20090825/p1
es.minHeight = sh + 'px';
var diff = sh + paddingTopAndBottom - el.clientHeight
if (diff > 0) es.minHeight = sh + diff + 'px';
} else {
// http://d.hatena.ne.jp/javascripter/20090311/1236779096
es.height = '0px';
es.height = sh - paddingTopAndBottom + 'px';
}
}
var script = document.createElement('script');
script.textContent = [ // run in page's context. works for Greasemonkey & Chrome
,"function fireMyEvent(o) {"
,"if (o.error) return;"
,"var url = o.query.diagnostics.url;"
,"url = url.content || url[url.length - 1].content;"
,"var title = o.query.results;"
,"if (window.opera) {"
,"var ev = document.createEvent('Event');"
,"ev.initEvent('TitleReady', true, false);"
,"ev.url = url;"
,"ev.title = title;"
,"} else {"
,"var ev = document.createEvent('MessageEvent');"
,"ev.initMessageEvent('TitleReady', true, false," // type, canBubble, cancelable
,"JSON.stringify({url: url, title: title})," // data
,"location.protocol + '//' + location.host," // origin
,"''," // lastEventId
,"window" // source
,");"
,"}"
,"document.dispatchEvent(ev);"
,"}"
].join('\n');
document.body.appendChild(script);
var URL2TITLE = {};
document.addEventListener('TitleReady', function(ev) {
var data = ev.data ? JSON.parse(ev.data) : ev;
URL2TITLE[data.url] = data.title || null;
replaceTitles();
setTextArea();
}, false);
function replaceTitles() {
Array.prototype.forEach.call(
preview.getElementsByTagName('a'),
function(a) {
if (a.textContent === '{{title}}') {
var title = URL2TITLE[a.href];
if (title === void 0) {
// title must be fetched
} else if (title === null) {
a.textContent = a.href;
} else if (title === '') {
// JSONP not loaded yet
} else {
a.textContent = title;
var grandpa = a.parentNode.parentNode;
if (/blockquote/i.test(grandpa.tagName) &&
grandpa.getAttribute('title') === '{{title}}')
grandpa.setAttribute('title', title);
}
}
}
);
}
function fetchTitles() {
Array.prototype.forEach.call(
preview.getElementsByTagName('a'),
function(a) {
var url = a.href;
if (a.textContent === '{{title}}' && URL2TITLE[url] === void 0) {
URL2TITLE[url] = '';
var api = "http://query.yahooapis.com/v1/public/yql" +
"?format=json&callback=fireMyEvent&q=select%20*%20from%20html%20where%20url%3d'" +
encodeURIComponent(url) + "'%20and%20xpath%3d'%2f%2ftitle%2ftext()'";
var script = document.createElement('script');
script.src = api;
document.body.appendChild(script);
}
}
);
}
}, 10);
/*
* http://tech.nitoyon.com/javascript/application/texthatena/text-hatena0-2.js
* modified by edvakf
*/
// from prototype.js
Object.extend = function(destination, source) {
for (property in source) {
destination[property] = source[property];
}
return destination;
}
String.times = function(str, time){
var s = "";
for(var i = 0; i < time; i++)s += str;
return s;
}
String._escapeHTML = function(s){
s = s.replace(/\&/g, "&");
s = s.replace(//g, ">");
s = s.replace(/"/g, """);
s = s.replace(/\'/g, "'");
s = s.replace(/\\/g, "\");
return s;
}
String._unescapeHTML = function(s){
s = s.replace(/&/g, "&");
s = s.replace(/</g, "<");
s = s.replace(/>/g, ">");
s = s.replace(/"/g, "\"");
return s;
}
// Hatena::Hatena_HTMLFilter
Hatena_HTMLFilter = function(args){
this.self = {
context : args["context"],
html : ''
};
this.init();
}
Hatena_HTMLFilter.prototype = {
init :function(){
// HTML::Parser を利用すべきなんだけど JavaScript ではなんとも...
},
parse : function(html){
var c = this.self.context;
this.self.html = c.self.texthandler(html, c);
},
html : function(){
return this.self.html;
}
}
// Hatena
Hatena = function(args){
if(args == null) args = {};
this.self = {
html : '',
baseuri : args["baseuri"],
permalink : args["permalink"] || "",
ilevel : args["ilevel"] || 0,
invalidnode : args["invalidnode"] || [],
sectionanchor : args["sectionanchor"] || 'o-',
texthandler : args["texthandler"] || function(text, c){
// footnote
var p = c.self.permalink;
var html = "";
var foot = text.split("((");
for(var i = 0; i < foot.length; i++){
if(i == 0){
html += foot[i];
continue;
}
var s = foot[i].split("))", 2);
if(s.length != 2){
html += "((" + foot[i];
continue;
}
var pre = foot[i - i];
var note = s[0];
var post = foot[i].substr(s[0].length + 2);
if(pre.match(/\)$/) && post.match(/^\(/)){
html += "((" + post;
} else {
var notes = c.footnotes(note);
var num = notes.length;
note = note.replace(/<.*?>/g, "");
note = note.replace(/&/g, "&");
html += '*' + num + '' + post;
}
}
// auto link (added by edvakf)
html = html.replace(/\[(https?:\/\/[^\]\s]+?)(:title(=[^\]\n]*)?)?\]/g, function($0,$1,$2,$3) {
return '' + (
$3 ? String._escapeHTML($3.slice(1)) : // title given by user
$2 ? '{{title}}' : // title will be fetched (via YQL)
$1 // use URL instead of title
) + '';
});
return html;
}
};
}
Hatena.prototype = {
parse : function(text){
this.self.context = new Hatena_Context({
text : text || "",
baseuri : this.self.baseuri,
permalink : this.self.permalink,
invalidnode : this.self.invalidnode,
sectionanchor : this.self.sectionanchor,
texthandler : this.self.texthandler
});
var c = this.self.context;
var node = new Hatena_BodyNode();
node._new({
context : c,
ilevel : this.self.ilevel
});
node.parse();
var parser = new Hatena_HTMLFilter({
context : c
});
parser.parse(c.html());
this.self.html = parser.html();
if (this.self.context.footnotes().length != 0) {
var node = new Hatena_FootnoteNode();
node._new({
context : this.self.context,
ilevel : this.self.ilevel
});
node.parse();
this.self.html += "\n";
this.self.html += node.self.html;
}
},
html : function(){
return this.self.html;
}
}
// Hatena::Context
Hatena_Context = function(args){
this.self = {
text : args["text"],
baseuri : args["baseuri"],
permalink : args["permalink"],
invalidnode : args["invalidnode"],
sectionanchor : args["sectionanchor"],
texthandler : args["texthandler"],
_htmllines : [],
footnotes : Array(),
sectioncount : 0,
syntaxrefs : [],
noparagraph : 0
};
this.init();
}
Hatena_Context.prototype = {
init : function() {
this.self.text = this.self.text.replace(/\r/g, "");
this.self.lines = this.self.text.split('\n');
this.self.index = -1;
},
hasnext : function() {
return (this.self.lines != null && this.self.lines.length - 1 > this.self.index);
},
nextline : function() {
return this.self.lines[this.self.index + 1];
},
shiftline : function() {
return this.self.lines[++this.self.index];
},
currentline : function() {
return this.self.lines[this.self.index];
},
html : function() {
return this.self._htmllines.join ("\n");
},
htmllines : function(line) {
if(line != null) this.self._htmllines.push(line);
return this.self._htmllines;
},
lasthtmlline : function() {return this.self._htmllines[this.self._htmllines.length - 1]; },
footnotes : function(line) {
if(line != null) this.self.footnotes.push(line);
return this.self.footnotes;
},
syntaxrefs : function(line) {
if(line != null) this.self.syntaxrefs.push(line);
return this.self.syntaxrefs;
},
syntaxpattern : function(pattern) {
if(pattern != null) this.self.syntaxpattern = pattern;
return this.self.syntaxpattern;
},
noparagraph : function(noparagraph) {
if(noparagraph != null) this.self.noparagraph = noparagraph;
return this.self.noparagraph;
},
incrementsection : function() {
return this.self.sectioncount++;
}
}
// Hatena::Node
Hatena_Node = function(){}
Hatena_Node.prototype = {
html : "",
pattern : "",
_new : function(args){
if(args == null) args = Array();
this.self = {
context : args["context"],
ilevel : args["ilevel"],
html : ''
};
this.init();
},
init : function(){
this.self.pattern = '';
},
parse : function(){ alert('die'); },
context : function(v){
this.self.context = v;
}
};
// Hatena::BodyNode
Hatena_BodyNode = function(){};
Hatena_BodyNode.prototype = Object.extend(new Hatena_Node(), {
parse : function(){
var c = this.self.context;
while (this.self.context.hasnext()) {
var node = new Hatena_SectionNode();
node._new({
context : c,
ilevel : this.self.ilevel
});
node.parse();
}
}
})
// Hatena::BrNode
Hatena_BrNode = function(){};
Hatena_BrNode.prototype = Object.extend(new Hatena_Node(), {
parse : function(){
var c = this.self.context;
var l = c.shiftline();
if(l.length != 0) return;
var t = String.times("\t", this.self.ilevel);
if (c.lasthtmlline() == t + "
" || c.lasthtmlline() == t) {
c.htmllines(t + "
");
} else {
c.htmllines(t);
}
}
})
// Hatena::CDataNode
Hatena_CDataNode = function(){};
Hatena_CDataNode.prototype = Object.extend(new Hatena_Node(), {
parse : function(){
var c = this.self.context;
var t = String.times("\t", this.self.ilevel);
var l = c.shiftline();
var text = new Hatena_Text();
text._new({context : c});
text.parse(l);
l = text.html();
c.htmllines(t + l);
}
})
// Hatena::DlNode
Hatena_DlNode = function(){};
Hatena_DlNode.prototype = Object.extend(new Hatena_Node(), {
init : function(){
this.self.pattern = /^\:((?:<[^>]+>|\[\].+?\[\]|\[[^\]]+\]|\[\]|[^\:<\[]+)+)\:(.+)$/;
},
parse : function(){
var c = this.self.context;
var l = c.nextline();
if(!l.match(this.self.pattern)) return;
this.self.llevel = RegExp.$1.length;
var t = String.times("\t", this.self.ilevel);
c.htmllines(t + "
*' + num + ': ' + text.html() + '
'; this.self["html"] += l + "\n"; } this.self["html"] += t + '" + l + "
"); } }); // Hatena::PreNode Hatena_PreNode = function(){}; Hatena_PreNode.prototype = Object.extend(new Hatena_Node(), { init :function(){ this.self.pattern = /^>\|$/; this.self.endpattern = /(.*)\|<$/; this.self.startstring = ""; this.self.endstring = ""; }, parse : function(){ // modified by edvakf var c = this.self.context; var m; if(!(m = c.nextline().match(this.self.pattern))) return; c.shiftline(); var t = String.times("\t", this.self.ilevel); c.htmllines(t + (m[1] ? // add class for syntax highlight this.self.startstring.replace('>',' class="sh_' + m[1] + '">') : this.self.startstring)); var x = ''; while (c.hasnext()) { var l = c.nextline(); if (l.match(this.self.endpattern)) { var x = RegExp.$1; c.shiftline(); break; } c.htmllines(this.escape_pre(c.shiftline())); } c.htmllines(x + this.self.endstring); }, escape_pre : function(text){ return text; } }) // Hatena::SuperpreNode Hatena_SuperpreNode = function(){}; Hatena_SuperpreNode.prototype = Object.extend(new Hatena_PreNode(), { init : function(){ this.self.pattern = /^>\|(\S*)\|$/; // modified by edvakf this.self.endpattern = /^\|\|<$/; this.self.startstring = "
"; this.self.endstring = ""; }, escape_pre : function(s){ return String._escapeHTML(s); } }) // Hatena::SuperpreNode Hatena_TableNode = function(){}; Hatena_TableNode.prototype = Object.extend(new Hatena_Node(), { init : function(){ this.self.pattern = /^\|([^\|]*\|(?:[^\|]*\|)+)$/; }, parse : function(s){ var c = this.self.context; var l = c.nextline(); if(!l.match(this.self.pattern)) return; var t = String.times("\t", this.self.ilevel); c.htmllines(t + "
" + RegExp.$1 + " | "); } else { c.htmllines(t + "\t\t" + item + " | "); } } c.htmllines(t + "\t
---|
"; this.self.endstring = ""; this.self.child_node_refs = Array(); }, parse : function(){ var c = this.self.context; var m; if(!(m = c.nextline().match(this.self.pattern))) return; if (m[1]) { // m[1] is the url (added by edvakf) var title = String._escapeHTML(m[3] ? m[3].substr(1) : // if title given, then use it m[2] ? '{{title}}' : // else if title not given, fetch from YQL m[1]); // else, use URL this.self.startstring = this.self.startstring.replace('>', ' cite="' + m[1] + '" title="' + title + '">'); var cite = '' + title + ''; } else { var cite = ''; } c.shiftline(); var t = String.times("\t", this.self.ilevel); this._set_child_node_refs(); c.htmllines(t + this.self.startstring); while (c.hasnext()) { var l = c.nextline(); if (l.match(this.self.endpattern)) { c.shiftline(); break; } var node = this._findnode(l); if(node == null) break; node.parse(); } c.htmllines(t + cite + this.self.endstring); } }) // Hatena::TagNode Hatena_TagNode = function(){}; Hatena_TagNode.prototype = Object.extend(new Hatena_SectionNode(), { init : function(){ this.self.pattern = /^>(<.*)$/; this.self.endpattern = /^(.*>)<$/; this.self.childnode = ["h4", "h5", "blockquote", "dl", "list", "pre", "superpre", "table"]; this.self.child_node_refs = Array(); }, parse : function(){ var c = this.self.context; var t = String.times("\t", this.self.ilevel); if(!c.nextline().match(this.self.pattern)) return; c.shiftline(); c.noparagraph(1); this._set_child_node_refs(); var x =this._parse_text(RegExp.$1); c.htmllines(t + x); while (c.hasnext()) { var l = c.nextline(); if (l.match(this.self.endpattern)) { c.shiftline(); x = this._parse_text(RegExp.$1); c.htmllines(t + x); break; } var node = this._findnode(l); if(node == null) break; node.parse(); } c.noparagraph(0); }, _parse_text : function(l){ var text = new Hatena_Text(); text._new({context : this.self.context}); text.parse(l); return text.html(); } }) // Hatena::TaglineNode Hatena_TaglineNode = function(){}; Hatena_TaglineNode.prototype = Object.extend(new Hatena_SectionNode(), { init : function(){ this.self.pattern = /^>(<.*>)<$/; this.self.child_node_refs = Array(); }, parse : function(){ var c = this.self.context; var t = String.times("\t", this.self.ilevel); if(!c.nextline().match(this.self.pattern)) return; c.shiftline(); c.htmllines(t + RegExp.$1); } }) // Hatena::Text Hatena_Text = function(){} Hatena_Text.prototype = { _new : function(args){ this.self = { context : args["context"], html : '' }; }, parse : function(text){ this.self.html = ''; if(text == null) return; this.self.html = text; }, html : function(){return this.self.html;} } /*var h = new Hatena(); h.parse("hoge((a))aaa))aaaa\n>hoge
element containing the source code to be highlighted @param language a language definition object */ function sh_highlightElement(element, language) { sh_addClass(element, 'sh_sourceCode'); var originalTags = []; var inputString = sh_extractTags(element, originalTags); var highlightTags = sh_highlightString(inputString, language); var tags = sh_mergeTags(originalTags, highlightTags); var documentFragment = sh_insertTags(tags, inputString); while (element.hasChildNodes()) { element.removeChild(element.firstChild); } element.appendChild(documentFragment); } /* function sh_getXMLHttpRequest() { if (window.ActiveXObject) { return new ActiveXObject('Msxml2.XMLHTTP'); } else if (window.XMLHttpRequest) { return new XMLHttpRequest(); } throw 'No XMLHttpRequest implementation available'; } function sh_load(language, element, prefix, suffix) { if (language in sh_requests) { sh_requests[language].push(element); return; } sh_requests[language] = [element]; var request = sh_getXMLHttpRequest(); var url = prefix + 'sh_' + language + suffix; request.open('GET', url, true); request.onreadystatechange = function () { if (request.readyState === 4) { try { if (! request.status || request.status === 200) { eval(request.responseText); var elements = sh_requests[language]; for (var i = 0; i < elements.length; i++) { sh_highlightElement(elements[i], sh_languages[language]); } } else { throw 'HTTP error: status ' + request.status; } } finally { request = null; } } }; request.send(null); } */ /** Highlights all elements containing source code on the current page. Elements containing source code must be "pre" elements with a "class" attribute of "sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java" identifies the element as containing "java" language source code. */ /* function sh_highlightDocument(prefix, suffix) { var nodeList = document.getElementsByTagName('pre'); for (var i = 0; i < nodeList.length; i++) { var element = nodeList.item(i); var htmlClasses = sh_getClasses(element); for (var j = 0; j < htmlClasses.length; j++) { var htmlClass = htmlClasses[j].toLowerCase(); if (htmlClass === 'sh_sourcecode') { continue; } if (htmlClass.substr(0, 3) === 'sh_') { var language = htmlClass.substring(3); if (language in sh_languages) { sh_highlightElement(element, sh_languages[language]); } else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') { sh_load(language, element, prefix, suffix); } else { throw 'Foundelement with class="' + htmlClass + '", but no such language exists'; } break; } } } } */ if (! this.sh_languages) { this.sh_languages = {}; } sh_languages['c'] = [ [ [ /\/\/\//g, 'sh_comment', 1 ], [ /\/\//g, 'sh_comment', 7 ], [ /\/\*\*/g, 'sh_comment', 8 ], [ /\/\*/g, 'sh_comment', 9 ], [ /(\bstruct)([ \t]+)([A-Za-z0-9_]+)/g, ['sh_keyword', 'sh_normal', 'sh_classname'], -1 ], [ /^[ \t]*#(?:[ \t]*include)/g, 'sh_preproc', 10, 1 ], [ /^[ \t]*#(?:[ \t]*[A-Za-z0-9_]*)/g, 'sh_preproc', -1 ], [ /\b[+-]?(?:(?:0x[A-Fa-f0-9]+)|(?:(?:[\d]*\.)?[\d]+(?:[eE][+-]?[\d]+)?))u?(?:(?:int(?:8|16|32|64))|L)?\b/g, 'sh_number', -1 ], [ /"/g, 'sh_string', 13 ], [ /'/g, 'sh_string', 14 ], [ /\b(?:__asm|__cdecl|__declspec|__export|__far16|__fastcall|__fortran|__import|__pascal|__rtti|__stdcall|_asm|_cdecl|__except|_export|_far16|_fastcall|__finally|_fortran|_import|_pascal|_stdcall|__thread|__try|asm|auto|break|case|catch|cdecl|const|continue|default|do|else|enum|extern|for|goto|if|pascal|register|return|sizeof|static|struct|switch|typedef|union|volatile|while)\b/g, 'sh_keyword', -1 ], [ /\b(?:bool|char|double|float|int|long|short|signed|unsigned|void|wchar_t)\b/g, 'sh_type', -1 ], [ /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|:|;|,|\.|\/|\?|&|<|>|\|/g, 'sh_symbol', -1 ], [ /\{|\}/g, 'sh_cbracket', -1 ], [ /(?:[A-Za-z]|_)[A-Za-z0-9_]*(?=[ \t]*\()/g, 'sh_function', -1 ], [ /([A-Za-z](?:[^`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\s]|[_])*)((?:<.*>)?)(\s+(?=[*&]*[A-Za-z][^`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\s]*\s*[`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\[\]]+))/g, ['sh_usertype', 'sh_usertype', 'sh_normal'], -1 ] ], [ [ /$/g, null, -2 ], [ /(?:)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g, 'sh_url', -1 ], [ /<\?xml/g, 'sh_preproc', 2, 1 ], [ //g, 'sh_keyword', -1 ], [ /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g, 'sh_keyword', 6, 1 ], [ /&(?:[A-Za-z0-9]+);/g, 'sh_preproc', -1 ], [ /<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g, 'sh_keyword', -1 ], [ /<(?:\/)?[A-Za-z][A-Za-z0-9]*/g, 'sh_keyword', 6, 1 ], [ /@[A-Za-z]+/g, 'sh_type', -1 ], [ /(?:TODO|FIXME|BUG)(?:[:]?)/g, 'sh_todo', -1 ] ], [ [ /\?>/g, 'sh_preproc', -2 ], [ /([^=" \t>]+)([ \t]*)(=?)/g, ['sh_type', 'sh_normal', 'sh_symbol'], -1 ], [ /"/g, 'sh_string', 3 ] ], [ [ /\\(?:\\|")/g, null, -1 ], [ /"/g, 'sh_string', -2 ] ], [ [ />/g, 'sh_preproc', -2 ], [ /([^=" \t>]+)([ \t]*)(=?)/g, ['sh_type', 'sh_normal', 'sh_symbol'], -1 ], [ /"/g, 'sh_string', 3 ] ], [ [ /-->/g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ //g, 'sh_comment', -2 ], [ /