##// END OF EJS Templates
Decoupling the celltoolbar select UI from CellToolbar....
Decoupling the celltoolbar select UI from CellToolbar. The select menu for celltoolbar presets should live entirely in the maintoolbar code - it was 1/2 in CellToolbar itself. This fixes this issue using events and an additional method on CellToolbar (list_presets).

File last commit:

r8053:58574fbf
r9146:10bda596
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");
//}}}