##// END OF EJS Templates
default application logger shouldn't propagate...
default application logger shouldn't propagate avoids annoying duplicate messages on the root logger under some circumstances. If apps want to hook up their own logging, they should assign the log attribute.

File last commit:

r8053:58574fbf
r10203:e2932e09
Show More
tiddlywiki.js
384 lines | 9.3 KiB | application/javascript | JavascriptLexer
/***
|''Name''|tiddlywiki.js|
|''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|
|''Author''|PMario|
|''Version''|0.1.7|
|''Status''|''stable''|
|''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
|''Documentation''|http://codemirror.tiddlyspace.com/|
|''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|codemirror.js|
|''Keywords''|syntax highlighting color code mirror codemirror|
! Info
CoreVersion parameter is needed for TiddlyWiki only!
***/
//{{{
CodeMirror.defineMode("tiddlywiki", function (config, parserConfig) {
var indentUnit = config.indentUnit;
// Tokenizer
var textwords = function () {
function kw(type) {
return {
type: type,
style: "text"
};
}
return {};
}();
var keywords = function () {
function kw(type) {
return { type: type, style: "macro"};
}
return {
"allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
"newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
"permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
"search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'),
"tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'),
"tiddler": kw('tiddler'), "timeline": kw('timeline'),
"today": kw('today'), "version": kw('version'), "option": kw('option'),
"with": kw('with'),
"filter": kw('filter')
};
}();
var isSpaceName = /[\w_\-]/i,
reHR = /^\-\-\-\-+$/, // <hr>
reWikiCommentStart = /^\/\*\*\*$/, // /***
reWikiCommentStop = /^\*\*\*\/$/, // ***/
reBlockQuote = /^<<<$/,
reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start
reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop
reXmlCodeStart = /^<!--\{\{\{-->$/, // xml block start
reXmlCodeStop = /^<!--\}\}\}-->$/, // xml stop
reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start
reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop
reCodeStart = /\{\{\{/, // {{{ code span start
reUntilCodeStop = /.*?\}\}\}/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
// used for strings
function nextUntilUnescaped(stream, end) {
var escaped = false,
next;
while ((next = stream.next()) != null) {
if (next == end && !escaped) return false;
escaped = !escaped && next == "\\";
}
return escaped;
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp;
content = cont;
return style;
}
function jsTokenBase(stream, state) {
var sol = stream.sol(),
ch, tch;
state.block = false; // indicates the start of a code block.
ch = stream.peek(); // don't eat, to make matching simpler
// check start of blocks
if (sol && /[<\/\*{}\-]/.test(ch)) {
if (stream.match(reCodeBlockStart)) {
state.block = true;
return chain(stream, state, twTokenCode);
}
if (stream.match(reBlockQuote)) {
return ret('quote', 'quote');
}
if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
return ret('code', 'comment');
}
if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
return ret('code', 'comment');
}
if (stream.match(reHR)) {
return ret('hr', 'hr');
}
} // sol
ch = stream.next();
if (sol && /[\/\*!#;:>|]/.test(ch)) {
if (ch == "!") { // tw header
stream.skipToEnd();
return ret("header", "header");
}
if (ch == "*") { // tw list
stream.eatWhile('*');
return ret("list", "comment");
}
if (ch == "#") { // tw numbered list
stream.eatWhile('#');
return ret("list", "comment");
}
if (ch == ";") { // definition list, term
stream.eatWhile(';');
return ret("list", "comment");
}
if (ch == ":") { // definition list, description
stream.eatWhile(':');
return ret("list", "comment");
}
if (ch == ">") { // single line quote
stream.eatWhile(">");
return ret("quote", "quote");
}
if (ch == '|') {
return ret('table', 'header');
}
}
if (ch == '{' && stream.match(/\{\{/)) {
return chain(stream, state, twTokenCode);
}
// rudimentary html:// file:// link matching. TW knows much more ...
if (/[hf]/i.test(ch)) {
if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
return ret("link", "link");
}
}
// just a little string indicator, don't want to have the whole string covered
if (ch == '"') {
return ret('string', 'string');
}
if (ch == '~') { // _no_ CamelCase indicator should be bold
return ret('text', 'brace');
}
if (/[\[\]]/.test(ch)) { // check for [[..]]
if (stream.peek() == ch) {
stream.next();
return ret('brace', 'brace');
}
}
if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
stream.eatWhile(isSpaceName);
return ret("link", "link");
}
if (/\d/.test(ch)) { // numbers
stream.eatWhile(/\d/);
return ret("number", "number");
}
if (ch == "/") { // tw invisible comment
if (stream.eat("%")) {
return chain(stream, state, twTokenComment);
}
else if (stream.eat("/")) { //
return chain(stream, state, twTokenEm);
}
}
if (ch == "_") { // tw underline
if (stream.eat("_")) {
return chain(stream, state, twTokenUnderline);
}
}
// strikethrough and mdash handling
if (ch == "-") {
if (stream.eat("-")) {
// if strikethrough looks ugly, change CSS.
if (stream.peek() != ' ')
return chain(stream, state, twTokenStrike);
// mdash
if (stream.peek() == ' ')
return ret('text', 'brace');
}
}
if (ch == "'") { // tw bold
if (stream.eat("'")) {
return chain(stream, state, twTokenStrong);
}
}
if (ch == "<") { // tw macro
if (stream.eat("<")) {
return chain(stream, state, twTokenMacro);
}
}
else {
return ret(ch);
}
// core macro handling
stream.eatWhile(/[\w\$_]/);
var word = stream.current(),
known = textwords.propertyIsEnumerable(word) && textwords[word];
return known ? ret(known.type, known.style, word) : ret("text", null, word);
} // jsTokenBase()
function twTokenString(quote) {
return function (stream, state) {
if (!nextUntilUnescaped(stream, quote)) state.tokenize = jsTokenBase;
return ret("string", "string");
};
}
// tw invisible comment
function twTokenComment(stream, state) {
var maybeEnd = false,
ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "%");
}
return ret("comment", "comment");
}
// tw strong / bold
function twTokenStrong(stream, state) {
var maybeEnd = false,
ch;
while (ch = stream.next()) {
if (ch == "'" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "'");
}
return ret("text", "strong");
}
// tw code
function twTokenCode(stream, state) {
var ch, sb = state.block;
if (sb && stream.current()) {
return ret("code", "comment");
}
if (!sb && stream.match(reUntilCodeStop)) {
state.tokenize = jsTokenBase;
return ret("code", "comment");
}
if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
state.tokenize = jsTokenBase;
return ret("code", "comment");
}
ch = stream.next();
return (sb) ? ret("code", "comment") : ret("code", "comment");
}
// tw em / italic
function twTokenEm(stream, state) {
var maybeEnd = false,
ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "/");
}
return ret("text", "em");
}
// tw underlined text
function twTokenUnderline(stream, state) {
var maybeEnd = false,
ch;
while (ch = stream.next()) {
if (ch == "_" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "_");
}
return ret("text", "underlined");
}
// tw strike through text looks ugly
// change CSS if needed
function twTokenStrike(stream, state) {
var maybeEnd = false,
ch, nr;
while (ch = stream.next()) {
if (ch == "-" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "-");
}
return ret("text", "strikethrough");
}
// macro
function twTokenMacro(stream, state) {
var ch, tmp, word, known;
if (stream.current() == '<<') {
return ret('brace', 'macro');
}
ch = stream.next();
if (!ch) {
state.tokenize = jsTokenBase;
return ret(ch);
}
if (ch == ">") {
if (stream.peek() == '>') {
stream.next();
state.tokenize = jsTokenBase;
return ret("brace", "macro");
}
}
stream.eatWhile(/[\w\$_]/);
word = stream.current();
known = keywords.propertyIsEnumerable(word) && keywords[word];
if (known) {
return ret(known.type, known.style, word);
}
else {
return ret("macro", null, word);
}
}
// Interface
return {
startState: function (basecolumn) {
return {
tokenize: jsTokenBase,
indented: 0,
level: 0
};
},
token: function (stream, state) {
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
return style;
},
electricChars: ""
};
});
CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
//}}}