define([ 'cm/lib/codemirror', 'cm/addon/mode/simple' ], function (CodeMirror) { CodeMirror.__mode = 'orgmode'; CodeMirror.defineSimpleMode("orgmode", { start: [ {regex: /(\*\s)(TODO|DOING|WAITING|NEXT|PENDING|)(CANCELLED|CANCELED|CANCEL|DONE|REJECTED|STOP|STOPPED|)(\s+\[\#[A-C]\]\s+|)(.*?)(?:(\s{10,}|))(\:[\S]+\:|)$/, sol: true, token: ["header level1 org-level-star","header level1 org-todo","header level1 org-done", "header level1 org-priority", "header level1", "header level1 void", "header level1 comment"]}, {regex: /(\*{1,}\s)(TODO|DOING|WAITING|NEXT|PENDING|)(CANCELLED|CANCELED|CANCEL|DEFERRED|DONE|REJECTED|STOP|STOPPED|)(\s+\[\#[A-C]\]\s+|)(.*?)(?:(\s{10,}|))(\:[\S]+\:|)$/, sol: true, token: ["header org-level-star","header org-todo","header org-done", "header org-priority", "header", "header void", "header comment"]}, {regex: /(\+[^\+]+\+)/, token: ["strikethrough"]}, {regex: /(\*[^\*]+\*)/, token: ["strong"]}, {regex: /(\/[^\/]+\/)/, token: ["em"]}, {regex: /(\_[^\_]+\_)/, token: ["link"]}, {regex: /(\~[^\~]+\~)/, token: ["comment"]}, {regex: /(\=[^\=]+\=)/, token: ["comment"]}, {regex: /\[\[[^\[\]]+\]\[[^\[\]]+\]\]/, token: "org-url"}, // links {regex: /\[\[[^\[\]]+\]\]/, token: "org-image"}, // image {regex: /\[[xX\s\-\_]\]/, token: 'qualifier org-toggle'}, // checkbox {regex: /\#\+(?:(BEGIN|begin))_[a-zA-Z]*/, token: "comment", next: "env", sol: true}, // comments {regex: /:?[A-Z_]+\:.*/, token: "comment", sol: true}, // property drawers {regex: /(\#\+[a-zA-Z_]*)(\:.*)/, token: ["keyword", 'qualifier'], sol: true}, // environments {regex: /(CLOCK\:|SHEDULED\:|DEADLINE\:)(\s.+)/, token: ["comment", "keyword"]} ], env: [ {regex: /\#\+(?:(END|end))_[a-zA-Z]*/, token: "comment", next: "start", sol: true}, {regex: /.*/, token: "comment"} ] }); CodeMirror.registerHelper("fold", "orgmode", function(cm, start) { function headerLevel (lineNo) { var line = cm.getLine(lineNo); var match = /^\*+/.exec(line); if (match && match.length === 1 && /header/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)))) { return match[0].length; } return null; } // init var levelToMatch = headerLevel(start.line); // no folding needed if(levelToMatch === null) { return; } // find folding limits var lastLine = cm.lastLine(); var end = start.line; while (end < lastLine){ end += 1; var level = headerLevel(end); if (level && level <= levelToMatch) { end = end - 1; break; } } return { from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), to: CodeMirror.Pos(end, cm.getLine(end).length) }; }); CodeMirror.registerGlobalHelper("fold", "drawer", function(mode) { return mode.name === 'orgmode' ? true : false; }, function(cm, start) { function isBeginningOfADrawer(lineNo) { var line = cm.getLine(lineNo); var match = /^\:.*\:$/.exec(line); if(match && match.length === 1 && match[0] !== ':END:'){ return true; } return false; } function isEndOfADrawer(lineNo){ var line = cm.getLine(lineNo); return line.trim() === ':END:' ? true : false; } var drawer = isBeginningOfADrawer(start.line); if (drawer === false) { return; } // find folding limits var lastLine = cm.lastLine(); var end = start.line; while(end < lastLine){ end += 1; if (isEndOfADrawer(end)) { break; } } return { from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), to: CodeMirror.Pos(end, cm.getLine(end).length) }; }); CodeMirror.afterInit = function(editor){ function fold(cm, start){ cm.foldCode(start, null, "fold"); } function unfold(cm, start){ cm.foldCode(start, null, "unfold"); } function isFold(cm, start){ var line = start.line; var marks = cm.findMarks(CodeMirror.Pos(line, 0), CodeMirror.Pos(line + 1, 0)); for (var i = 0; i < marks.length; ++i) { if (marks[i].__isFold && marks[i].find().from.line === line) { return marks[i]; } } return false; } var state = { stab: 'OVERVIEW' }; editor.setOption("extraKeys", { "Tab": function(cm) { var pos = cm.getCursor(); return isFold(cm, pos) ? unfold(cm, pos) : fold(cm, pos); }, "Shift-Tab": function(cm){ if(state.stab === "SHOW_ALL"){ // fold everything that can be fold state.stab = 'OVERVIEW'; cm.operation(function() { for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++){ fold(cm, CodeMirror.Pos(i, 0)); } }); }else{ // unfold all headers state.stab = 'SHOW_ALL'; cm.operation(function() { for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++){ if(/header/.test(cm.getTokenTypeAt(CodeMirror.Pos(i, 0))) === true){ unfold(cm, CodeMirror.Pos(i, 0)); } } }); } } }); editor.on('touchstart', function(cm){ setTimeout(function () { return isFold(cm, cm.getCursor()) ? unfold(cm, cm.getCursor()) : fold(cm, cm.getCursor()); }, 150); }); // fold everything except headers by default editor.operation(function() { for (var i = 0; i < editor.lineCount() ; i++) { if(/header/.test(editor.getTokenTypeAt(CodeMirror.Pos(i, 0))) === false){ fold(editor, CodeMirror.Pos(i, 0)); } } }); }; });