1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-23 07:09:43 +02:00

upgraded libs and improved Markdown editing experience

This commit is contained in:
Harvey Kandola 2017-03-13 15:40:28 +00:00
parent 2e146cf767
commit ea1a8000ee
165 changed files with 15930 additions and 19013 deletions

View file

@ -8,7 +8,7 @@ The mission is to bring software dev inspired features (refactoring, testing, li
## Latest version ## Latest version
v0.43.0 v0.43.1
## OS Support ## OS Support

View file

@ -94,7 +94,16 @@ export default Ember.Component.extend(TooltipMixin, {
}, },
willDestroyElement() { willDestroyElement() {
let editor = this.get('codeEditor');
if (is.not.null(editor)) {
editor.toTextArea();
editor = null;
this.set('codeEditor', null); this.set('codeEditor', null);
}
this.destroyTooltips();
}, },
// Wrap code in PRE tag with language identifier for subsequent rendering. // Wrap code in PRE tag with language identifier for subsequent rendering.

View file

@ -74,6 +74,12 @@ export default Ember.Component.extend({
willDestroyElement() { willDestroyElement() {
this._super(...arguments); this._super(...arguments);
let editor = this.get('codeEditor');
if (is.not.null(editor)) {
editor.toTextArea();
editor = null;
}
this.set('codeEditor', null); this.set('codeEditor', null);
} }
}); });

View file

@ -35,46 +35,35 @@ export default Ember.Component.extend(TooltipMixin, {
init() { init() {
this._super(...arguments); this._super(...arguments);
let self = this; // let self = this;
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js"; CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
let rawBody = this.get('meta.rawBody'); this.set('pageBody', this.get('meta.rawBody').trim());
let cleanBody = rawBody.replace("</pre>", "");
cleanBody = cleanBody.replace('<pre class="code-mirror cm-s-solarized cm-s-dark" data-lang="', ""); // let opts = [];
let startPos = cleanBody.indexOf('">'); // let syntax = {
let syntax = { // mode: "markdown",
mode: "markdown", // name: "Markdown"
name: "Markdown" // };
};
if (startPos !== -1) { // _.each(_.sortBy(CodeMirror.modeInfo, 'name'), function(item) {
syntax = cleanBody.substring(0, startPos); // let i = {
cleanBody = cleanBody.substring(startPos + 2); // mode: item.mode,
} // name: item.name
// };
// opts.pushObject(i);
this.set('pageBody', cleanBody); // if (item.mode === syntax) {
// self.set('codeSyntax', i);
// }
// });
let opts = []; // this.set('syntaxOptions', opts);
_.each(_.sortBy(CodeMirror.modeInfo, 'name'), function(item) { // // default check
let i = { // if (is.null(this.get("codeSyntax"))) {
mode: item.mode, // this.set("codeSyntax", opts.findBy("mode", "markdown"));
name: item.name // }
};
opts.pushObject(i);
if (item.mode === syntax) {
self.set('codeSyntax', i);
}
});
this.set('syntaxOptions', opts);
// default check
if (is.null(this.get("codeSyntax"))) {
this.set("codeSyntax", opts.findBy("mode", "markdown"));
}
}, },
didInsertElement() { didInsertElement() {
@ -83,17 +72,25 @@ export default Ember.Component.extend(TooltipMixin, {
}, },
willDestroyElement() { willDestroyElement() {
let editor = this.get('codeEditor');
if (this.get('editMode')) {
editor.toTextArea();
editor = null;
}
this.set('codeEditor', null); this.set('codeEditor', null);
this.destroyTooltips(); this.destroyTooltips();
}, },
getBody() { getBody() {
return this.get('codeEditor').getDoc().getValue(); return this.get('codeEditor').getDoc().getValue().trim();
}, },
attachEditor() { attachEditor() {
var editor = CodeMirror.fromTextArea(document.getElementById(this.get('editorId')), { var editor = CodeMirror.fromTextArea(document.getElementById(this.get('editorId')), {
theme: "default", theme: "default",
mode: "markdown",
lineNumbers: false, lineNumbers: false,
lineWrapping: true, lineWrapping: true,
indentUnit: 4, indentUnit: 4,
@ -112,8 +109,8 @@ export default Ember.Component.extend(TooltipMixin, {
let syntax = this.get("codeSyntax"); let syntax = this.get("codeSyntax");
if (is.not.undefined(syntax)) { if (is.not.undefined(syntax)) {
CodeMirror.autoLoadMode(editor, syntax.mode); CodeMirror.autoLoadMode(editor, "markdown");
editor.setOption("mode", syntax.mode); editor.setOption("mode", "markdown");
} }
}, },

View file

@ -23,6 +23,7 @@
<script src="/codemirror/lib/codemirror.js"></script> <script src="/codemirror/lib/codemirror.js"></script>
<script src="/codemirror/mode/meta.js"></script> <script src="/codemirror/mode/meta.js"></script>
<script src="/codemirror/addon/mode/loadmode.js"></script> <script src="/codemirror/addon/mode/loadmode.js"></script>
<script src="/codemirror/addon/mode/overlay.js"></script>
<script src="/codemirror/addon/runmode/runmode.js"></script> <script src="/codemirror/addon/runmode/runmode.js"></script>
<script src="/codemirror/addon/runmode/colorize.js"></script> <script src="/codemirror/addon/runmode/colorize.js"></script>
{{content-for 'body-footer'}} {{content-for 'body-footer'}}

View file

@ -6,7 +6,9 @@
} }
} }
/* BASICS */ /* BASICS */
.CodeMirror { .CodeMirror {
/* Set height, width, borders, and global font properties here */ /* Set height, width, borders, and global font properties here */
font-family: monospace; font-family: monospace;
@ -59,7 +61,7 @@
} }
.cm-fat-cursor .CodeMirror-cursor { .cm-fat-cursor .CodeMirror-cursor {
width: auto; width: auto;
border: 0; border: 0 !important;
background: #7e7; background: #7e7;
} }
.cm-fat-cursor div.CodeMirror-cursors { .cm-fat-cursor div.CodeMirror-cursors {
@ -95,8 +97,14 @@
.cm-tab { display: inline-block; text-decoration: inherit; } .cm-tab { display: inline-block; text-decoration: inherit; }
.CodeMirror-rulers {
position: absolute;
left: 0; right: 0; top: -50px; bottom: -20px;
overflow: hidden;
}
.CodeMirror-ruler { .CodeMirror-ruler {
border-left: 1px solid #ccc; border-left: 1px solid #ccc;
top: 0; bottom: 0;
position: absolute; position: absolute;
} }
@ -198,16 +206,15 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-gutters { .CodeMirror-gutters {
position: absolute; left: 0; top: 0; position: absolute; left: 0; top: 0;
min-height: 100%;
z-index: 3; z-index: 3;
} }
.CodeMirror-gutter { .CodeMirror-gutter {
white-space: normal; white-space: normal;
height: 100%; height: 100%;
display: inline-block; display: inline-block;
vertical-align: top;
margin-bottom: -30px; margin-bottom: -30px;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
} }
.CodeMirror-gutter-wrapper { .CodeMirror-gutter-wrapper {
position: absolute; position: absolute;
@ -251,6 +258,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
position: relative; position: relative;
overflow: visible; overflow: visible;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
-webkit-font-variant-ligatures: contextual;
font-variant-ligatures: contextual;
} }
.CodeMirror-wrap pre { .CodeMirror-wrap pre {
word-wrap: break-word; word-wrap: break-word;
@ -294,7 +303,10 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
visibility: hidden; visibility: hidden;
} }
.CodeMirror-cursor { position: absolute; } .CodeMirror-cursor {
position: absolute;
pointer-events: none;
}
.CodeMirror-measure pre { position: static; } .CodeMirror-measure pre { position: static; }
div.CodeMirror-cursors { div.CodeMirror-cursors {
@ -321,9 +333,6 @@ div.CodeMirror-dragcursors {
background: rgba(255, 255, 0, .4); background: rgba(255, 255, 0, .4);
} }
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
/* Used to force a border model for a node */ /* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; } .cm-force-border { padding-right: .1px; }
@ -340,6 +349,7 @@ div.CodeMirror-dragcursors {
/* Help users use markselection to safely style text background */ /* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; } span.CodeMirror-selectedtext { background: none; }
/* /*
Name: material Name: material
@ -394,6 +404,7 @@ span.CodeMirror-selectedtext { background: none; }
color: white !important; color: white !important;
} }
/* /*
Name: yeti Name: yeti

View file

@ -17,7 +17,7 @@
<div class="section-markdown-editor"> <div class="section-markdown-editor">
{{#if editMode}} {{#if editMode}}
{{focus-textarea value=pageBody id=editorId class="mousetrap"}} <textarea id={{editorId}} class="mousetrap">{{{pageBody}}}</textarea>
{{else}} {{else}}
<div class="mousetrap wysiwyg section-markdown-preview"> <div class="mousetrap wysiwyg section-markdown-preview">
{{{pagePreview}}} {{{pagePreview}}}

View file

@ -1,6 +1,6 @@
{ {
"name": "documize", "name": "documize",
"version": "0.43.0", "version": "0.43.1",
"description": "The Document IDE", "description": "The Document IDE",
"private": true, "private": true,
"repository": "", "repository": "",

View file

@ -44,9 +44,22 @@
} }
}); });
// Rough heuristic to try and detect lines that are part of multi-line string
function probablyInsideString(cm, pos, line) {
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line)
}
function getMode(cm, pos) {
var mode = cm.getMode()
return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
}
CodeMirror.defineExtension("lineComment", function(from, to, options) { CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = getMode(self, from);
var firstLine = self.getLine(from.line);
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
var commentString = options.lineComment || mode.lineComment; var commentString = options.lineComment || mode.lineComment;
if (!commentString) { if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) { if (options.blockCommentStart || mode.blockCommentStart) {
@ -55,8 +68,7 @@
} }
return; return;
} }
var firstLine = self.getLine(from.line);
if (firstLine == null) return;
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding; var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line; var blankLines = options.commentBlankLines || from.line == to.line;
@ -88,7 +100,7 @@
CodeMirror.defineExtension("blockComment", function(from, to, options) { CodeMirror.defineExtension("blockComment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = getMode(self, from);
var startString = options.blockCommentStart || mode.blockCommentStart; var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd; var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) { if (!startString || !endString) {
@ -96,6 +108,7 @@
self.lineComment(from, to, options); self.lineComment(from, to, options);
return; return;
} }
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
var end = Math.min(to.line, self.lastLine()); var end = Math.min(to.line, self.lastLine());
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
@ -121,7 +134,7 @@
CodeMirror.defineExtension("uncomment", function(from, to, options) { CodeMirror.defineExtension("uncomment", function(from, to, options) {
if (!options) options = noOptions; if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from); var self = this, mode = getMode(self, from);
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
// Try finding line comments // Try finding line comments
@ -133,7 +146,7 @@
var line = self.getLine(i); var line = self.getLine(i);
var found = line.indexOf(lineString); var found = line.indexOf(lineString);
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; if (found == -1 && nonWS.test(line)) break lineComment;
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
lines.push(line); lines.push(line);
} }
@ -155,13 +168,15 @@
var endString = options.blockCommentEnd || mode.blockCommentEnd; var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) return false; if (!startString || !endString) return false;
var lead = options.blockCommentLead || mode.blockCommentLead; var lead = options.blockCommentLead || mode.blockCommentLead;
var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); var startLine = self.getLine(start), open = startLine.indexOf(startString)
var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); if (open == -1) return false
var endLine = end == start ? startLine : self.getLine(end)
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
if (close == -1 && start != end) { if (close == -1 && start != end) {
endLine = self.getLine(--end); endLine = self.getLine(--end);
close = endLine.lastIndexOf(endString); close = endLine.indexOf(endString);
} }
if (open == -1 || close == -1 || if (close == -1 ||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
return false; return false;

View file

@ -56,6 +56,8 @@
var inp = dialog.getElementsByTagName("input")[0], button; var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) { if (inp) {
inp.focus();
if (options.value) { if (options.value) {
inp.value = options.value; inp.value = options.value;
if (options.selectValueOnOpen !== false) { if (options.selectValueOnOpen !== false) {
@ -79,8 +81,6 @@
}); });
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
inp.focus();
} else if (button = dialog.getElementsByTagName("button")[0]) { } else if (button = dialog.getElementsByTagName("button")[0]) {
CodeMirror.on(button, "click", function() { CodeMirror.on(button, "click", function() {
close(); close();

View file

@ -38,6 +38,9 @@
var height = (options && options.height) || node.offsetHeight; var height = (options && options.height) || node.offsetHeight;
this._setSize(null, info.heightLeft -= height); this._setSize(null, info.heightLeft -= height);
info.panels++; info.panels++;
if (options.stable && isAtTop(this, node))
this.scrollTo(null, this.getScrollInfo().top + height)
return new Panel(this, node, options, height); return new Panel(this, node, options, height);
}); });
@ -54,6 +57,8 @@
this.cleared = true; this.cleared = true;
var info = this.cm.state.panels; var info = this.cm.state.panels;
this.cm._setSize(null, info.heightLeft += this.height); this.cm._setSize(null, info.heightLeft += this.height);
if (this.options.stable && isAtTop(this.cm, this.node))
this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height)
info.wrapper.removeChild(this.node); info.wrapper.removeChild(this.node);
if (--info.panels == 0) removePanels(this.cm); if (--info.panels == 0) removePanels(this.cm);
}; };
@ -109,4 +114,10 @@
cm.setSize = cm._setSize; cm.setSize = cm._setSize;
cm.setSize(); cm.setSize();
} }
function isAtTop(cm, dom) {
for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling)
if (sibling == cm.getWrapperElement()) return true
return false
}
}); });

View file

@ -14,10 +14,12 @@
if (val && !prev) { if (val && !prev) {
cm.on("blur", onBlur); cm.on("blur", onBlur);
cm.on("change", onChange); cm.on("change", onChange);
cm.on("swapDoc", onChange);
onChange(cm); onChange(cm);
} else if (!val && prev) { } else if (!val && prev) {
cm.off("blur", onBlur); cm.off("blur", onBlur);
cm.off("change", onChange); cm.off("change", onChange);
cm.off("swapDoc", onChange);
clearPlaceholder(cm); clearPlaceholder(cm);
var wrapper = cm.getWrapperElement(); var wrapper = cm.getWrapperElement();
wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");

View file

@ -11,30 +11,26 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineOption("rulers", false, function(cm, val, old) { CodeMirror.defineOption("rulers", false, function(cm, val) {
if (old && old != CodeMirror.Init) { if (cm.state.rulerDiv) {
clearRulers(cm); cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv)
cm.off("refresh", refreshRulers); cm.state.rulerDiv = null
cm.off("refresh", drawRulers)
} }
if (val && val.length) { if (val && val.length) {
setRulers(cm); cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace)
cm.on("refresh", refreshRulers); cm.state.rulerDiv.className = "CodeMirror-rulers"
drawRulers(cm)
cm.on("refresh", drawRulers)
} }
}); });
function clearRulers(cm) { function drawRulers(cm) {
for (var i = cm.display.lineSpace.childNodes.length - 1; i >= 0; i--) { cm.state.rulerDiv.textContent = ""
var node = cm.display.lineSpace.childNodes[i];
if (/(^|\s)CodeMirror-ruler($|\s)/.test(node.className))
node.parentNode.removeChild(node);
}
}
function setRulers(cm) {
var val = cm.getOption("rulers"); var val = cm.getOption("rulers");
var cw = cm.defaultCharWidth(); var cw = cm.defaultCharWidth();
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left;
var minH = cm.display.scroller.offsetHeight + 30; cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px";
for (var i = 0; i < val.length; i++) { for (var i = 0; i < val.length; i++) {
var elt = document.createElement("div"); var elt = document.createElement("div");
elt.className = "CodeMirror-ruler"; elt.className = "CodeMirror-ruler";
@ -49,15 +45,7 @@
if (conf.width) elt.style.borderLeftWidth = conf.width; if (conf.width) elt.style.borderLeftWidth = conf.width;
} }
elt.style.left = (left + col * cw) + "px"; elt.style.left = (left + col * cw) + "px";
elt.style.top = "-50px"; cm.state.rulerDiv.appendChild(elt)
elt.style.bottom = "-20px";
elt.style.minHeight = minH + "px";
cm.display.lineSpace.insertBefore(elt, cm.display.cursorDiv);
} }
} }
function refreshRulers(cm) {
clearRulers(cm);
setRulers(cm);
}
}); });

View file

@ -45,7 +45,7 @@
function getConfig(cm) { function getConfig(cm) {
var deflt = cm.state.closeBrackets; var deflt = cm.state.closeBrackets;
if (!deflt) return null; if (!deflt || deflt.override) return deflt;
var mode = cm.getModeAt(cm.getCursor()); var mode = cm.getModeAt(cm.getCursor());
return mode.closeBrackets || deflt; return mode.closeBrackets || deflt;
} }
@ -63,7 +63,7 @@
} }
for (var i = ranges.length - 1; i >= 0; i--) { for (var i = ranges.length - 1; i >= 0; i--) {
var cur = ranges[i].head; var cur = ranges[i].head;
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
} }
} }
@ -109,14 +109,16 @@
var ranges = cm.listSelections(); var ranges = cm.listSelections();
var opening = pos % 2 == 0; var opening = pos % 2 == 0;
var type, next; var type;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], cur = range.head, curType; var range = ranges[i], cur = range.head, curType;
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
if (opening && !range.empty()) { if (opening && !range.empty()) {
curType = "surround"; curType = "surround";
} else if ((identical || !opening) && next == ch) { } else if ((identical || !opening) && next == ch) {
if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) if (identical && stringStartsAfter(cm, cur))
curType = "both";
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
curType = "skipThree"; curType = "skipThree";
else else
curType = "skip"; curType = "skip";
@ -183,7 +185,7 @@
function enteringString(cm, pos, ch) { function enteringString(cm, pos, ch) {
var line = cm.getLine(pos.line); var line = cm.getLine(pos.line);
var token = cm.getTokenAt(pos); var token = cm.getTokenAt(pos);
if (/\bstring2?\b/.test(token.type)) return false; if (/\bstring2?\b/.test(token.type) || stringStartsAfter(cm, pos)) return false;
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
stream.pos = stream.start = token.start; stream.pos = stream.start = token.start;
for (;;) { for (;;) {
@ -192,4 +194,9 @@
stream.start = stream.pos; stream.start = stream.pos;
} }
} }
function stringStartsAfter(cm, pos) {
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
return /\bstring/.test(token.type) && token.start == pos.ch
}
}); });

View file

@ -11,8 +11,8 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\s*)/, var listRE = /^(\s*)(>[> ]*|- \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)[.)])(\s*)$/, emptyListRE = /^(\s*)(>[> ]*|- \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/; unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
@ -30,7 +30,7 @@
return; return;
} }
if (emptyListRE.test(line)) { if (emptyListRE.test(line)) {
cm.replaceRange("", { if (!/>\s*$/.test(line)) cm.replaceRange("", {
line: pos.line, ch: 0 line: pos.line, ch: 0
}, { }, {
line: pos.line, ch: pos.ch + 1 line: pos.line, ch: pos.ch + 1
@ -39,7 +39,7 @@
} else { } else {
var indent = match[1], after = match[5]; var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
? match[2] ? match[2].replace("x", " ")
: (parseInt(match[3], 10) + 1) + match[4]; : (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after; replacements[i] = "\n" + indent + bullet + after;

View file

@ -102,8 +102,10 @@
} }
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets); cm.off("cursorActivity", doMatchBrackets);
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
}
if (val) { if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets); cm.on("cursorActivity", doMatchBrackets);

View file

@ -13,7 +13,7 @@
CodeMirror.registerHelper("fold", "brace", function(cm, start) { CodeMirror.registerHelper("fold", "brace", function(cm, start) {
var line = start.line, lineText = cm.getLine(line); var line = start.line, lineText = cm.getLine(line);
var startCh, tokenType; var tokenType;
function findOpening(openCh) { function findOpening(openCh) {
for (var at = start.ch, pass = 0;;) { for (var at = start.ch, pass = 0;;) {
@ -72,15 +72,15 @@ CodeMirror.registerHelper("fold", "import", function(cm, start) {
} }
} }
var start = start.line, has = hasImport(start), prev; var startLine = start.line, has = hasImport(startLine), prev;
if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1)) if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
return null; return null;
for (var end = has.end;;) { for (var end = has.end;;) {
var next = hasImport(end.line + 1); var next = hasImport(end.line + 1);
if (next == null) break; if (next == null) break;
end = next.end; end = next.end;
} }
return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end}; return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
}); });
CodeMirror.registerHelper("fold", "include", function(cm, start) { CodeMirror.registerHelper("fold", "include", function(cm, start) {
@ -91,14 +91,14 @@ CodeMirror.registerHelper("fold", "include", function(cm, start) {
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
} }
var start = start.line, has = hasInclude(start); var startLine = start.line, has = hasInclude(startLine);
if (has == null || hasInclude(start - 1) != null) return null; if (has == null || hasInclude(startLine - 1) != null) return null;
for (var end = start;;) { for (var end = startLine;;) {
var next = hasInclude(end + 1); var next = hasInclude(end + 1);
if (next == null) break; if (next == null) break;
++end; ++end;
} }
return {from: CodeMirror.Pos(start, has + 1), return {from: CodeMirror.Pos(startLine, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))}; to: cm.clipPos(CodeMirror.Pos(end))};
}); });

View file

@ -29,7 +29,7 @@ CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
} }
if (pass == 1 && found < start.ch) return; if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
(lineText.slice(found - endToken.length, found) == endToken || (found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length; startCh = found + startToken.length;
break; break;

View file

@ -49,7 +49,7 @@
}); });
var myRange = cm.markText(range.from, range.to, { var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget, replacedWith: myWidget,
clearOnEnter: true, clearOnEnter: getOption(cm, options, "clearOnEnter"),
__isFold: true __isFold: true
}); });
myRange.on("clear", function(from, to) { myRange.on("clear", function(from, to) {
@ -129,7 +129,8 @@
rangeFinder: CodeMirror.fold.auto, rangeFinder: CodeMirror.fold.auto,
widget: "\u2194", widget: "\u2194",
minFoldSize: 0, minFoldSize: 0,
scanUp: false scanUp: false,
clearOnEnter: true
}; };
CodeMirror.defineOption("foldOptions", null); CodeMirror.defineOption("foldOptions", null);

View file

@ -20,7 +20,7 @@
cm.off("viewportChange", onViewportChange); cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold); cm.off("fold", onFold);
cm.off("unfold", onFold); cm.off("unfold", onFold);
cm.off("swapDoc", updateInViewport); cm.off("swapDoc", onChange);
} }
if (val) { if (val) {
cm.state.foldGutter = new State(parseOptions(val)); cm.state.foldGutter = new State(parseOptions(val));
@ -30,7 +30,7 @@
cm.on("viewportChange", onViewportChange); cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold); cm.on("fold", onFold);
cm.on("unfold", onFold); cm.on("unfold", onFold);
cm.on("swapDoc", updateInViewport); cm.on("swapDoc", onChange);
} }
}); });
@ -50,7 +50,7 @@
} }
function isFolded(cm, line) { function isFolded(cm, line) {
var marks = cm.findMarksAt(Pos(line)); var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
for (var i = 0; i < marks.length; ++i) for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i]; if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
} }

View file

@ -11,32 +11,36 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function lineIndent(cm, lineNo) {
var text = cm.getLine(lineNo)
var spaceTo = text.search(/\S/)
if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
return -1
return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
}
!
CodeMirror.registerHelper("fold", "indent", function(cm, start) { CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); var myIndent = lineIndent(cm, start.line)
if (!/\S/.test(firstLine)) return; if (myIndent < 0) return
var getIndent = function(line) { var lastLineInFold = null
return CodeMirror.countColumn(line, null, tabSize);
};
var myIndent = getIndent(firstLine);
var lastLineInFold = null;
// Go through lines until we find a line that definitely doesn't belong in // Go through lines until we find a line that definitely doesn't belong in
// the block we're folding, or to the end. // the block we're folding, or to the end.
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var curLine = cm.getLine(i); var indent = lineIndent(cm, i)
var curIndent = getIndent(curLine); if (indent == -1) {
if (curIndent > myIndent) { } else if (indent > myIndent) {
// Lines with a greater indent are considered part of the block. // Lines with a greater indent are considered part of the block.
lastLineInFold = i; lastLineInFold = i;
} else if (!/\S/.test(curLine)) {
// Empty lines might be breaks within the block we're trying to fold.
} else { } else {
// A non-empty line at an indent equal to or less than ours marks the // If this line has non-space, non-comment content, and is
// start of another block. // indented less or equal to the start line, it is the start of
// another block.
break; break;
} }
} }
if (lastLineInFold) return { if (lastLineInFold) return {
from: CodeMirror.Pos(start.line, firstLine.length), from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
}; };
}); });

View file

@ -21,8 +21,8 @@
function Iter(cm, line, ch, range) { function Iter(cm, line, ch, range) {
this.line = line; this.ch = ch; this.line = line; this.ch = ch;
this.cm = cm; this.text = cm.getLine(line); this.cm = cm; this.text = cm.getLine(line);
this.min = range ? range.from : cm.firstLine(); this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
this.max = range ? range.to - 1 : cm.lastLine(); this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
} }
function tagAt(iter, ch) { function tagAt(iter, ch) {
@ -140,9 +140,9 @@
var openTag = toNextTag(iter), end; var openTag = toNextTag(iter), end;
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
if (!openTag[1] && end != "selfClose") { if (!openTag[1] && end != "selfClose") {
var start = Pos(iter.line, iter.ch); var startPos = Pos(iter.line, iter.ch);
var close = findMatchingClose(iter, openTag[2]); var endPos = findMatchingClose(iter, openTag[2]);
return close && {from: start, to: close.from}; return endPos && {from: startPos, to: endPos.from};
} }
} }
}); });

View file

@ -97,6 +97,15 @@
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
function forAllProps(obj, callback) {
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
for (var name in obj) callback(name)
} else {
for (var o = obj; o; o = Object.getPrototypeOf(o))
Object.getOwnPropertyNames(o).forEach(callback)
}
}
function getCompletions(token, context, keywords, options) { function getCompletions(token, context, keywords, options) {
var found = [], start = token.string, global = options && options.globalScope || window; var found = [], start = token.string, global = options && options.globalScope || window;
function maybeAdd(str) { function maybeAdd(str) {
@ -106,7 +115,7 @@
if (typeof obj == "string") forEach(stringProps, maybeAdd); if (typeof obj == "string") forEach(stringProps, maybeAdd);
else if (obj instanceof Array) forEach(arrayProps, maybeAdd); else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
else if (obj instanceof Function) forEach(funcProps, maybeAdd); else if (obj instanceof Function) forEach(funcProps, maybeAdd);
for (var name in obj) maybeAdd(name); forAllProps(obj, maybeAdd)
} }
if (context && context.length) { if (context && context.length) {

View file

@ -25,8 +25,6 @@
margin: 0; margin: 0;
padding: 0 4px; padding: 0 4px;
border-radius: 2px; border-radius: 2px;
max-width: 19em;
overflow: hidden;
white-space: pre; white-space: pre;
color: black; color: black;
cursor: pointer; cursor: pointer;

View file

@ -108,24 +108,22 @@
}, },
update: function(first) { update: function(first) {
if (this.tick == null) return; if (this.tick == null) return
if (!this.options.hint.async) { var self = this, myTick = ++this.tick
this.finishUpdate(this.options.hint(this.cm, this.options), first); fetchHints(this.options.hint, this.cm, this.options, function(data) {
} else { if (self.tick == myTick) self.finishUpdate(data, first)
var myTick = ++this.tick, self = this; })
this.options.hint(this.cm, function(data) {
if (self.tick == myTick) self.finishUpdate(data, first);
}, this.options);
}
}, },
finishUpdate: function(data, first) { finishUpdate: function(data, first) {
if (this.data) CodeMirror.signal(this.data, "update"); if (this.data) CodeMirror.signal(this.data, "update");
if (data && this.data && CodeMirror.cmpPos(data.from, this.data.from)) data = null;
this.data = data;
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
if (this.widget) this.widget.close(); if (this.widget) this.widget.close();
if (data && this.data && isNewCompletion(this.data, data)) return;
this.data = data;
if (data && data.list.length) { if (data && data.list.length) {
if (picked && data.list.length == 1) { if (picked && data.list.length == 1) {
this.pick(data, 0); this.pick(data, 0);
@ -137,6 +135,11 @@
} }
}; };
function isNewCompletion(old, nw) {
var moved = CodeMirror.cmpPos(nw.from, old.from)
return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch
}
function parseOptions(cm, pos, options) { function parseOptions(cm, pos, options) {
var editor = cm.options.hintOptions; var editor = cm.options.hintOptions;
var out = {}; var out = {};
@ -226,6 +229,9 @@
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
(completion.options.container || document.body).appendChild(hints); (completion.options.container || document.body).appendChild(hints);
var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
var scrolls = hints.scrollHeight > hints.clientHeight + 1
var startScroll = cm.getScrollInfo();
if (overlapY > 0) { if (overlapY > 0) {
var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
if (curTop - height > 0) { // Fits above cursor if (curTop - height > 0) { // Fits above cursor
@ -250,6 +256,8 @@
} }
hints.style.left = (left = pos.left - overlapX) + "px"; hints.style.left = (left = pos.left - overlapX) + "px";
} }
if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
node.style.paddingRight = cm.display.nativeBarWidth + "px"
cm.addKeyMap(this.keyMap = buildKeyMap(completion, { cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
@ -267,7 +275,6 @@
cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
} }
var startScroll = cm.getScrollInfo();
cm.on("scroll", this.onScroll = function() { cm.on("scroll", this.onScroll = function() {
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
var newTop = top + startScroll.top - curScroll.top; var newTop = top + startScroll.top - curScroll.top;
@ -355,40 +362,31 @@
return result return result
} }
function fetchHints(hint, cm, options, callback) {
if (hint.async) {
hint(cm, callback, options)
} else {
var result = hint(cm, options)
if (result && result.then) result.then(callback)
else callback(result)
}
}
function resolveAutoHints(cm, pos) { function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) { if (helpers.length) {
var async = false, resolved var resolved = function(cm, callback, options) {
for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true var app = applicableHelpers(cm, helpers);
if (async) { function run(i) {
resolved = function(cm, callback, options) {
var app = applicableHelpers(cm, helpers)
function run(i, result) {
if (i == app.length) return callback(null) if (i == app.length) return callback(null)
var helper = app[i] fetchHints(app[i], cm, options, function(result) {
if (helper.async) { if (result && result.list.length > 0) callback(result)
helper(cm, function(result) {
if (result) callback(result)
else run(i + 1) else run(i + 1)
}, options) })
} else {
var result = helper(cm, options)
if (result) callback(result)
else run(i + 1)
}
} }
run(0) run(0)
} }
resolved.async = true resolved.async = true
} else {
resolved = function(cm, options) {
var app = applicableHelpers(cm, helpers)
for (var i = 0; i < app.length; i++) {
var cur = app[i](cm, options)
if (cur && cur.list.length) return cur
}
}
}
resolved.supportsSelection = true resolved.supportsSelection = true
return resolved return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {

View file

@ -18,7 +18,9 @@
QUERY_DIV: ";", QUERY_DIV: ";",
ALIAS_KEYWORD: "AS" ALIAS_KEYWORD: "AS"
}; };
var Pos = CodeMirror.Pos; var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
function getKeywords(editor) { function getKeywords(editor) {
var mode = editor.doc.modeOption; var mode = editor.doc.modeOption;
@ -30,10 +32,28 @@
return typeof item == "string" ? item : item.text; return typeof item == "string" ? item : item.text;
} }
function getItem(list, item) { function wrapTable(name, value) {
if (!list.slice) return list[item]; if (isArray(value)) value = {columns: value}
for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item) if (!value.text) value.text = name
return list[i]; return value
}
function parseTables(input) {
var result = {}
if (isArray(input)) {
for (var i = input.length - 1; i >= 0; i--) {
var item = input[i]
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
}
} else if (input) {
for (var name in input)
result[name.toUpperCase()] = wrapTable(name, input[name])
}
return result
}
function getTable(name) {
return tables[name.toUpperCase()]
} }
function shallowClone(object) { function shallowClone(object) {
@ -50,11 +70,18 @@
} }
function addMatches(result, search, wordlist, formatter) { function addMatches(result, search, wordlist, formatter) {
for (var word in wordlist) { if (isArray(wordlist)) {
if (!wordlist.hasOwnProperty(word)) continue; for (var i = 0; i < wordlist.length; i++)
if (wordlist.slice) word = wordlist[word]; if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
} else {
if (match(search, word)) result.push(formatter(word)); for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
var val = wordlist[word]
if (!val || val === true)
val = word
else
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
if (match(search, val)) result.push(formatter(val))
}
} }
} }
@ -78,7 +105,7 @@
} }
function nameCompletion(cur, token, result, editor) { function nameCompletion(cur, token, result, editor) {
// Try to complete table, colunm names and return start position of completion // Try to complete table, column names and return start position of completion
var useBacktick = false; var useBacktick = false;
var nameParts = []; var nameParts = [];
var start = token.start; var start = token.start;
@ -115,13 +142,13 @@
var alias = false; var alias = false;
var aliasTable = table; var aliasTable = table;
// Check if table is available. If not, find table by Alias // Check if table is available. If not, find table by Alias
if (!getItem(tables, table)) { if (!getTable(table)) {
var oldTable = table; var oldTable = table;
table = findTableByAlias(table, editor); table = findTableByAlias(table, editor);
if (table !== oldTable) alias = true; if (table !== oldTable) alias = true;
} }
var columns = getItem(tables, table); var columns = getTable(table);
if (columns && columns.columns) if (columns && columns.columns)
columns = columns.columns; columns = columns.columns;
@ -151,15 +178,6 @@
} }
} }
function convertCurToNumber(cur) {
// max characters of a line is 999,999.
return cur.line + cur.ch / Math.pow(10, 6);
}
function convertNumberToCur(num) {
return Pos(Math.floor(num), +num.toString().split('.').pop());
}
function findTableByAlias(alias, editor) { function findTableByAlias(alias, editor) {
var doc = editor.doc; var doc = editor.doc;
var fullQuery = doc.getValue(); var fullQuery = doc.getValue();
@ -182,15 +200,14 @@
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
//find valid range //find valid range
var prevItem = 0; var prevItem = null;
var current = convertCurToNumber(editor.getCursor()); var current = editor.getCursor()
for (var i = 0; i < separator.length; i++) { for (var i = 0; i < separator.length; i++) {
var _v = convertCurToNumber(separator[i]); if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
if (current > prevItem && current <= _v) { validRange = {start: prevItem, end: separator[i]};
validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
break; break;
} }
prevItem = _v; prevItem = separator[i];
} }
var query = doc.getRange(validRange.start, validRange.end, false); var query = doc.getRange(validRange.start, validRange.end, false);
@ -199,7 +216,7 @@
var lineText = query[i]; var lineText = query[i];
eachWord(lineText, function(word) { eachWord(lineText, function(word) {
var wordUpperCase = word.toUpperCase(); var wordUpperCase = word.toUpperCase();
if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord)) if (wordUpperCase === aliasUpperCase && getTable(previousWord))
table = previousWord; table = previousWord;
if (wordUpperCase !== CONS.ALIAS_KEYWORD) if (wordUpperCase !== CONS.ALIAS_KEYWORD)
previousWord = word; previousWord = word;
@ -210,11 +227,11 @@
} }
CodeMirror.registerHelper("hint", "sql", function(editor, options) { CodeMirror.registerHelper("hint", "sql", function(editor, options) {
tables = (options && options.tables) || {}; tables = parseTables(options && options.tables)
var defaultTableName = options && options.defaultTable; var defaultTableName = options && options.defaultTable;
var disableKeywords = options && options.disableKeywords; var disableKeywords = options && options.disableKeywords;
defaultTable = defaultTableName && getItem(tables, defaultTableName); defaultTable = defaultTableName && getTable(defaultTableName);
keywords = keywords || getKeywords(editor); keywords = getKeywords(editor);
if (defaultTableName && !defaultTable) if (defaultTableName && !defaultTable)
defaultTable = findTableByAlias(defaultTableName, editor); defaultTable = findTableByAlias(defaultTableName, editor);

View file

@ -4,10 +4,10 @@
} }
.CodeMirror-lint-tooltip { .CodeMirror-lint-tooltip {
background-color: infobackground; background-color: #ffd;
border: 1px solid black; border: 1px solid black;
border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
color: infotext; color: black;
font-family: monospace; font-family: monospace;
font-size: 10pt; font-size: 10pt;
overflow: hidden; overflow: hidden;

View file

@ -186,9 +186,14 @@
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
} }
function popupSpanTooltip(ann, e) { function popupTooltips(annotations, e) {
var target = e.target || e.srcElement; var target = e.target || e.srcElement;
showTooltipFor(e, annotationTooltip(ann), target); var tooltip = document.createDocumentFragment();
for (var i = 0; i < annotations.length; i++) {
var ann = annotations[i];
tooltip.appendChild(annotationTooltip(ann));
}
showTooltipFor(e, tooltip, target);
} }
function onMouseOver(cm, e) { function onMouseOver(cm, e) {
@ -196,10 +201,13 @@
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client"));
var annotations = [];
for (var i = 0; i < spans.length; ++i) { for (var i = 0; i < spans.length; ++i) {
var ann = spans[i].__annotation; var ann = spans[i].__annotation;
if (ann) return popupSpanTooltip(ann, e); if (ann) annotations.push(ann);
} }
if (annotations.length) popupTooltips(annotations, e);
} }
CodeMirror.defineOption("lint", false, function(cm, val, old) { CodeMirror.defineOption("lint", false, function(cm, val, old) {
@ -218,7 +226,7 @@
var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
if (state.options.lintOnChange !== false) if (state.options.lintOnChange !== false)
cm.on("change", onChange); cm.on("change", onChange);
if (state.options.tooltips != false) if (state.options.tooltips != false && state.options.tooltips != "gutter")
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
startLinting(cm); startLinting(cm);

View file

@ -60,6 +60,7 @@
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
color: #44c; color: #44c;
z-index: 3;
} }
.CodeMirror-merge-copy-reverse { .CodeMirror-merge-copy-reverse {

View file

@ -37,15 +37,26 @@
constructor: DiffView, constructor: DiffView,
init: function(pane, orig, options) { init: function(pane, orig, options) {
this.edit = this.mv.edit; this.edit = this.mv.edit;
(this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); ;(this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this);
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options)));
if (this.mv.options.connect == "align") {
if (!this.edit.state.trackAlignable) this.edit.state.trackAlignable = new TrackAlignable(this.edit)
this.orig.state.trackAlignable = new TrackAlignable(this.orig)
}
this.orig.state.diffViews = [this]; this.orig.state.diffViews = [this];
var classLocation = options.chunkClassLocation || "background";
if (Object.prototype.toString.call(classLocation) != "[object Array]") classLocation = [classLocation]
this.classes.classLocation = classLocation
this.diff = getDiff(asString(orig), asString(options.value)); this.diff = getDiff(asString(orig), asString(options.value));
this.chunks = getChunks(this.diff); this.chunks = getChunks(this.diff);
this.diffOutOfDate = this.dealigned = false; this.diffOutOfDate = this.dealigned = false;
this.needsScrollSync = null
this.showDifferences = options.showDifferences !== false; this.showDifferences = options.showDifferences !== false;
},
registerEvents: function() {
this.forceUpdate = registerUpdate(this); this.forceUpdate = registerUpdate(this);
setScrollLock(this, true, false); setScrollLock(this, true, false);
registerScroll(this); registerScroll(this);
@ -88,10 +99,12 @@
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
} }
makeConnections(dv);
if (dv.mv.options.connect == "align") if (dv.mv.options.connect == "align")
alignChunks(dv); alignChunks(dv);
makeConnections(dv);
if (dv.needsScrollSync != null) syncScroll(dv, dv.needsScrollSync)
updating = false; updating = false;
} }
function setDealign(fast) { function setDealign(fast) {
@ -113,12 +126,18 @@
// Update faster when a line was added/removed // Update faster when a line was added/removed
setDealign(change.text.length - 1 != change.to.line - change.from.line); setDealign(change.text.length - 1 != change.to.line - change.from.line);
} }
function swapDoc() {
dv.diffOutOfDate = true;
update("full");
}
dv.edit.on("change", change); dv.edit.on("change", change);
dv.orig.on("change", change); dv.orig.on("change", change);
dv.edit.on("markerAdded", setDealign); dv.edit.on("swapDoc", swapDoc);
dv.edit.on("markerCleared", setDealign); dv.orig.on("swapDoc", swapDoc);
dv.orig.on("markerAdded", setDealign); if (dv.mv.options.connect == "align") {
dv.orig.on("markerCleared", setDealign); CodeMirror.on(dv.edit.state.trackAlignable, "realign", setDealign)
CodeMirror.on(dv.orig.state.trackAlignable, "realign", setDealign)
}
dv.edit.on("viewportChange", function() { set(false); }); dv.edit.on("viewportChange", function() { set(false); });
dv.orig.on("viewportChange", function() { set(false); }); dv.orig.on("viewportChange", function() { set(false); });
update(); update();
@ -127,23 +146,27 @@
function registerScroll(dv) { function registerScroll(dv) {
dv.edit.on("scroll", function() { dv.edit.on("scroll", function() {
syncScroll(dv, DIFF_INSERT) && makeConnections(dv); syncScroll(dv, true) && makeConnections(dv);
}); });
dv.orig.on("scroll", function() { dv.orig.on("scroll", function() {
syncScroll(dv, DIFF_DELETE) && makeConnections(dv); syncScroll(dv, false) && makeConnections(dv);
}); });
} }
function syncScroll(dv, type) { function syncScroll(dv, toOrig) {
// Change handler will do a refresh after a timeout when diff is out of date // Change handler will do a refresh after a timeout when diff is out of date
if (dv.diffOutOfDate) return false; if (dv.diffOutOfDate) {
if (dv.lockScroll && dv.needsScrollSync == null) dv.needsScrollSync = toOrig
return false
}
dv.needsScrollSync = null
if (!dv.lockScroll) return true; if (!dv.lockScroll) return true;
var editor, other, now = +new Date; var editor, other, now = +new Date;
if (type == DIFF_INSERT) { editor = dv.edit; other = dv.orig; } if (toOrig) { editor = dv.edit; other = dv.orig; }
else { editor = dv.orig; other = dv.edit; } else { editor = dv.orig; other = dv.edit; }
// Don't take action if the position of this editor was recently set // Don't take action if the position of this editor was recently set
// (to prevent feedback loops) // (to prevent feedback loops)
if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false; if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 250 > now) return false;
var sInfo = editor.getScrollInfo(); var sInfo = editor.getScrollInfo();
if (dv.mv.options.connect == "align") { if (dv.mv.options.connect == "align") {
@ -151,9 +174,9 @@
} else { } else {
var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
var mid = editor.lineAtHeight(midY, "local"); var mid = editor.lineAtHeight(midY, "local");
var around = chunkBoundariesAround(dv.chunks, mid, type == DIFF_INSERT); var around = chunkBoundariesAround(dv.chunks, mid, toOrig);
var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig); var off = getOffsets(editor, toOrig ? around.edit : around.orig);
var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit); var offOther = getOffsets(other, toOrig ? around.orig : around.edit);
var ratio = (midY - off.top) / (off.bot - off.top); var ratio = (midY - off.top) / (off.bot - off.top);
var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top);
@ -191,16 +214,22 @@
// Updating the marks for editor content // Updating the marks for editor content
function removeClass(editor, line, classes) {
var locs = classes.classLocation
for (var i = 0; i < locs.length; i++) {
editor.removeLineClass(line, locs[i], classes.chunk);
editor.removeLineClass(line, locs[i], classes.start);
editor.removeLineClass(line, locs[i], classes.end);
}
}
function clearMarks(editor, arr, classes) { function clearMarks(editor, arr, classes) {
for (var i = 0; i < arr.length; ++i) { for (var i = 0; i < arr.length; ++i) {
var mark = arr[i]; var mark = arr[i];
if (mark instanceof CodeMirror.TextMarker) { if (mark instanceof CodeMirror.TextMarker)
mark.clear(); mark.clear();
} else if (mark.parent) { else if (mark.parent)
editor.removeLineClass(mark, "background", classes.chunk); removeClass(editor, mark, classes);
editor.removeLineClass(mark, "background", classes.start);
editor.removeLineClass(mark, "background", classes.end);
}
} }
arr.length = 0; arr.length = 0;
} }
@ -226,28 +255,34 @@
}); });
} }
function addClass(editor, lineNr, classes, main, start, end) {
var locs = classes.classLocation, line = editor.getLineHandle(lineNr);
for (var i = 0; i < locs.length; i++) {
if (main) editor.addLineClass(line, locs[i], classes.chunk);
if (start) editor.addLineClass(line, locs[i], classes.start);
if (end) editor.addLineClass(line, locs[i], classes.end);
}
return line;
}
function markChanges(editor, diff, type, marks, from, to, classes) { function markChanges(editor, diff, type, marks, from, to, classes) {
var pos = Pos(0, 0); var pos = Pos(0, 0);
var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1));
var cls = type == DIFF_DELETE ? classes.del : classes.insert; var cls = type == DIFF_DELETE ? classes.del : classes.insert;
function markChunk(start, end) { function markChunk(start, end) {
var bfrom = Math.max(from, start), bto = Math.min(to, end); var bfrom = Math.max(from, start), bto = Math.min(to, end);
for (var i = bfrom; i < bto; ++i) { for (var i = bfrom; i < bto; ++i)
var line = editor.addLineClass(i, "background", classes.chunk); marks.push(addClass(editor, i, classes, true, i == start, i == end - 1));
if (i == start) editor.addLineClass(line, "background", classes.start);
if (i == end - 1) editor.addLineClass(line, "background", classes.end);
marks.push(line);
}
// When the chunk is empty, make sure a horizontal line shows up // When the chunk is empty, make sure a horizontal line shows up
if (start == end && bfrom == end && bto == end) { if (start == end && bfrom == end && bto == end) {
if (bfrom) if (bfrom)
marks.push(editor.addLineClass(bfrom - 1, "background", classes.end)); marks.push(addClass(editor, bfrom - 1, classes, false, false, true));
else else
marks.push(editor.addLineClass(bfrom, "background", classes.start)); marks.push(addClass(editor, bfrom, classes, false, true, false));
} }
} }
var chunkStart = 0; var chunkStart = 0, pending = false;
for (var i = 0; i < diff.length; ++i) { for (var i = 0; i < diff.length; ++i) {
var part = diff[i], tp = part[0], str = part[1]; var part = diff[i], tp = part[0], str = part[1];
if (tp == DIFF_EQUAL) { if (tp == DIFF_EQUAL) {
@ -255,10 +290,11 @@
moveOver(pos, str); moveOver(pos, str);
var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0);
if (cleanTo > cleanFrom) { if (cleanTo > cleanFrom) {
if (i) markChunk(chunkStart, cleanFrom); if (pending) { markChunk(chunkStart, cleanFrom); pending = false }
chunkStart = cleanTo; chunkStart = cleanTo;
} }
} else { } else {
pending = true
if (tp == type) { if (tp == type) {
var end = moveOver(pos, str, true); var end = moveOver(pos, str, true);
var a = posMax(top, pos), b = posMin(bot, end); var a = posMax(top, pos), b = posMin(bot, end);
@ -268,7 +304,7 @@
} }
} }
} }
if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1); if (pending) markChunk(chunkStart, pos.line + 1);
} }
// Updating the gap between editor and original // Updating the gap between editor and original
@ -284,7 +320,9 @@
if (dv.copyButtons) clear(dv.copyButtons); if (dv.copyButtons) clear(dv.copyButtons);
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top; var outerTop = dv.mv.wrap.getBoundingClientRect().top
var sTopEdit = outerTop - dv.edit.getScrollerElement().getBoundingClientRect().top + dv.edit.getScrollInfo().top
var sTopOrig = outerTop - dv.orig.getScrollerElement().getBoundingClientRect().top + dv.orig.getScrollInfo().top;
for (var i = 0; i < dv.chunks.length; i++) { for (var i = 0; i < dv.chunks.length; i++) {
var ch = dv.chunks[i]; var ch = dv.chunks[i];
if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from &&
@ -305,29 +343,73 @@
return origStart + (editLine - editStart); return origStart + (editLine - editStart);
} }
// Combines information about chunks and widgets/markers to return
// an array of lines, in a single editor, that probably need to be
// aligned with their counterparts in the editor next to it.
function alignableFor(cm, chunks, isOrig) {
var tracker = cm.state.trackAlignable
var start = cm.firstLine(), trackI = 0
var result = []
for (var i = 0;; i++) {
var chunk = chunks[i]
var chunkStart = !chunk ? cm.lastLine() + 1 : isOrig ? chunk.origFrom : chunk.editFrom
for (; trackI < tracker.alignable.length; trackI += 2) {
var n = tracker.alignable[trackI] + 1
if (n <= start) continue
if (n < chunkStart) result.push(n)
else break
}
if (!chunk) break
result.push(start = isOrig ? chunk.origTo : chunk.editTo)
}
return result
}
// Given information about alignable lines in two editors, fill in
// the result (an array of three-element arrays) to reflect the
// lines that need to be aligned with each other.
function mergeAlignable(result, origAlignable, chunks, setIndex) {
var rI = 0, origI = 0, chunkI = 0, diff = 0
for (;; rI++) {
var nextR = result[rI], nextO = origAlignable[origI]
if (!nextR && nextO == null) break
var rLine = nextR ? nextR[0] : 1e9, oLine = nextO == null ? 1e9 : nextO
while (chunkI < chunks.length) {
var chunk = chunks[chunkI]
if (chunk.editTo > rLine) break
diff += (chunk.origTo - chunk.origFrom) - (chunk.editTo - chunk.editFrom)
chunkI++
}
if (rLine == oLine - diff) {
nextR[setIndex] = oLine
origI++
} else if (rLine < oLine - diff) {
nextR[setIndex] = rLine + diff
} else {
var record = [oLine - diff, null, null]
record[setIndex] = oLine
result.splice(rI, 0, record)
origI++
}
}
}
function findAlignedLines(dv, other) { function findAlignedLines(dv, other) {
var linesToAlign = []; var alignable = alignableFor(dv.edit, dv.chunks, false), result = []
for (var i = 0; i < dv.chunks.length; i++) { if (other) for (var i = 0, j = 0; i < other.chunks.length; i++) {
var chunk = dv.chunks[i]; var n = other.chunks[i].editTo
linesToAlign.push([chunk.origTo, chunk.editTo, other ? getMatchingOrigLine(chunk.editTo, other.chunks) : null]); while (j < alignable.length && alignable[j] < n) j++
if (j == alignable.length || alignable[j] != n) alignable.splice(j++, 0, n)
} }
if (other) { for (var i = 0; i < alignable.length; i++)
for (var i = 0; i < other.chunks.length; i++) { result.push([alignable[i], null, null])
var chunk = other.chunks[i];
for (var j = 0; j < linesToAlign.length; j++) { mergeAlignable(result, alignableFor(dv.orig, dv.chunks, true), dv.chunks, 1)
var align = linesToAlign[j]; if (other)
if (align[1] == chunk.editTo) { mergeAlignable(result, alignableFor(other.orig, other.chunks, true), other.chunks, 2)
j = -1;
break; return result
} else if (align[1] > chunk.editTo) {
break;
}
}
if (j > -1)
linesToAlign.splice(j - 1, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]);
}
}
return linesToAlign;
} }
function alignChunks(dv, force) { function alignChunks(dv, force) {
@ -350,7 +432,7 @@
aligners[i].clear(); aligners[i].clear();
aligners.length = 0; aligners.length = 0;
var cm = [dv.orig, dv.edit], scroll = []; var cm = [dv.edit, dv.orig], scroll = [];
if (other) cm.push(other.orig); if (other) cm.push(other.orig);
for (var i = 0; i < cm.length; i++) for (var i = 0; i < cm.length; i++)
scroll.push(cm[i].getScrollInfo().top); scroll.push(cm[i].getScrollInfo().top);
@ -385,18 +467,18 @@
var elt = document.createElement("div"); var elt = document.createElement("div");
elt.className = "CodeMirror-merge-spacer"; elt.className = "CodeMirror-merge-spacer";
elt.style.height = size + "px"; elt.style.minWidth = "1px"; elt.style.height = size + "px"; elt.style.minWidth = "1px";
return cm.addLineWidget(line, elt, {height: size, above: above}); return cm.addLineWidget(line, elt, {height: size, above: above, mergeSpacer: true});
} }
function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) {
var flip = dv.type == "left"; var flip = dv.type == "left";
var top = dv.orig.heightAtLine(chunk.origFrom, "local") - sTopOrig; var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig;
if (dv.svg) { if (dv.svg) {
var topLpx = top; var topLpx = top;
var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit;
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
var botLpx = dv.orig.heightAtLine(chunk.origTo, "local") - sTopOrig; var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig;
var botRpx = dv.edit.heightAtLine(chunk.editTo, "local") - sTopEdit; var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit;
if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
@ -410,10 +492,10 @@
var editOriginals = dv.mv.options.allowEditingOriginals; var editOriginals = dv.mv.options.allowEditingOriginals;
copy.title = editOriginals ? "Push to left" : "Revert chunk"; copy.title = editOriginals ? "Push to left" : "Revert chunk";
copy.chunk = chunk; copy.chunk = chunk;
copy.style.top = top + "px"; copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px";
if (editOriginals) { if (editOriginals) {
var topReverse = dv.orig.heightAtLine(chunk.editFrom, "local") - sTopEdit; var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit;
var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc",
"CodeMirror-merge-copy-reverse")); "CodeMirror-merge-copy-reverse"));
copyReverse.title = "Push to right"; copyReverse.title = "Push to right";
@ -427,8 +509,15 @@
function copyChunk(dv, to, from, chunk) { function copyChunk(dv, to, from, chunk) {
if (dv.diffOutOfDate) return; if (dv.diffOutOfDate) return;
to.replaceRange(from.getRange(Pos(chunk.origFrom, 0), Pos(chunk.origTo, 0)), var origStart = chunk.origTo > from.lastLine() ? Pos(chunk.origFrom - 1) : Pos(chunk.origFrom, 0)
Pos(chunk.editFrom, 0), Pos(chunk.editTo, 0)); var origEnd = Pos(chunk.origTo, 0)
var editStart = chunk.editTo > to.lastLine() ? Pos(chunk.editFrom - 1) : Pos(chunk.editFrom, 0)
var editEnd = Pos(chunk.editTo, 0)
var handler = dv.mv.options.revertChunk
if (handler)
handler(dv.mv, from, origStart, origEnd, to, editStart, editEnd)
else
to.replaceRange(from.getRange(origStart, origEnd), editStart, editEnd)
} }
// Merge view, containing 0, 1, or 2 diff views. // Merge view, containing 0, 1, or 2 diff views.
@ -446,18 +535,18 @@
if (hasLeft) { if (hasLeft) {
left = this.left = new DiffView(this, "left"); left = this.left = new DiffView(this, "left");
var leftPane = elt("div", null, "CodeMirror-merge-pane"); var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left");
wrap.push(leftPane); wrap.push(leftPane);
wrap.push(buildGap(left)); wrap.push(buildGap(left));
} }
var editPane = elt("div", null, "CodeMirror-merge-pane"); var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor");
wrap.push(editPane); wrap.push(editPane);
if (hasRight) { if (hasRight) {
right = this.right = new DiffView(this, "right"); right = this.right = new DiffView(this, "right");
wrap.push(buildGap(right)); wrap.push(buildGap(right));
var rightPane = elt("div", null, "CodeMirror-merge-pane"); var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right");
wrap.push(rightPane); wrap.push(rightPane);
} }
@ -470,7 +559,6 @@
if (left) left.init(leftPane, origLeft, options); if (left) left.init(leftPane, origLeft, options);
if (right) right.init(rightPane, origRight, options); if (right) right.init(rightPane, origRight, options);
if (options.collapseIdentical) if (options.collapseIdentical)
this.editor().operation(function() { this.editor().operation(function() {
collapseIdenticalStretches(self, options.collapseIdentical); collapseIdenticalStretches(self, options.collapseIdentical);
@ -479,6 +567,9 @@
this.aligners = []; this.aligners = [];
alignChunks(this.left || this.right, true); alignChunks(this.left || this.right, true);
} }
if (left) left.registerEvents()
if (right) right.registerEvents()
var onResize = function() { var onResize = function() {
if (left) makeConnections(left); if (left) makeConnections(left);
@ -521,7 +612,7 @@
} }
MergeView.prototype = { MergeView.prototype = {
constuctor: MergeView, constructor: MergeView,
editor: function() { return this.edit; }, editor: function() { return this.edit; },
rightOriginal: function() { return this.right && this.right.orig; }, rightOriginal: function() { return this.right && this.right.orig; },
leftOriginal: function() { return this.left && this.left.orig; }, leftOriginal: function() { return this.left && this.left.orig; },
@ -547,7 +638,6 @@
var dmp = new diff_match_patch(); var dmp = new diff_match_patch();
function getDiff(a, b) { function getDiff(a, b) {
var diff = dmp.diff_main(a, b); var diff = dmp.diff_main(a, b);
dmp.diff_cleanupSemantic(diff);
// The library sometimes leaves in empty parts, which confuse the algorithm // The library sometimes leaves in empty parts, which confuse the algorithm
for (var i = 0; i < diff.length; ++i) { for (var i = 0; i < diff.length; ++i) {
var part = diff[i]; var part = diff[i];
@ -591,10 +681,10 @@
function endOfLineClean(diff, i) { function endOfLineClean(diff, i) {
if (i == diff.length - 1) return true; if (i == diff.length - 1) return true;
var next = diff[i + 1][1]; var next = diff[i + 1][1];
if (next.length == 1 || next.charCodeAt(0) != 10) return false; if ((next.length == 1 && i < diff.length - 2) || next.charCodeAt(0) != 10) return false;
if (i == diff.length - 2) return true; if (i == diff.length - 2) return true;
next = diff[i + 2][1]; next = diff[i + 2][1];
return next.length > 1 && next.charCodeAt(0) == 10; return (next.length > 1 || i == diff.length - 3) && next.charCodeAt(0) == 10;
} }
function startOfLineClean(diff, i) { function startOfLineClean(diff, i) {
@ -728,6 +818,126 @@
return out; return out;
} }
// Tracks collapsed markers and line widgets, in order to be able to
// accurately align the content of two editors.
var F_WIDGET = 1, F_WIDGET_BELOW = 2, F_MARKER = 4
function TrackAlignable(cm) {
this.cm = cm
this.alignable = []
var self = this
cm.on("markerAdded", function(_, marker) {
if (!marker.collapsed) return
var found = marker.find(1)
if (found != null) self.set(found.line, F_MARKER)
})
cm.on("markerCleared", function(_, marker, _min, max) {
if (max != null && marker.collapsed)
self.check(max, F_MARKER, self.hasMarker)
})
cm.on("markerChanged", this.signal.bind(this))
cm.on("lineWidgetAdded", function(_, widget, lineNo) {
if (widget.mergeSpacer) return
if (widget.above) self.set(lineNo - 1, F_WIDGET_BELOW)
else self.set(lineNo, F_WIDGET)
})
cm.on("lineWidgetCleared", function(_, widget, lineNo) {
if (widget.mergeSpacer) return
if (widget.above) self.check(lineNo - 1, F_WIDGET_BELOW, self.hasWidgetBelow)
else self.check(lineNo, F_WIDGET, self.hasWidget)
})
cm.on("lineWidgetChanged", this.signal.bind(this))
cm.on("change", function(_, change) {
var start = change.from.line, nBefore = change.to.line - change.from.line
var nAfter = change.text.length - 1, end = start + nAfter
if (nBefore || nAfter) self.map(start, nBefore, nAfter)
self.check(end, F_MARKER, self.hasMarker)
if (nBefore || nAfter) self.check(change.from.line, F_MARKER, self.hasMarker)
})
}
TrackAlignable.prototype = {
signal: function() {
CodeMirror.signal(this, "realign")
},
set: function(n, flags) {
var pos = -1
for (; pos < this.alignable.length; pos += 2) {
var diff = this.alignable[pos] - n
if (diff == 0) {
if ((this.alignable[pos + 1] & flags) == flags) return
this.alignable[pos + 1] |= flags
this.signal()
return
}
if (diff > 0) break
}
this.signal()
this.alignable.splice(pos, 0, n, flags)
},
find: function(n) {
for (var i = 0; i < this.alignable.length; i += 2)
if (this.alignable[i] == n) return i
return -1
},
check: function(n, flag, pred) {
var found = this.find(n)
if (found == -1 || !(this.alignable[found + 1] & flag)) return
if (!pred.call(this, n)) {
this.signal()
var flags = this.alignable[found + 1] & ~flag
if (flags) this.alignable[found + 1] = flags
else this.alignable.splice(found, 2)
}
},
hasMarker: function(n) {
var handle = this.cm.getLineHandle(n)
if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++)
if (handle.markedSpans[i].mark.collapsed && handle.markedSpans[i].to != null)
return true
return false
},
hasWidget: function(n) {
var handle = this.cm.getLineHandle(n)
if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++)
if (!handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true
return false
},
hasWidgetBelow: function(n) {
if (n == this.cm.lastLine()) return false
var handle = this.cm.getLineHandle(n + 1)
if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++)
if (handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true
return false
},
map: function(from, nBefore, nAfter) {
var diff = nAfter - nBefore, to = from + nBefore, widgetFrom = -1, widgetTo = -1
for (var i = 0; i < this.alignable.length; i += 2) {
var n = this.alignable[i]
if (n == from && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetFrom = i
if (n == to && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetTo = i
if (n <= from) continue
else if (n < to) this.alignable.splice(i--, 2)
else this.alignable[i] += diff
}
if (widgetFrom > -1) {
var flags = this.alignable[widgetFrom + 1]
if (flags == F_WIDGET_BELOW) this.alignable.splice(widgetFrom, 2)
else this.alignable[widgetFrom + 1] = flags & ~F_WIDGET_BELOW
}
if (widgetTo > -1 && nAfter)
this.set(from + nAfter, F_WIDGET_BELOW)
}
}
function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; }
function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; }
function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }

View file

@ -76,8 +76,13 @@ CodeMirror.overlayMode = function(base, overlay, combine) {
innerMode: function(state) { return {state: state.base, mode: base}; }, innerMode: function(state) { return {state: state.base, mode: base}; },
blankLine: function(state) { blankLine: function(state) {
if (base.blankLine) base.blankLine(state.base); var baseToken, overlayToken;
if (overlay.blankLine) overlay.blankLine(state.overlay); if (base.blankLine) baseToken = base.blankLine(state.base);
if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay);
return overlayToken == null ?
baseToken :
(combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken);
} }
}; };
}; };

View file

@ -77,17 +77,21 @@
curLine = pos.line; curLine = pos.line;
curLineObj = cm.getLineHandle(curLine); curLineObj = cm.getLineHandle(curLine);
} }
if (wrapping && curLineObj.height > singleLineH) if ((curLineObj.widgets && curLineObj.widgets.length) ||
(wrapping && curLineObj.height > singleLineH))
return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
var topY = cm.heightAtLine(curLineObj, "local"); var topY = cm.heightAtLine(curLineObj, "local");
return topY + (top ? 0 : curLineObj.height); return topY + (top ? 0 : curLineObj.height);
} }
var lastLine = cm.lastLine()
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i]; var ann = anns[i];
if (ann.to.line > lastLine) continue;
var top = nextTop || getY(ann.from, true) * hScale; var top = nextTop || getY(ann.from, true) * hScale;
var bottom = getY(ann.to, false) * hScale; var bottom = getY(ann.to, false) * hScale;
while (i < anns.length - 1) { while (i < anns.length - 1) {
if (anns[i + 1].to.line > lastLine) break;
nextTop = getY(anns[i + 1].from, true) * hScale; nextTop = getY(anns[i + 1].from, true) * hScale;
if (nextTop > bottom + .9) break; if (nextTop > bottom + .9) break;
ann = anns[++i]; ann = anns[++i];

View file

@ -40,7 +40,9 @@
if (cm.state.scrollPastEndPadding != padding) { if (cm.state.scrollPastEndPadding != padding) {
cm.state.scrollPastEndPadding = padding; cm.state.scrollPastEndPadding = padding;
cm.display.lineSpace.parentNode.style.paddingBottom = padding; cm.display.lineSpace.parentNode.style.paddingBottom = padding;
cm.off("refresh", updateBottomMargin);
cm.setSize(); cm.setSize();
cm.on("refresh", updateBottomMargin);
} }
} }
}); });

View file

@ -59,22 +59,29 @@
CodeMirror.on(this.node, "DOMMouseScroll", onWheel); CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
} }
Bar.prototype.moveTo = function(pos, update) { Bar.prototype.setPos = function(pos, force) {
if (pos < 0) pos = 0; if (pos < 0) pos = 0;
if (pos > this.total - this.screen) pos = this.total - this.screen; if (pos > this.total - this.screen) pos = this.total - this.screen;
if (pos == this.pos) return; if (!force && pos == this.pos) return false;
this.pos = pos; this.pos = pos;
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
(pos * (this.size / this.total)) + "px"; (pos * (this.size / this.total)) + "px";
if (update !== false) this.scroll(pos, this.orientation); return true
}; };
Bar.prototype.moveTo = function(pos) {
if (this.setPos(pos)) this.scroll(pos, this.orientation);
}
var minButtonSize = 10; var minButtonSize = 10;
Bar.prototype.update = function(scrollSize, clientSize, barSize) { Bar.prototype.update = function(scrollSize, clientSize, barSize) {
var sizeChanged = this.screen != clientSize || this.total != scrollSize || this.size != barSize
if (sizeChanged) {
this.screen = clientSize; this.screen = clientSize;
this.total = scrollSize; this.total = scrollSize;
this.size = barSize; this.size = barSize;
}
var buttonSize = this.screen * (this.size / this.total); var buttonSize = this.screen * (this.size / this.total);
if (buttonSize < minButtonSize) { if (buttonSize < minButtonSize) {
@ -83,8 +90,7 @@
} }
this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
buttonSize + "px"; buttonSize + "px";
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = this.setPos(this.pos, sizeChanged);
this.pos * (this.size / this.total) + "px";
}; };
function SimpleScrollbars(cls, place, scroll) { function SimpleScrollbars(cls, place, scroll) {
@ -111,7 +117,6 @@
if (needsV) { if (needsV) {
this.vert.update(measure.scrollHeight, measure.clientHeight, this.vert.update(measure.scrollHeight, measure.clientHeight,
measure.viewHeight - (needsH ? width : 0)); measure.viewHeight - (needsH ? width : 0));
this.vert.node.style.display = "block";
this.vert.node.style.bottom = needsH ? width + "px" : "0"; this.vert.node.style.bottom = needsH ? width + "px" : "0";
} }
if (needsH) { if (needsH) {
@ -125,11 +130,11 @@
}; };
SimpleScrollbars.prototype.setScrollTop = function(pos) { SimpleScrollbars.prototype.setScrollTop = function(pos) {
this.vert.moveTo(pos, false); this.vert.setPos(pos);
}; };
SimpleScrollbars.prototype.setScrollLeft = function(pos) { SimpleScrollbars.prototype.setScrollLeft = function(pos) {
this.horiz.moveTo(pos, false); this.horiz.setPos(pos);
}; };
SimpleScrollbars.prototype.clear = function() { SimpleScrollbars.prototype.clear = function() {

View file

@ -16,81 +16,118 @@
// highlighted only if the selected text is a word. showToken, when enabled, // highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected. // will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before // delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. // highlighting the matches. If annotateScrollbar is enabled, the occurences
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod); define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var DEFAULT_MIN_CHARS = 2; var defaults = {
var DEFAULT_TOKEN_STYLE = "matchhighlight"; style: "matchhighlight",
var DEFAULT_DELAY = 100; minChars: 2,
var DEFAULT_WORDS_ONLY = false; delay: 100,
wordsOnly: false,
annotateScrollbar: false,
showToken: false,
trim: true
}
function State(options) { function State(options) {
if (typeof options == "object") { this.options = {}
this.minChars = options.minChars; for (var name in defaults)
this.style = options.style; this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.showToken = options.showToken;
this.delay = options.delay;
this.wordsOnly = options.wordsOnly;
}
if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
if (this.delay == null) this.delay = DEFAULT_DELAY;
if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;
this.overlay = this.timeout = null; this.overlay = this.timeout = null;
this.matchesonscroll = null;
this.active = false;
} }
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) { if (old && old != CodeMirror.Init) {
var over = cm.state.matchHighlighter.overlay; removeOverlay(cm);
if (over) cm.removeOverlay(over);
clearTimeout(cm.state.matchHighlighter.timeout); clearTimeout(cm.state.matchHighlighter.timeout);
cm.state.matchHighlighter = null; cm.state.matchHighlighter = null;
cm.off("cursorActivity", cursorActivity); cm.off("cursorActivity", cursorActivity);
cm.off("focus", onFocus)
} }
if (val) { if (val) {
cm.state.matchHighlighter = new State(val); var state = cm.state.matchHighlighter = new State(val);
highlightMatches(cm); if (cm.hasFocus()) {
state.active = true
highlightMatches(cm)
} else {
cm.on("focus", onFocus)
}
cm.on("cursorActivity", cursorActivity); cm.on("cursorActivity", cursorActivity);
} }
}); });
function cursorActivity(cm) { function cursorActivity(cm) {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
}
function onFocus(cm) {
var state = cm.state.matchHighlighter
if (!state.active) {
state.active = true
scheduleHighlight(cm, state)
}
}
function scheduleHighlight(cm, state) {
clearTimeout(state.timeout); clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
}
function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"});
}
}
function removeOverlay(cm) {
var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
if (state.matchesonscroll) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
}
}
} }
function highlightMatches(cm) { function highlightMatches(cm) {
cm.operation(function() { cm.operation(function() {
var state = cm.state.matchHighlighter; var state = cm.state.matchHighlighter;
if (state.overlay) { removeOverlay(cm);
cm.removeOverlay(state.overlay); if (!cm.somethingSelected() && state.options.showToken) {
state.overlay = null; var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
}
if (!cm.somethingSelected() && state.showToken) {
var re = state.showToken === true ? /[\w$]/ : state.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start; while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end; while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end) if (start < end)
cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); addOverlay(cm, line.slice(start, end), re, state.options.style);
return; return;
} }
var from = cm.getCursor("from"), to = cm.getCursor("to"); var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return; if (from.line != to.line) return;
if (state.wordsOnly && !isWord(cm, from, to)) return; if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); var selection = cm.getRange(from, to)
if (selection.length >= state.minChars) if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style);
}); });
} }

View file

@ -57,12 +57,13 @@
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query)); return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
} }
function persistentDialog(cm, text, deflt, f) { function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
cm.openDialog(text, f, { cm.openDialog(text, onEnter, {
value: deflt, value: deflt,
selectValueOnOpen: true, selectValueOnOpen: true,
closeOnEnter: false, closeOnEnter: false,
onClose: function() { clearSearch(cm); } onClose: function() { clearSearch(cm); },
onKeyDown: onKeyDown
}); });
} }
@ -112,16 +113,19 @@
} }
} }
function doSearch(cm, rev, persistent) { function doSearch(cm, rev, persistent, immediate) {
var state = getSearchState(cm); var state = getSearchState(cm);
if (state.query) return findNext(cm, rev); if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery; var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) { if (persistent && cm.openDialog) {
var hiding = null var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) { var searchNext = function(query, event) {
CodeMirror.e_stop(event); CodeMirror.e_stop(event);
if (!query) return; if (!query) return;
if (query != state.queryText) startSearch(cm, state, query); if (query != state.queryText) {
startSearch(cm, state, query);
state.posFrom = state.posTo = cm.getCursor();
}
if (hiding) hiding.style.opacity = 1 if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) { findNext(cm, event.shiftKey, function(_, to) {
var dialog var dialog
@ -130,7 +134,25 @@
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4 (hiding = dialog).style.opacity = .4
}) })
};
persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
var keyName = CodeMirror.keyName(event)
var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
if (cmd == "findNext" || cmd == "findPrev" ||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
CodeMirror.e_stop(event);
startSearch(cm, getSearchState(cm), query);
cm.execCommand(cmd);
} else if (cmd == "find" || cmd == "findPersistent") {
CodeMirror.e_stop(event);
searchNext(query, event);
}
}); });
if (immediate && q) {
startSearch(cm, state, q);
findNext(cm, rev);
}
} else { } else {
dialog(cm, queryDialog, "Search for:", q, function(query) { dialog(cm, queryDialog, "Search for:", q, function(query) {
if (query && !state.query) cm.operation(function() { if (query && !state.query) cm.operation(function() {
@ -193,7 +215,7 @@
replaceAll(cm, query, text) replaceAll(cm, query, text)
} else { } else {
clearSearch(cm); clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor()); var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() { var advance = function() {
var start = cursor.from(), match; var start = cursor.from(), match;
if (!(match = cursor.findNext())) { if (!(match = cursor.findNext())) {
@ -220,6 +242,8 @@
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
CodeMirror.commands.findNext = doSearch; CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch; CodeMirror.commands.clearSearch = clearSearch;

View file

@ -1,12 +1,6 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// Because sometimes you need to style the cursor's line.
//
// Adds an option 'styleActiveLine' which, when enabled, gives the
// active line's wrapping <div> the CSS class "CodeMirror-activeline",
// and gives its background <div> the class "CodeMirror-activeline-background".
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
@ -18,24 +12,28 @@
"use strict"; "use strict";
var WRAP_CLASS = "CodeMirror-activeline"; var WRAP_CLASS = "CodeMirror-activeline";
var BACK_CLASS = "CodeMirror-activeline-background"; var BACK_CLASS = "CodeMirror-activeline-background";
var GUTT_CLASS = "CodeMirror-activeline-gutter";
CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
var prev = old && old != CodeMirror.Init; var prev = old == CodeMirror.Init ? false : old;
if (val && !prev) { if (val == prev) return
cm.state.activeLines = []; if (prev) {
updateActiveLines(cm, cm.listSelections());
cm.on("beforeSelectionChange", selectionChange);
} else if (!val && prev) {
cm.off("beforeSelectionChange", selectionChange); cm.off("beforeSelectionChange", selectionChange);
clearActiveLines(cm); clearActiveLines(cm);
delete cm.state.activeLines; delete cm.state.activeLines;
} }
if (val) {
cm.state.activeLines = [];
updateActiveLines(cm, cm.listSelections());
cm.on("beforeSelectionChange", selectionChange);
}
}); });
function clearActiveLines(cm) { function clearActiveLines(cm) {
for (var i = 0; i < cm.state.activeLines.length; i++) { for (var i = 0; i < cm.state.activeLines.length; i++) {
cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS);
} }
} }
@ -50,7 +48,9 @@
var active = []; var active = [];
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
var range = ranges[i]; var range = ranges[i];
if (!range.empty()) continue; var option = cm.getOption("styleActiveLine");
if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty())
continue
var line = cm.getLineHandleVisualStart(range.head.line); var line = cm.getLineHandleVisualStart(range.head.line);
if (active[active.length - 1] != line) active.push(line); if (active[active.length - 1] != line) active.push(line);
} }
@ -60,6 +60,7 @@
for (var i = 0; i < active.length; i++) { for (var i = 0; i < active.length; i++) {
cm.addLineClass(active[i], "wrap", WRAP_CLASS); cm.addLineClass(active[i], "wrap", WRAP_CLASS);
cm.addLineClass(active[i], "background", BACK_CLASS); cm.addLineClass(active[i], "background", BACK_CLASS);
cm.addLineClass(active[i], "gutter", GUTT_CLASS);
} }
cm.state.activeLines = active; cm.state.activeLines = active;
}); });

View file

@ -179,7 +179,7 @@
var data = findDoc(ts, doc); var data = findDoc(ts, doc);
var argHints = ts.cachedArgHints; var argHints = ts.cachedArgHints;
if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0)
ts.cachedArgHints = null; ts.cachedArgHints = null;
var changed = data.changed; var changed = data.changed;
@ -306,7 +306,7 @@
ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
if (error || !data.type || !(/^fn\(/).test(data.type)) return; if (error || !data.type || !(/^fn\(/).test(data.type)) return;
ts.cachedArgHints = { ts.cachedArgHints = {
start: pos, start: start,
type: parseFnType(data.type), type: parseFnType(data.type),
name: data.exprName || data.name || "fn", name: data.exprName || data.name || "fn",
guess: data.guess, guess: data.guess,

View file

@ -30,7 +30,9 @@
} }
function findBreakPoint(text, column, wrapOn, killTrailingSpace) { function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
for (var at = column; at > 0; --at) var at = column
while (at < text.length && text.charAt(at) == " ") at++
for (; at > 0; --at)
if (wrapOn.test(text.slice(at - 1, at + 1))) break; if (wrapOn.test(text.slice(at - 1, at + 1))) break;
for (var first = true;; first = false) { for (var first = true;; first = false) {
var endOfText = at; var endOfText = at;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
<!doctype html> <!doctype html>
<title>CodeMirror: ASN.1 mode</title> <title>CodeMirror: ASN.1 mode</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
@ -74,5 +74,4 @@
</a>.</p> </a>.</p>
<p>Coded by Asmelash Tsegay Gebretsadkan </p> <p>Coded by Asmelash Tsegay Gebretsadkan </p>
</article> </article>
</article>

View file

@ -11,6 +11,41 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function Context(indented, column, type, info, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.info = info;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type, info) {
var indent = state.indented;
if (state.context && state.context.type == "statement" && type != "statement")
indent = state.context.indented;
return state.context = new Context(indent, col, type, info, null, state.context);
}
function popContext(state) {
var t = state.context.type;
if (t == ")" || t == "]" || t == "}")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
function typeBefore(stream, state, pos) {
if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
}
function isTopScope(context) {
for (;;) {
if (!context || context.type == "top") return true;
if (context.type == "}" && context.prev.info != "namespace") return false;
context = context.prev;
}
}
CodeMirror.defineMode("clike", function(config, parserConfig) { CodeMirror.defineMode("clike", function(config, parserConfig) {
var indentUnit = config.indentUnit, var indentUnit = config.indentUnit,
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
@ -29,8 +64,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
numberStart = parserConfig.numberStart || /[\d\.]/, numberStart = parserConfig.numberStart || /[\d\.]/,
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/, isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/;
endStatement = parserConfig.endStatement || /^[;:,]$/;
var curPunc, isDefKeyword; var curPunc, isDefKeyword;
@ -64,7 +98,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
} }
} }
if (isOperatorChar.test(ch)) { if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar); while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
return "operator"; return "operator";
} }
stream.eatWhile(/[\w\$_\xa1-\uffff]/); stream.eatWhile(/[\w\$_\xa1-\uffff]/);
@ -111,40 +145,9 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "comment"; return "comment";
} }
function Context(indented, column, type, align, prev) { function maybeEOL(stream, state) {
this.indented = indented; if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
this.column = column; state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
this.type = type;
this.align = align;
this.prev = prev;
}
function isStatement(type) {
return type == "statement" || type == "switchstatement" || type == "namespace";
}
function pushContext(state, col, type) {
var indent = state.indented;
if (state.context && isStatement(state.context.type) && !isStatement(type))
indent = state.context.indented;
return state.context = new Context(indent, col, type, null, state.context);
}
function popContext(state) {
var t = state.context.type;
if (t == ")" || t == "]" || t == "}")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
function typeBefore(stream, state) {
if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true;
}
function isTopScope(context) {
for (;;) {
if (!context || context.type == "top") return true;
if (context.type == "}" && context.prev.type != "namespace") return false;
context = context.prev;
}
} }
// Interface // Interface
@ -153,7 +156,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
startState: function(basecolumn) { startState: function(basecolumn) {
return { return {
tokenize: null, tokenize: null,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
indented: 0, indented: 0,
startOfLine: true, startOfLine: true,
prevToken: null prevToken: null
@ -167,36 +170,32 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
state.indented = stream.indentation(); state.indented = stream.indentation();
state.startOfLine = true; state.startOfLine = true;
} }
if (stream.eatSpace()) return null; if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
curPunc = isDefKeyword = null; curPunc = isDefKeyword = null;
var style = (state.tokenize || tokenBase)(stream, state); var style = (state.tokenize || tokenBase)(stream, state);
if (style == "comment" || style == "meta") return style; if (style == "comment" || style == "meta") return style;
if (ctx.align == null) ctx.align = true; if (ctx.align == null) ctx.align = true;
if (endStatement.test(curPunc)) while (isStatement(state.context.type)) popContext(state); if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
while (state.context.type == "statement") popContext(state);
else if (curPunc == "{") pushContext(state, stream.column(), "}"); else if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]"); else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")"); else if (curPunc == "(") pushContext(state, stream.column(), ")");
else if (curPunc == "}") { else if (curPunc == "}") {
while (isStatement(ctx.type)) ctx = popContext(state); while (ctx.type == "statement") ctx = popContext(state);
if (ctx.type == "}") ctx = popContext(state); if (ctx.type == "}") ctx = popContext(state);
while (isStatement(ctx.type)) ctx = popContext(state); while (ctx.type == "statement") ctx = popContext(state);
} }
else if (curPunc == ctx.type) popContext(state); else if (curPunc == ctx.type) popContext(state);
else if (indentStatements && else if (indentStatements &&
(((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
(isStatement(ctx.type) && curPunc == "newstatement"))) { (ctx.type == "statement" && curPunc == "newstatement"))) {
var type = "statement"; pushContext(state, stream.column(), "statement", stream.current());
if (curPunc == "newstatement" && indentSwitch && stream.current() == "switch")
type = "switchstatement";
else if (style == "keyword" && stream.current() == "namespace")
type = "namespace";
pushContext(state, stream.column(), type);
} }
if (style == "variable" && if (style == "variable" &&
((state.prevToken == "def" || ((state.prevToken == "def" ||
(parserConfig.typeFirstDefinitions && typeBefore(stream, state) && (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
isTopScope(state.context) && stream.match(/^\s*\(/, false))))) isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
style = "def"; style = "def";
@ -209,24 +208,28 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
state.startOfLine = false; state.startOfLine = false;
state.prevToken = isDefKeyword ? "def" : style || curPunc; state.prevToken = isDefKeyword ? "def" : style || curPunc;
maybeEOL(stream, state);
return style; return style;
}, },
indent: function(state, textAfter) { indent: function(state, textAfter) {
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev; if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
if (parserConfig.dontIndentStatements)
while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
ctx = ctx.prev
if (hooks.indent) { if (hooks.indent) {
var hook = hooks.indent(state, ctx, textAfter); var hook = hooks.indent(state, ctx, textAfter);
if (typeof hook == "number") return hook if (typeof hook == "number") return hook
} }
var closing = firstChar == ctx.type; var closing = firstChar == ctx.type;
var switchBlock = ctx.prev && ctx.prev.type == "switchstatement"; var switchBlock = ctx.prev && ctx.prev.info == "switch";
if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
return ctx.indented return ctx.indented
} }
if (isStatement(ctx.type)) if (ctx.type == "statement")
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
if (ctx.align && (!dontAlignCalls || ctx.type != ")")) if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
return ctx.column + (closing ? 0 : 1); return ctx.column + (closing ? 0 : 1);
@ -264,9 +267,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
function cppHook(stream, state) { function cppHook(stream, state) {
if (!state.startOfLine) return false if (!state.startOfLine) return false
for (var ch, next = null; ch = stream.peek();) { for (var ch, next = null; ch = stream.peek();) {
if (!ch) { if (ch == "\\" && stream.match(/^.$/)) {
break
} else if (ch == "\\" && stream.match(/^.$/)) {
next = cppHook next = cppHook
break break
} else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
@ -388,6 +389,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
defKeywords: words("class namespace struct enum union"), defKeywords: words("class namespace struct enum union"),
typeFirstDefinitions: true, typeFirstDefinitions: true,
atoms: words("true false null"), atoms: words("true false null"),
dontIndentStatements: /^template$/,
hooks: { hooks: {
"#": cppHook, "#": cppHook,
"*": pointerHook, "*": pointerHook,
@ -423,16 +425,19 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
"do else enum extends final finally float for goto if implements import " + "do else enum extends final finally float for goto if implements import " +
"instanceof interface native new package private protected public " + "instanceof interface native new package private protected public " +
"return static strictfp super switch synchronized this throw throws transient " + "return static strictfp super switch synchronized this throw throws transient " +
"try volatile while"), "try volatile while @interface"),
types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
"Integer Long Number Object Short String StringBuffer StringBuilder Void"), "Integer Long Number Object Short String StringBuffer StringBuilder Void"),
blockKeywords: words("catch class do else finally for if switch try while"), blockKeywords: words("catch class do else finally for if switch try while"),
defKeywords: words("class interface package enum"), defKeywords: words("class interface package enum @interface"),
typeFirstDefinitions: true, typeFirstDefinitions: true,
atoms: words("true false null"), atoms: words("true false null"),
endStatement: /^[;:]$/, number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
hooks: { hooks: {
"@": function(stream) { "@": function(stream) {
// Don't match the @interface keyword.
if (stream.match('interface', false)) return false;
stream.eatWhile(/[\w\$_]/); stream.eatWhile(/[\w\$_]/);
return "meta"; return "meta";
} }
@ -488,18 +493,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
/* scala */ /* scala */
"abstract case catch class def do else extends final finally for forSome if " + "abstract case catch class def do else extends final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " + "implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try type val var while with yield _ : = => <- <: " + "sealed super this throw trait try type val var while with yield _ " +
"<% >: # @ " +
/* package scala */ /* package scala */
"assert assume require print println printf readLine readBoolean readByte readShort " + "assert assume require print println printf readLine readBoolean readByte readShort " +
"readChar readInt readLong readFloat readDouble " + "readChar readInt readLong readFloat readDouble"
":: #:: "
), ),
types: words( types: words(
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
@ -516,6 +518,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
atoms: words("true false null"), atoms: words("true false null"),
indentStatements: false, indentStatements: false,
indentSwitch: false, indentSwitch: false,
isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
hooks: { hooks: {
"@": function(stream) { "@": function(stream) {
stream.eatWhile(/[\w\$_]/); stream.eatWhile(/[\w\$_]/);
@ -529,6 +532,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
"'": function(stream) { "'": function(stream) {
stream.eatWhile(/[\w\$_\xa1-\uffff]/); stream.eatWhile(/[\w\$_\xa1-\uffff]/);
return "atom"; return "atom";
},
"=": function(stream, state) {
var cx = state.context
if (cx.type == "}" && cx.align && stream.eat(">")) {
state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
return "operator"
} else {
return false
}
} }
}, },
modeProps: {closeBrackets: {triples: '"'}} modeProps: {closeBrackets: {triples: '"'}}
@ -660,7 +672,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
def("text/x-objectivec", { def("text/x-objectivec", {
name: "clike", name: "clike",
keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in " + keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " +
"inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"), "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),
types: words(cTypes), types: words(cTypes),
atoms: words("YES NO NULL NILL ON OFF true false"), atoms: words("YES NO NULL NILL ON OFF true false"),

View file

@ -25,6 +25,10 @@
"[keyword struct] [def bar]{}", "[keyword struct] [def bar]{}",
"[variable-3 int] [variable-3 *][def baz]() {}"); "[variable-3 int] [variable-3 *][def baz]() {}");
MT("def_new_line",
"::[variable std]::[variable SomeTerribleType][operator <][variable T][operator >]",
"[def SomeLongMethodNameThatDoesntFitIntoOneLine]([keyword const] [variable MyType][operator &] [variable param]) {}")
MT("double_block", MT("double_block",
"[keyword for] (;;)", "[keyword for] (;;)",
" [keyword for] (;;)", " [keyword for] (;;)",

File diff suppressed because one or more lines are too long

View file

@ -78,6 +78,9 @@
\tab \return \backspace \tab \return \backspace
\u1000 \uAaAa \u9F9F) \u1000 \uAaAa \u9F9F)
;; Let's play with numbers
(+ 1 -1 1/2 -1/2 -0.5 0.5)
</textarea></form> </textarea></form>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {}); var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});

View file

@ -43,11 +43,12 @@ CodeMirror.defineMode("commonlisp", function (config) {
else { stream.skipToEnd(); return "error"; } else { stream.skipToEnd(); return "error"; }
} else if (ch == "#") { } else if (ch == "#") {
var ch = stream.next(); var ch = stream.next();
if (ch == "[") { type = "open"; return "bracket"; } if (ch == "(") { type = "open"; return "bracket"; }
else if (/[+\-=\.']/.test(ch)) return null; else if (/[+\-=\.']/.test(ch)) return null;
else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null; else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null;
else if (ch == "|") return (state.tokenize = inComment)(stream, state); else if (ch == "|") return (state.tokenize = inComment)(stream, state);
else if (ch == ":") { readSym(stream); return "meta"; } else if (ch == ":") { readSym(stream); return "meta"; }
else if (ch == "\\") { stream.next(); readSym(stream); return "string-2" }
else return "error"; else return "error";
} else { } else {
var name = readSym(stream); var name = readSym(stream);

View file

@ -29,26 +29,22 @@
var types = /^[A-Z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/; var types = /^[A-Z_\u009F-\uFFFF][a-zA-Z0-9_\u009F-\uFFFF]*/;
var keywords = wordRegExp([ var keywords = wordRegExp([
"abstract", "alias", "as", "asm", "begin", "break", "case", "class", "def", "do", "abstract", "alias", "as", "asm", "begin", "break", "case", "class", "def", "do",
"else", "elsif", "end", "ensure", "enum", "extend", "for", "fun", "if", "ifdef", "else", "elsif", "end", "ensure", "enum", "extend", "for", "fun", "if",
"include", "instance_sizeof", "lib", "macro", "module", "next", "of", "out", "pointerof", "include", "instance_sizeof", "lib", "macro", "module", "next", "of", "out", "pointerof",
"private", "protected", "rescue", "return", "require", "sizeof", "struct", "private", "protected", "rescue", "return", "require", "select", "sizeof", "struct",
"super", "then", "type", "typeof", "union", "unless", "until", "when", "while", "with", "super", "then", "type", "typeof", "uninitialized", "union", "unless", "until", "when", "while", "with",
"yield", "__DIR__", "__FILE__", "__LINE__" "yield", "__DIR__", "__END_LINE__", "__FILE__", "__LINE__"
]); ]);
var atomWords = wordRegExp(["true", "false", "nil", "self"]); var atomWords = wordRegExp(["true", "false", "nil", "self"]);
var indentKeywordsArray = [ var indentKeywordsArray = [
"def", "fun", "macro", "def", "fun", "macro",
"class", "module", "struct", "lib", "enum", "union", "class", "module", "struct", "lib", "enum", "union",
"if", "unless", "case", "while", "until", "begin", "then", "do", "for"
"do",
"for", "ifdef"
]; ];
var indentKeywords = wordRegExp(indentKeywordsArray); var indentKeywords = wordRegExp(indentKeywordsArray);
var dedentKeywordsArray = [ var indentExpressionKeywordsArray = ["if", "unless", "case", "while", "until", "begin", "then"];
"end", var indentExpressionKeywords = wordRegExp(indentExpressionKeywordsArray);
"else", "elsif", var dedentKeywordsArray = ["end", "else", "elsif", "rescue", "ensure"];
"rescue", "ensure"
];
var dedentKeywords = wordRegExp(dedentKeywordsArray); var dedentKeywords = wordRegExp(dedentKeywordsArray);
var dedentPunctualsArray = ["\\)", "\\}", "\\]"]; var dedentPunctualsArray = ["\\)", "\\}", "\\]"];
var dedentPunctuals = new RegExp("^(?:" + dedentPunctualsArray.join("|") + ")$"); var dedentPunctuals = new RegExp("^(?:" + dedentPunctualsArray.join("|") + ")$");
@ -90,12 +86,15 @@
} else if (state.lastToken == ".") { } else if (state.lastToken == ".") {
return "property"; return "property";
} else if (keywords.test(matched)) { } else if (keywords.test(matched)) {
if (state.lastToken != "abstract" && indentKeywords.test(matched)) { if (indentKeywords.test(matched)) {
if (!(matched == "fun" && state.blocks.indexOf("lib") >= 0)) { if (!(matched == "fun" && state.blocks.indexOf("lib") >= 0) && !(matched == "def" && state.lastToken == "abstract")) {
state.blocks.push(matched); state.blocks.push(matched);
state.currentIndent += 1; state.currentIndent += 1;
} }
} else if (dedentKeywords.test(matched)) { } else if ((state.lastStyle == "operator" || !state.lastStyle) && indentExpressionKeywords.test(matched)) {
state.blocks.push(matched);
state.currentIndent += 1;
} else if (matched == "end") {
state.blocks.pop(); state.blocks.pop();
state.currentIndent -= 1; state.currentIndent -= 1;
} }
@ -124,12 +123,6 @@
return "variable-2"; return "variable-2";
} }
// Global variables
if (stream.eat("$")) {
stream.eat(/[0-9]+|\?/) || stream.match(idents) || stream.match(types);
return "variable-3";
}
// Constants and types // Constants and types
if (stream.match(types)) { if (stream.match(types)) {
return "tag"; return "tag";
@ -165,6 +158,9 @@
} else if (stream.match("%w")) { } else if (stream.match("%w")) {
embed = false; embed = false;
delim = stream.next(); delim = stream.next();
} else if (stream.match("%q")) {
embed = false;
delim = stream.next();
} else { } else {
if(delim = stream.match(/^%([^\w\s=])/)) { if(delim = stream.match(/^%([^\w\s=])/)) {
delim = delim[1]; delim = delim[1];
@ -183,6 +179,11 @@
return chain(tokenQuote(delim, style, embed), stream, state); return chain(tokenQuote(delim, style, embed), stream, state);
} }
// Here Docs
if (matched = stream.match(/^<<-('?)([A-Z]\w*)\1/)) {
return chain(tokenHereDoc(matched[2], !matched[1]), stream, state)
}
// Characters // Characters
if (stream.eat("'")) { if (stream.eat("'")) {
stream.match(/^(?:[^']|\\(?:[befnrtv0'"]|[0-7]{3}|u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]{1,6}\})))/); stream.match(/^(?:[^']|\\(?:[befnrtv0'"]|[0-7]{3}|u(?:[0-9a-fA-F]{4}|\{[0-9a-fA-F]{1,6}\})))/);
@ -202,14 +203,14 @@
return "number"; return "number";
} }
if (stream.eat(/\d/)) { if (stream.eat(/^\d/)) {
stream.match(/^\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/); stream.match(/^\d*(?:\.\d+)?(?:[eE][+-]?\d+)?/);
return "number"; return "number";
} }
// Operators // Operators
if (stream.match(operators)) { if (stream.match(operators)) {
stream.eat("="); // Operators can follow assigin symbol. stream.eat("="); // Operators can follow assign symbol.
return "operator"; return "operator";
} }
@ -339,7 +340,7 @@
return style; return style;
} }
escaped = ch == "\\"; escaped = embed && ch == "\\";
} else { } else {
stream.next(); stream.next();
escaped = false; escaped = false;
@ -350,12 +351,52 @@
}; };
} }
function tokenHereDoc(phrase, embed) {
return function (stream, state) {
if (stream.sol()) {
stream.eatSpace()
if (stream.match(phrase)) {
state.tokenize.pop();
return "string";
}
}
var escaped = false;
while (stream.peek()) {
if (!escaped) {
if (stream.match("{%", false)) {
state.tokenize.push(tokenMacro("%", "%"));
return "string";
}
if (stream.match("{{", false)) {
state.tokenize.push(tokenMacro("{", "}"));
return "string";
}
if (embed && stream.match("#{", false)) {
state.tokenize.push(tokenNest("#{", "}", "meta"));
return "string";
}
escaped = embed && stream.next() == "\\";
} else {
stream.next();
escaped = false;
}
}
return "string";
}
}
return { return {
startState: function () { startState: function () {
return { return {
tokenize: [tokenBase], tokenize: [tokenBase],
currentIndent: 0, currentIndent: 0,
lastToken: null, lastToken: null,
lastStyle: null,
blocks: [] blocks: []
}; };
}, },
@ -366,6 +407,7 @@
if (style && style != "comment") { if (style && style != "comment") {
state.lastToken = token; state.lastToken = token;
state.lastStyle = style;
} }
return style; return style;

View file

@ -48,8 +48,6 @@ puts "Listening on http://0.0.0.0:8080"
server.listen server.listen
module Foo module Foo
def initialize(@foo); end
abstract def abstract_method : String abstract def abstract_method : String
@[AlwaysInline] @[AlwaysInline]
@ -58,7 +56,8 @@ module Foo
end end
struct Foo struct Foo
def initialize(@foo); end def initialize(@foo : ::Foo)
end
def hello_world def hello_world
@foo.abstract_method @foo.abstract_method
@ -71,8 +70,7 @@ class Bar
@@foobar = 12345 @@foobar = 12345
def initialize(@bar) def initialize(@bar : Int32)
super(@bar.not_nil! + 100)
end end
macro alias_method(name, method) macro alias_method(name, method)
@ -87,11 +85,10 @@ class Bar
alias_method abstract_method, a_method alias_method abstract_method, a_method
macro def show_instance_vars : Nil def show_instance_vars : Nil
{% for var in @type.instance_vars %} {% for var in @type.instance_vars %}
puts "@{{ var }} = #{ @{{ var }} }" puts "@{{ var }} = #{ @{{ var }} }"
{% end %} {% end %}
nil
end end
end end
@ -101,9 +98,9 @@ lib LibC
fun c_puts = "puts"(str : Char*) : Int fun c_puts = "puts"(str : Char*) : Int
end end
$baz = Baz.new(100) baz = Baz.new(100)
$baz.show_instance_vars baz.show_instance_vars
$baz.with_foofoo do baz.with_foofoo do
LibC.c_puts hello_world LibC.c_puts hello_world
end end
</textarea></form> </textarea></form>

View file

@ -28,6 +28,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
colorKeywords = parserConfig.colorKeywords || {}, colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {}, valueKeywords = parserConfig.valueKeywords || {},
allowNested = parserConfig.allowNested, allowNested = parserConfig.allowNested,
lineComment = parserConfig.lineComment,
supportsAtComponent = parserConfig.supportsAtComponent === true; supportsAtComponent = parserConfig.supportsAtComponent === true;
var type, override; var type, override;
@ -253,6 +254,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
}; };
states.pseudo = function(type, stream, state) { states.pseudo = function(type, stream, state) {
if (type == "meta") return "pseudo";
if (type == "word") { if (type == "word") {
override = "variable-3"; override = "variable-3";
return state.context.type; return state.context.type;
@ -407,6 +410,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
electricChars: "}", electricChars: "}",
blockCommentStart: "/*", blockCommentStart: "/*",
blockCommentEnd: "*/", blockCommentEnd: "*/",
lineComment: lineComment,
fold: "brace" fold: "brace"
}; };
}); });
@ -414,7 +418,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
function keySet(array) { function keySet(array) {
var keys = {}; var keys = {};
for (var i = 0; i < array.length; ++i) { for (var i = 0; i < array.length; ++i) {
keys[array[i]] = true; keys[array[i].toLowerCase()] = true;
} }
return keys; return keys;
} }
@ -452,8 +456,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"animation-direction", "animation-duration", "animation-fill-mode", "animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state", "animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility", "animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-clip", "background-color", "background", "background-attachment", "background-blend-mode", "background-clip",
"background-image", "background-origin", "background-position", "background-color", "background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding", "background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state", "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color", "bookmark-target", "border", "border-bottom", "border-bottom-color",
@ -484,9 +488,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position", "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end", "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
"grid-column-start", "grid-row", "grid-row-end", "grid-row-start", "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
"grid-template", "grid-template-areas", "grid-template-columns", "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens", "grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution", "icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing", "inline-box-align", "justify-content", "left", "letter-spacing",
@ -494,7 +498,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"line-stacking-shift", "line-stacking-strategy", "list-style", "line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin", "list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top", "margin-bottom", "margin-left", "margin-right", "margin-top",
"marker-offset", "marks", "marquee-direction", "marquee-loop", "marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height", "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position", "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
@ -522,9 +526,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"text-wrap", "top", "transform", "transform-origin", "transform-style", "text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration", "transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi", "transition-property", "transition-timing-function", "unicode-bidi",
"vertical-align", "visibility", "voice-balance", "voice-duration", "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "word-break", "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
"word-spacing", "word-wrap", "z-index", "word-spacing", "word-wrap", "z-index",
// SVG-specific // SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
@ -589,7 +593,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"above", "absolute", "activeborder", "additive", "activecaption", "afar", "above", "absolute", "activeborder", "additive", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
@ -597,11 +601,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "column", "column-reverse", "compact", "condensed", "contain", "content", "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
"compact", "condensed", "contain", "content", "contents",
"content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "cyclic", "dashed", "decimal", "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "destination-atop", "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari", "destination-in", "destination-out", "destination-over", "devanagari", "difference",
"disc", "discard", "disclosure-closed", "disclosure-open", "document", "disc", "discard", "disclosure-closed", "disclosure-open", "document",
"dot-dash", "dot-dot-dash", "dot-dash", "dot-dot-dash",
"dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
@ -612,23 +617,23 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"ethiopic-halehame-gez", "ethiopic-halehame-om-et", "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
"ethiopic-numeric", "ew-resize", "expanded", "extends", "extra-condensed", "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext", "help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert", "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "japanese-formal", "japanese-informal", "justify", "kannada", "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
"katakana", "katakana-iroha", "keep-all", "khmer", "katakana", "katakana-iroha", "keep-all", "khmer",
"korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
"landscape", "lao", "large", "larger", "left", "level", "lighter", "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
"line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "malayalam", "match", "matrix", "matrix3d", "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
"media-controls-background", "media-current-time-display", "media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button", "media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button", "media-return-to-realtime-button", "media-rewind-button",
@ -637,10 +642,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"media-volume-slider-container", "media-volume-sliderthumb", "medium", "media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text", "menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
@ -651,15 +656,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
"rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
"rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
"scroll", "scrollbar", "se-resize", "searchfield", "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration", "searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration", "searchfield-results-button", "searchfield-results-decoration",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"simp-chinese-formal", "simp-chinese-informal", "single", "simp-chinese-formal", "simp-chinese-informal", "single",
"skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "solid", "somali", "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square", "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
"subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table", "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table",
@ -670,9 +675,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"trad-chinese-formal", "trad-chinese-informal", "trad-chinese-formal", "trad-chinese-informal", "transform",
"translate", "translate3d", "translateX", "translateY", "translateZ", "translate", "translate3d", "translateX", "translateY", "translateZ",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
@ -729,6 +734,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
valueKeywords: valueKeywords, valueKeywords: valueKeywords,
fontProperties: fontProperties, fontProperties: fontProperties,
allowNested: true, allowNested: true,
lineComment: "//",
tokenHooks: { tokenHooks: {
"/": function(stream, state) { "/": function(stream, state) {
if (stream.eat("/")) { if (stream.eat("/")) {
@ -771,6 +777,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
valueKeywords: valueKeywords, valueKeywords: valueKeywords,
fontProperties: fontProperties, fontProperties: fontProperties,
allowNested: true, allowNested: true,
lineComment: "//",
tokenHooks: { tokenHooks: {
"/": function(stream, state) { "/": function(stream, state) {
if (stream.eat("/")) { if (stream.eat("/")) {

View file

@ -64,7 +64,7 @@ code {
</textarea></form> </textarea></form>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), { var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
extraKeys: {"Ctrl-Space": "autocomplete"}, extraKeys: {"Ctrl-Space": "autocomplete"}
}); });
</script> </script>

View file

@ -26,10 +26,10 @@
MT("mixin", MT("mixin",
"[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {",
" [property color]: [variable darken]([variable-2 @color], [number 10%]);", " [property color]: [atom darken]([variable-2 @color], [number 10%]);",
"}", "}",
"[qualifier .mixin] ([variable light]; [variable-2 @color]) {", "[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
" [property color]: [variable lighten]([variable-2 @color], [number 10%]);", " [property color]: [atom lighten]([variable-2 @color], [number 10%]);",
"}", "}",
"[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {",
" [property display]: [atom block];", " [property display]: [atom block];",

View file

@ -95,7 +95,7 @@
MT('indent_parentheses', MT('indent_parentheses',
"[tag foo] {", "[tag foo] {",
" [property color]: [variable darken]([variable-2 $blue],", " [property color]: [atom darken]([variable-2 $blue],",
" [number 9%]);", " [number 9%]);",
"}"); "}");

View file

@ -20,8 +20,12 @@
CodeMirror.defineMode("cypher", function(config) { CodeMirror.defineMode("cypher", function(config) {
var tokenBase = function(stream/*, state*/) { var tokenBase = function(stream/*, state*/) {
var ch = stream.next(); var ch = stream.next();
if (ch === "\"" || ch === "'") { if (ch ==='"') {
stream.match(/.+?["']/); stream.match(/.*?"/);
return "string";
}
if (ch === "'") {
stream.match(/.*?'/);
return "string"; return "string";
} }
if (/[{}\(\),\.;\[\]]/.test(ch)) { if (/[{}\(\),\.;\[\]]/.test(ch)) {
@ -62,7 +66,7 @@
var curPunc; var curPunc;
var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]); var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]);
var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]); var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]);
var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]); var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with", "call", "yield"]);
var operatorChars = /[*+\-<>=&|~%^]/; var operatorChars = /[*+\-<>=&|~%^]/;
return { return {

37
app/public/codemirror/mode/cypher/test.js vendored Executable file
View file

@ -0,0 +1,37 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, "cypher");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("unbalancedDoubledQuotedString",
"[string \"a'b\"][variable c]");
MT("unbalancedSingleQuotedString",
"[string 'a\"b'][variable c]");
MT("doubleQuotedString",
"[string \"a\"][variable b]");
MT("singleQuotedString",
"[string 'a'][variable b]");
MT("single attribute (with content)",
"[node {][atom a:][string 'a'][node }]");
MT("multiple attribute, singleQuotedString (with content)",
"[node {][atom a:][string 'a'][node ,][atom b:][string 'b'][node }]");
MT("multiple attribute, doubleQuotedString (with content)",
"[node {][atom a:][string \"a\"][node ,][atom b:][string \"b\"][node }]");
MT("single attribute (without content)",
"[node {][atom a:][string 'a'][node }]");
MT("multiple attribute, singleQuotedString (without content)",
"[node {][atom a:][string ''][node ,][atom b:][string ''][node }]");
MT("multiple attribute, doubleQuotedString (without content)",
"[node {][atom a:][string \"\"][node ,][atom b:][string \"\"][node }]");
})();

View file

@ -72,6 +72,12 @@
return null; return null;
} }
return false; return false;
},
"/": function(stream, state) {
if (!stream.eat("*")) return false
state.tokenize = tokenNestedComment(1)
return state.tokenize(stream, state)
} }
} }
}); });
@ -121,6 +127,27 @@
return "variable"; return "variable";
} }
function tokenNestedComment(depth) {
return function (stream, state) {
var ch
while (ch = stream.next()) {
if (ch == "*" && stream.eat("/")) {
if (depth == 1) {
state.tokenize = null
break
} else {
state.tokenize = tokenNestedComment(depth - 1)
return state.tokenize(stream, state)
}
} else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenNestedComment(depth + 1)
return state.tokenize(stream, state)
}
}
return "comment"
}
}
CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins)); CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins));
// This is needed to make loading through meta.js work. // This is needed to make loading through meta.js work.

View file

@ -61,16 +61,16 @@
// Ignore completely any stream series that do not match the // Ignore completely any stream series that do not match the
// Django template opening tags. // Django template opening tags.
while (stream.next() != null && !stream.match("{{", false) && !stream.match("{%", false)) {} while (stream.next() != null && !stream.match(/\{[{%#]/, false)) {}
return null; return null;
} }
// A string can be included in either single or double quotes (this is // A string can be included in either single or double quotes (this is
// the delimeter). Mark everything as a string until the start delimeter // the delimiter). Mark everything as a string until the start delimiter
// occurs again. // occurs again.
function inString (delimeter, previousTokenizer) { function inString (delimiter, previousTokenizer) {
return function (stream, state) { return function (stream, state) {
if (!state.escapeNext && stream.eat(delimeter)) { if (!state.escapeNext && stream.eat(delimiter)) {
state.tokenize = previousTokenizer; state.tokenize = previousTokenizer;
} else { } else {
if (state.escapeNext) { if (state.escapeNext) {
@ -80,7 +80,7 @@
var ch = stream.next(); var ch = stream.next();
// Take into account the backslash for escaping characters, such as // Take into account the backslash for escaping characters, such as
// the string delimeter. // the string delimiter.
if (ch == "\\") { if (ch == "\\") {
state.escapeNext = true; state.escapeNext = true;
} }
@ -100,7 +100,7 @@
return "null"; return "null";
} }
// Dot folowed by a non-word character should be considered an error. // Dot followed by a non-word character should be considered an error.
if (stream.match(/\.\W+/)) { if (stream.match(/\.\W+/)) {
return "error"; return "error";
} else if (stream.eat(".")) { } else if (stream.eat(".")) {
@ -119,7 +119,7 @@
return "null"; return "null";
} }
// Pipe folowed by a non-word character should be considered an error. // Pipe followed by a non-word character should be considered an error.
if (stream.match(/\.\W+/)) { if (stream.match(/\.\W+/)) {
return "error"; return "error";
} else if (stream.eat("|")) { } else if (stream.eat("|")) {
@ -199,7 +199,7 @@
return "null"; return "null";
} }
// Dot folowed by a non-word character should be considered an error. // Dot followed by a non-word character should be considered an error.
if (stream.match(/\.\W+/)) { if (stream.match(/\.\W+/)) {
return "error"; return "error";
} else if (stream.eat(".")) { } else if (stream.eat(".")) {
@ -218,7 +218,7 @@
return "null"; return "null";
} }
// Pipe folowed by a non-word character should be considered an error. // Pipe followed by a non-word character should be considered an error.
if (stream.match(/\.\W+/)) { if (stream.match(/\.\W+/)) {
return "error"; return "error";
} else if (stream.eat("|")) { } else if (stream.eat("|")) {
@ -317,9 +317,8 @@
// Mark everything as comment inside the tag and the tag itself. // Mark everything as comment inside the tag and the tag itself.
function inComment (stream, state) { function inComment (stream, state) {
if (stream.match("#}")) { if (stream.match(/^.*?#\}/)) state.tokenize = tokenBase
state.tokenize = tokenBase; else stream.skipToEnd()
}
return "comment"; return "comment";
} }

View file

@ -114,17 +114,17 @@ CodeMirror.defineMode("dtd", function(config) {
if( textAfter.match(/\]\s+|\]/) )n=n-1; if( textAfter.match(/\]\s+|\]/) )n=n-1;
else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){ else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){
if(textAfter.substr(0,1) === "<")n; if(textAfter.substr(0,1) === "<") {}
else if( type == "doindent" && textAfter.length > 1 )n; else if( type == "doindent" && textAfter.length > 1 ) {}
else if( type == "doindent")n--; else if( type == "doindent")n--;
else if( type == ">" && textAfter.length > 1)n; else if( type == ">" && textAfter.length > 1) {}
else if( type == "tag" && textAfter !== ">")n; else if( type == "tag" && textAfter !== ">") {}
else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--; else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--;
else if( type == "tag")n++; else if( type == "tag")n++;
else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--; else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--;
else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule")n; else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule") {}
else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1; else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1;
else if( textAfter === ">")n; else if( textAfter === ">") {}
else n=n-1; else n=n-1;
//over rule them all //over rule them all
if(type == null || type == "]")n--; if(type == null || type == "]")n--;

View file

@ -11,6 +11,14 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function forEach(arr, f) {
for (var i = 0; i < arr.length; i++) f(arr[i], i)
}
function some(arr, f) {
for (var i = 0; i < arr.length; i++) if (f(arr[i], i)) return true
return false
}
CodeMirror.defineMode("dylan", function(_config) { CodeMirror.defineMode("dylan", function(_config) {
// Words // Words
var words = { var words = {
@ -136,13 +144,13 @@ CodeMirror.defineMode("dylan", function(_config) {
var wordLookup = {}; var wordLookup = {};
var styleLookup = {}; var styleLookup = {};
[ forEach([
"keyword", "keyword",
"definition", "definition",
"simpleDefinition", "simpleDefinition",
"signalingCalls" "signalingCalls"
].forEach(function(type) { ], function(type) {
words[type].forEach(function(word) { forEach(words[type], function(word) {
wordLookup[word] = type; wordLookup[word] = type;
styleLookup[word] = styles[type]; styleLookup[word] = styles[type];
}); });
@ -169,16 +177,17 @@ CodeMirror.defineMode("dylan", function(_config) {
} else if (stream.eat("/")) { } else if (stream.eat("/")) {
stream.skipToEnd(); stream.skipToEnd();
return "comment"; return "comment";
} else {
stream.skipTo(" ");
return "operator";
} }
stream.backUp(1);
} }
// Decimal // Decimal
else if (/\d/.test(ch)) { else if (/[+\-\d\.]/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/); if (stream.match(/^[+-]?[0-9]*\.[0-9]*([esdx][+-]?[0-9]+)?/i) ||
stream.match(/^[+-]?[0-9]+([esdx][+-]?[0-9]+)/i) ||
stream.match(/^[+-]?\d+/)) {
return "number"; return "number";
} }
}
// Hash // Hash
else if (ch == "#") { else if (ch == "#") {
stream.next(); stream.next();
@ -186,7 +195,7 @@ CodeMirror.defineMode("dylan", function(_config) {
ch = stream.peek(); ch = stream.peek();
if (ch == '"') { if (ch == '"') {
stream.next(); stream.next();
return chain(stream, state, tokenString('"', "string-2")); return chain(stream, state, tokenString('"', "string"));
} }
// Binary number // Binary number
else if (ch == "b") { else if (ch == "b") {
@ -206,29 +215,73 @@ CodeMirror.defineMode("dylan", function(_config) {
stream.eatWhile(/[0-7]/); stream.eatWhile(/[0-7]/);
return "number"; return "number";
} }
// Hash symbol // Token concatenation in macros
else { else if (ch == '#') {
stream.eatWhile(/[-a-zA-Z]/); stream.next();
return "keyword"; return "punctuation";
} }
// Sequence literals
else if ((ch == '[') || (ch == '(')) {
stream.next();
return "bracket";
// Hash symbol
} else if (stream.match(/f|t|all-keys|include|key|next|rest/i)) {
return "atom";
} else {
stream.eatWhile(/[-a-zA-Z]/);
return "error";
}
} else if (ch == "~") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
return "operator";
}
return "operator";
}
return "operator";
} else if (ch == ":") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
return "operator";
} else if (ch == ":") {
stream.next();
return "punctuation";
}
} else if ("[](){}".indexOf(ch) != -1) {
stream.next();
return "bracket";
} else if (".,".indexOf(ch) != -1) {
stream.next();
return "punctuation";
} else if (stream.match("end")) { } else if (stream.match("end")) {
return "keyword"; return "keyword";
} }
for (var name in patterns) { for (var name in patterns) {
if (patterns.hasOwnProperty(name)) { if (patterns.hasOwnProperty(name)) {
var pattern = patterns[name]; var pattern = patterns[name];
if ((pattern instanceof Array && pattern.some(function(p) { if ((pattern instanceof Array && some(pattern, function(p) {
return stream.match(p); return stream.match(p);
})) || stream.match(pattern)) })) || stream.match(pattern))
return patternStyles[name]; return patternStyles[name];
} }
} }
if (/[+\-*\/^=<>&|]/.test(ch)) {
stream.next();
return "operator";
}
if (stream.match("define")) { if (stream.match("define")) {
return "def"; return "def";
} else { } else {
stream.eatWhile(/[\w\-]/); stream.eatWhile(/[\w\-]/);
// Keyword // Keyword
if (wordLookup[stream.current()]) { if (wordLookup.hasOwnProperty(stream.current())) {
return styleLookup[stream.current()]; return styleLookup[stream.current()];
} else if (stream.current().match(symbol)) { } else if (stream.current().match(symbol)) {
return "variable"; return "variable";
@ -240,29 +293,37 @@ CodeMirror.defineMode("dylan", function(_config) {
} }
function tokenComment(stream, state) { function tokenComment(stream, state) {
var maybeEnd = false, var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;
ch;
while ((ch = stream.next())) { while ((ch = stream.next())) {
if (ch == "/" && maybeEnd) { if (ch == "/" && maybeEnd) {
if (nestedCount > 0) {
nestedCount--;
} else {
state.tokenize = tokenBase; state.tokenize = tokenBase;
break; break;
} }
} else if (ch == "*" && maybeNested) {
nestedCount++;
}
maybeEnd = (ch == "*"); maybeEnd = (ch == "*");
maybeNested = (ch == "/");
} }
return "comment"; return "comment";
} }
function tokenString(quote, style) { function tokenString(quote, style) {
return function(stream, state) { return function(stream, state) {
var next, end = false; var escaped = false, next, end = false;
while ((next = stream.next()) != null) { while ((next = stream.next()) != null) {
if (next == quote) { if (next == quote && !escaped) {
end = true; end = true;
break; break;
} }
escaped = !escaped && next == "\\";
} }
if (end) if (end || !escaped) {
state.tokenize = tokenBase; state.tokenize = tokenBase;
}
return style; return style;
}; };
} }

88
app/public/codemirror/mode/dylan/test.js vendored Executable file
View file

@ -0,0 +1,88 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "dylan");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT('comments',
'[comment // This is a line comment]',
'[comment /* This is a block comment */]',
'[comment /* This is a multi]',
'[comment line comment]',
'[comment */]',
'[comment /* And this is a /*]',
'[comment /* nested */ comment */]');
MT('unary_operators',
'[operator -][variable a]',
'[operator -] [variable a]',
'[operator ~][variable a]',
'[operator ~] [variable a]');
MT('binary_operators',
'[variable a] [operator +] [variable b]',
'[variable a] [operator -] [variable b]',
'[variable a] [operator *] [variable b]',
'[variable a] [operator /] [variable b]',
'[variable a] [operator ^] [variable b]',
'[variable a] [operator =] [variable b]',
'[variable a] [operator ==] [variable b]',
'[variable a] [operator ~=] [variable b]',
'[variable a] [operator ~==] [variable b]',
'[variable a] [operator <] [variable b]',
'[variable a] [operator <=] [variable b]',
'[variable a] [operator >] [variable b]',
'[variable a] [operator >=] [variable b]',
'[variable a] [operator &] [variable b]',
'[variable a] [operator |] [variable b]',
'[variable a] [operator :=] [variable b]');
MT('integers',
'[number 1]',
'[number 123]',
'[number -123]',
'[number +456]',
'[number #b010]',
'[number #o073]',
'[number #xabcDEF123]');
MT('floats',
'[number .3]',
'[number -1.]',
'[number -2.335]',
'[number +3.78d1]',
'[number 3.78s-1]',
'[number -3.32e+5]');
MT('characters_and_strings',
"[string 'a']",
"[string '\\\\'']",
'[string ""]',
'[string "a"]',
'[string "abc def"]',
'[string "More escaped characters: \\\\\\\\ \\\\a \\\\b \\\\e \\\\f \\\\n \\\\r \\\\t \\\\0 ..."]');
MT('brackets',
'[bracket #[[]]]',
'[bracket #()]',
'[bracket #(][number 1][bracket )]',
'[bracket [[][number 1][punctuation ,] [number 3][bracket ]]]',
'[bracket ()]',
'[bracket {}]',
'[keyword if] [bracket (][variable foo][bracket )]',
'[bracket (][number 1][bracket )]',
'[bracket [[][number 1][bracket ]]]');
MT('hash_words',
'[punctuation ##]',
'[atom #f]', '[atom #F]',
'[atom #t]', '[atom #T]',
'[atom #all-keys]',
'[atom #include]',
'[atom #key]',
'[atom #next]',
'[atom #rest]',
'[string #"foo"]',
'[error #invalid]');
})();

View file

@ -94,7 +94,7 @@
if (bracesMode !== null && (state.braced || peek === "{")) { if (bracesMode !== null && (state.braced || peek === "{")) {
if (state.localState === null) if (state.localState === null)
state.localState = bracesMode.startState(); state.localState = CodeMirror.startState(bracesMode);
var token = bracesMode.token(stream, state.localState), var token = bracesMode.token(stream, state.localState),
text = stream.current(); text = stream.current();

View file

@ -433,15 +433,16 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
} }
function maybe_drop_post(s) { function maybe_drop_post(s) {
if (!s.length) return s
var last = s.length-1; var last = s.length-1;
if (s[last].type === "dot") { if (s[last].type === "dot") {
return []; return [];
} }
if (s[last].type === "fun" && s[last-1].token === "fun") { if (last > 1 && s[last].type === "fun" && s[last-1].token === "fun") {
return s.slice(0,last-1); return s.slice(0,last-1);
} }
switch (s[s.length-1].token) { switch (s[last].token) {
case "}": return d(s,{g:["{"]}); case "}": return d(s,{g:["{"]});
case "]": return d(s,{i:["["]}); case "]": return d(s,{i:["["]});
case ")": return d(s,{i:["("]}); case ")": return d(s,{i:["("]});

173
app/public/codemirror/mode/fcl/fcl.js vendored Executable file
View file

@ -0,0 +1,173 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("fcl", function(config) {
var indentUnit = config.indentUnit;
var keywords = {
"term": true,
"method": true, "accu": true,
"rule": true, "then": true, "is": true, "and": true, "or": true,
"if": true, "default": true
};
var start_blocks = {
"var_input": true,
"var_output": true,
"fuzzify": true,
"defuzzify": true,
"function_block": true,
"ruleblock": true
};
var end_blocks = {
"end_ruleblock": true,
"end_defuzzify": true,
"end_function_block": true,
"end_fuzzify": true,
"end_var": true
};
var atoms = {
"true": true, "false": true, "nan": true,
"real": true, "min": true, "max": true, "cog": true, "cogs": true
};
var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
function tokenBase(stream, state) {
var ch = stream.next();
if (/[\d\.]/.test(ch)) {
if (ch == ".") {
stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
} else if (ch == "0") {
stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
} else {
stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
}
return "number";
}
if (ch == "/" || ch == "(") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
}
if (stream.eat("/")) {
stream.skipToEnd();
return "comment";
}
}
if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return "operator";
}
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
var cur = stream.current().toLowerCase();
if (keywords.propertyIsEnumerable(cur) ||
start_blocks.propertyIsEnumerable(cur) ||
end_blocks.propertyIsEnumerable(cur)) {
return "keyword";
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
return "variable";
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if ((ch == "/" || ch == ")") && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return "comment";
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
return state.context = new Context(state.indented, col, type, null, state.context);
}
function popContext(state) {
if (!state.context.prev) return;
var t = state.context.type;
if (t == "end_block")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: null,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
}
if (stream.eatSpace()) return null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style == "comment") return style;
if (ctx.align == null) ctx.align = true;
var cur = stream.current().toLowerCase();
if (start_blocks.propertyIsEnumerable(cur)) pushContext(state, stream.column(), "end_block");
else if (end_blocks.propertyIsEnumerable(cur)) popContext(state);
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase && state.tokenize != null) return 0;
var ctx = state.context;
var closing = end_blocks.propertyIsEnumerable(textAfter);
if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "ryk",
fold: "brace",
blockCommentStart: "(*",
blockCommentEnd: "*)",
lineComment: "//"
};
});
CodeMirror.defineMIME("text/x-fcl", "fcl");
});

108
app/public/codemirror/mode/fcl/index.html vendored Executable file
View file

@ -0,0 +1,108 @@
<!doctype html>
<title>CodeMirror: FCL mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<link rel="stylesheet" href="../../theme/elegant.css">
<script src="../../lib/codemirror.js"></script>
<script src="../../addon/edit/matchbrackets.js"></script>
<script src="fcl.js"></script>
<style>.CodeMirror {border:1px solid #999; background:#ffc}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">FCL</a>
</ul>
</div>
<article>
<h2>FCL mode</h2>
<form><textarea id="code" name="code">
FUNCTION_BLOCK Fuzzy_FB
VAR_INPUT
TimeDay : REAL; (* RANGE(0 .. 23) *)
ApplicateHost: REAL;
TimeConfiguration: REAL;
TimeRequirements: REAL;
END_VAR
VAR_OUTPUT
ProbabilityDistribution: REAL;
ProbabilityAccess: REAL;
END_VAR
FUZZIFY TimeDay
TERM inside := (0, 0) (8, 1) (22,0);
TERM outside := (0, 1) (8, 0) (22, 1);
END_FUZZIFY
FUZZIFY ApplicateHost
TERM few := (0, 1) (100, 0) (200, 0);
TERM many := (0, 0) (100, 0) (200, 1);
END_FUZZIFY
FUZZIFY TimeConfiguration
TERM recently := (0, 1) (30, 1) (120, 0);
TERM long := (0, 0) (30, 0) (120, 1);
END_FUZZIFY
FUZZIFY TimeRequirements
TERM recently := (0, 1) (30, 1) (365, 0);
TERM long := (0, 0) (30, 0) (365, 1);
END_FUZZIFY
DEFUZZIFY ProbabilityAccess
TERM hight := 1;
TERM medium := 0.5;
TERM low := 0;
ACCU: MAX;
METHOD: COGS;
DEFAULT := 0;
END_DEFUZZIFY
DEFUZZIFY ProbabilityDistribution
TERM hight := 1;
TERM medium := 0.5;
TERM low := 0;
ACCU: MAX;
METHOD: COGS;
DEFAULT := 0;
END_DEFUZZIFY
RULEBLOCK No1
AND : MIN;
RULE 1 : IF TimeDay IS outside AND ApplicateHost IS few THEN ProbabilityAccess IS hight;
RULE 2 : IF ApplicateHost IS many THEN ProbabilityAccess IS hight;
RULE 3 : IF TimeDay IS inside AND ApplicateHost IS few THEN ProbabilityAccess IS low;
END_RULEBLOCK
RULEBLOCK No2
AND : MIN;
RULE 1 : IF ApplicateHost IS many THEN ProbabilityDistribution IS hight;
END_RULEBLOCK
END_FUNCTION_BLOCK
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
theme: "elegant",
matchBrackets: true,
indentUnit: 8,
tabSize: 8,
indentWithTabs: true,
mode: "text/x-fcl"
});
</script>
<p><strong>MIME type:</strong> <code>text/x-fcl</code></p>
</article>

View file

@ -77,5 +77,5 @@
}); });
</script> </script>
<p><strong>MIME types defined:</strong> <code>text/x-Fortran</code>.</p> <p><strong>MIME types defined:</strong> <code>text/x-fortran</code>.</p>
</article> </article>

View file

@ -47,7 +47,7 @@ Underscores_are_allowed_between_words.
GFM adds syntax to strikethrough text, which is missing from standard Markdown. GFM adds syntax to strikethrough text, which is missing from standard Markdown.
~~Mistaken text.~~ ~~Mistaken text.~~
~~**works with other fomatting**~~ ~~**works with other formatting**~~
~~spans across ~~spans across
lines~~ lines~~

View file

@ -51,6 +51,12 @@
"[comment ```]", "[comment ```]",
"bar"); "bar");
MT("fencedCodeBlockModeSwitchingObjc",
"[comment ```objective-c]",
"[keyword @property] [variable NSString] [operator *] [variable foo];",
"[comment ```]",
"bar");
MT("fencedCodeBlocksNoTildes", MT("fencedCodeBlocksNoTildes",
"~~~", "~~~",
"foo", "foo",

View file

@ -23,12 +23,13 @@ CodeMirror.defineMode("go", function(config) {
"bool":true, "byte":true, "complex64":true, "complex128":true, "bool":true, "byte":true, "complex64":true, "complex128":true,
"float32":true, "float64":true, "int8":true, "int16":true, "int32":true, "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
"int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true, "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
"uint64":true, "int":true, "uint":true, "uintptr":true "uint64":true, "int":true, "uint":true, "uintptr":true, "error": true,
"rune":true
}; };
var atoms = { var atoms = {
"true":true, "false":true, "iota":true, "nil":true, "append":true, "true":true, "false":true, "iota":true, "nil":true, "append":true,
"cap":true, "close":true, "complex":true, "copy":true, "imag":true, "cap":true, "close":true, "complex":true, "copy":true, "delete":true, "imag":true,
"len":true, "make":true, "new":true, "panic":true, "print":true, "len":true, "make":true, "new":true, "panic":true, "print":true,
"println":true, "real":true, "recover":true "println":true, "real":true, "recover":true
}; };
@ -173,6 +174,7 @@ CodeMirror.defineMode("go", function(config) {
}, },
electricChars: "{}):", electricChars: "{}):",
closeBrackets: "()[]{}''\"\"``",
fold: "brace", fold: "brace",
blockCommentStart: "/*", blockCommentStart: "/*",
blockCommentEnd: "*/", blockCommentEnd: "*/",

View file

@ -210,7 +210,7 @@ CodeMirror.defineMode("groovy", function(config) {
}, },
indent: function(state, textAfter) { indent: function(state, textAfter) {
if (!state.tokenize[state.tokenize.length-1].isBase) return 0; if (!state.tokenize[state.tokenize.length-1].isBase) return CodeMirror.Pass;
var firstChar = textAfter && textAfter.charAt(0), ctx = state.context; var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev; if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev;
var closing = firstChar == ctx.type; var closing = firstChar == ctx.type;

View file

@ -11,7 +11,7 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
// full haml mode. This handled embeded ruby and html fragments too // full haml mode. This handled embedded ruby and html fragments too
CodeMirror.defineMode("haml", function(config) { CodeMirror.defineMode("haml", function(config) {
var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"});
var rubyMode = CodeMirror.getMode(config, "ruby"); var rubyMode = CodeMirror.getMode(config, "ruby");
@ -98,8 +98,8 @@
return { return {
// default to html mode // default to html mode
startState: function() { startState: function() {
var htmlState = htmlMode.startState(); var htmlState = CodeMirror.startState(htmlMode);
var rubyState = rubyMode.startState(); var rubyState = CodeMirror.startState(rubyMode);
return { return {
htmlState: htmlState, htmlState: htmlState,
rubyState: rubyState, rubyState: rubyState,

View file

@ -67,9 +67,13 @@
mode: {name: "handlebars", base: "text/html"} mode: {name: "handlebars", base: "text/html"}
}); });
</script> </script>
</script>
<p>Handlebars syntax highlighting for CodeMirror.</p> <p>Handlebars syntax highlighting for CodeMirror.</p>
<p><strong>MIME types defined:</strong> <code>text/x-handlebars-template</code></p> <p><strong>MIME types defined:</strong> <code>text/x-handlebars-template</code></p>
<p>Supported options: <code>base</code> to set the mode to
wrap. For example, use</p>
<pre>mode: {name: "handlebars", base: "text/html"}</pre>
<p>to highlight an HTML template.</p>
</article> </article>

View file

@ -0,0 +1,43 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../haskell/haskell"))
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../haskell/haskell"], mod)
else // Plain browser env
mod(CodeMirror)
})(function (CodeMirror) {
"use strict"
CodeMirror.defineMode("haskell-literate", function (config, parserConfig) {
var baseMode = CodeMirror.getMode(config, (parserConfig && parserConfig.base) || "haskell")
return {
startState: function () {
return {
inCode: false,
baseState: CodeMirror.startState(baseMode)
}
},
token: function (stream, state) {
if (stream.sol()) {
if (state.inCode = stream.eat(">"))
return "meta"
}
if (state.inCode) {
return baseMode.token(stream, state.baseState)
} else {
stream.skipToEnd()
return "comment"
}
},
innerMode: function (state) {
return state.inCode ? {state: state.baseState, mode: baseMode} : null
}
}
}, "haskell")
CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate")
});

View file

@ -0,0 +1,282 @@
<!doctype html>
<title>CodeMirror: Haskell-literate mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="haskell-literate.js"></script>
<script src="../haskell/haskell.js"></script>
<style>.CodeMirror {
border-top : 1px solid #DDDDDD;
border-bottom : 1px solid #DDDDDD;
}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo
src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">Haskell-literate</a>
</ul>
</div>
<article>
<h2>Haskell literate mode</h2>
<form>
<textarea id="code" name="code">
> {-# LANGUAGE OverloadedStrings #-}
> {-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
> import Control.Applicative ((<$>), (<*>))
> import Data.Maybe (isJust)
> import Data.Text (Text)
> import Text.Blaze ((!))
> import qualified Data.Text as T
> import qualified Happstack.Server as Happstack
> import qualified Text.Blaze.Html5 as H
> import qualified Text.Blaze.Html5.Attributes as A
> import Text.Digestive
> import Text.Digestive.Blaze.Html5
> import Text.Digestive.Happstack
> import Text.Digestive.Util
Simple forms and validation
---------------------------
Let's start by creating a very simple datatype to represent a user:
> data User = User
> { userName :: Text
> , userMail :: Text
> } deriving (Show)
And dive in immediately to create a `Form` for a user. The `Form v m a` type
has three parameters:
- `v`: the type for messages and errors (usually a `String`-like type, `Text` in
this case);
- `m`: the monad we are operating in, not specified here;
- `a`: the return type of the `Form`, in this case, this is obviously `User`.
> userForm :: Monad m => Form Text m User
We create forms by using the `Applicative` interface. A few form types are
provided in the `Text.Digestive.Form` module, such as `text`, `string`,
`bool`...
In the `digestive-functors` library, the developer is required to label each
field using the `.:` operator. This might look like a bit of a burden, but it
allows you to do some really useful stuff, like separating the `Form` from the
actual HTML layout.
> userForm = User
> <$> "name" .: text Nothing
> <*> "mail" .: check "Not a valid email address" checkEmail (text Nothing)
The `check` function enables you to validate the result of a form. For example,
we can validate the email address with a really naive `checkEmail` function.
> checkEmail :: Text -> Bool
> checkEmail = isJust . T.find (== '@')
More validation
---------------
For our example, we also want descriptions of Haskell libraries, and in order to
do that, we need package versions...
> type Version = [Int]
We want to let the user input a version number such as `0.1.0.0`. This means we
need to validate if the input `Text` is of this form, and then we need to parse
it to a `Version` type. Fortunately, we can do this in a single function:
`validate` allows conversion between values, which can optionally fail.
`readMaybe :: Read a => String -> Maybe a` is a utility function imported from
`Text.Digestive.Util`.
> validateVersion :: Text -> Result Text Version
> validateVersion = maybe (Error "Cannot parse version") Success .
> mapM (readMaybe . T.unpack) . T.split (== '.')
A quick test in GHCi:
ghci> validateVersion (T.pack "0.3.2.1")
Success [0,3,2,1]
ghci> validateVersion (T.pack "0.oops")
Error "Cannot parse version"
It works! This means we can now easily add a `Package` type and a `Form` for it:
> data Category = Web | Text | Math
> deriving (Bounded, Enum, Eq, Show)
> data Package = Package Text Version Category
> deriving (Show)
> packageForm :: Monad m => Form Text m Package
> packageForm = Package
> <$> "name" .: text Nothing
> <*> "version" .: validate validateVersion (text (Just "0.0.0.1"))
> <*> "category" .: choice categories Nothing
> where
> categories = [(x, T.pack (show x)) | x <- [minBound .. maxBound]]
Composing forms
---------------
A release has an author and a package. Let's use this to illustrate the
composability of the digestive-functors library: we can reuse the forms we have
written earlier on.
> data Release = Release User Package
> deriving (Show)
> releaseForm :: Monad m => Form Text m Release
> releaseForm = Release
> <$> "author" .: userForm
> <*> "package" .: packageForm
Views
-----
As mentioned before, one of the advantages of using digestive-functors is
separation of forms and their actual HTML layout. In order to do this, we have
another type, `View`.
We can get a `View` from a `Form` by supplying input. A `View` contains more
information than a `Form`, it has:
- the original form;
- the input given by the user;
- any errors that have occurred.
It is this view that we convert to HTML. For this tutorial, we use the
[blaze-html] library, and some helpers from the `digestive-functors-blaze`
library.
[blaze-html]: http://jaspervdj.be/blaze/
Let's write a view for the `User` form. As you can see, we here refer to the
different fields in the `userForm`. The `errorList` will generate a list of
errors for the `"mail"` field.
> userView :: View H.Html -> H.Html
> userView view = do
> label "name" view "Name: "
> inputText "name" view
> H.br
>
> errorList "mail" view
> label "mail" view "Email address: "
> inputText "mail" view
> H.br
Like forms, views are also composable: let's illustrate that by adding a view
for the `releaseForm`, in which we reuse `userView`. In order to do this, we
take only the parts relevant to the author from the view by using `subView`. We
can then pass the resulting view to our own `userView`.
We have no special view code for `Package`, so we can just add that to
`releaseView` as well. `childErrorList` will generate a list of errors for each
child of the specified form. In this case, this means a list of errors from
`"package.name"` and `"package.version"`. Note how we use `foo.bar` to refer to
nested forms.
> releaseView :: View H.Html -> H.Html
> releaseView view = do
> H.h2 "Author"
> userView $ subView "author" view
>
> H.h2 "Package"
> childErrorList "package" view
>
> label "package.name" view "Name: "
> inputText "package.name" view
> H.br
>
> label "package.version" view "Version: "
> inputText "package.version" view
> H.br
>
> label "package.category" view "Category: "
> inputSelect "package.category" view
> H.br
The attentive reader might have wondered what the type parameter for `View` is:
it is the `String`-like type used for e.g. error messages.
But wait! We have
releaseForm :: Monad m => Form Text m Release
releaseView :: View H.Html -> H.Html
... doesn't this mean that we need a `View Text` rather than a `View Html`? The
answer is yes -- but having `View Html` allows us to write these views more
easily with the `digestive-functors-blaze` library. Fortunately, we will be able
to fix this using the `Functor` instance of `View`.
fmap :: Monad m => (v -> w) -> View v -> View w
A backend
---------
To finish this tutorial, we need to be able to actually run this code. We need
an HTTP server for that, and we use [Happstack] for this tutorial. The
`digestive-functors-happstack` library gives about everything we need for this.
[Happstack]: http://happstack.com/
> site :: Happstack.ServerPart Happstack.Response
> site = do
> Happstack.decodeBody $ Happstack.defaultBodyPolicy "/tmp" 4096 4096 4096
> r <- runForm "test" releaseForm
> case r of
> (view, Nothing) -> do
> let view' = fmap H.toHtml view
> Happstack.ok $ Happstack.toResponse $
> template $
> form view' "/" $ do
> releaseView view'
> H.br
> inputSubmit "Submit"
> (_, Just release) -> Happstack.ok $ Happstack.toResponse $
> template $ do
> css
> H.h1 "Release received"
> H.p $ H.toHtml $ show release
>
> main :: IO ()
> main = Happstack.simpleHTTP Happstack.nullConf site
Utilities
---------
> template :: H.Html -> H.Html
> template body = H.docTypeHtml $ do
> H.head $ do
> H.title "digestive-functors tutorial"
> css
> H.body body
> css :: H.Html
> css = H.style ! A.type_ "text/css" $ do
> "label {width: 130px; float: left; clear: both}"
> "ul.digestive-functors-error-list {"
> " color: red;"
> " list-style-type: none;"
> " padding-left: 0px;"
> "}"
</textarea>
</form>
<p><strong>MIME types
defined:</strong> <code>text/x-literate-haskell</code>.</p>
<p>Parser configuration parameters recognized: <code>base</code> to
set the base mode (defaults to <code>"haskell"</code>).</p>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "haskell-literate"});
</script>
</article>

View file

@ -56,7 +56,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) {
if (source.eat('\'')) { if (source.eat('\'')) {
return "string"; return "string";
} }
return "error"; return "string error";
} }
if (ch == '"') { if (ch == '"') {
@ -166,7 +166,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) {
} }
} }
setState(normal); setState(normal);
return "error"; return "string error";
} }
function stringGap(source, setState) { function stringGap(source, setState) {
@ -194,7 +194,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) {
"module", "newtype", "of", "then", "type", "where", "_"); "module", "newtype", "of", "then", "type", "where", "_");
setType("keyword")( setType("keyword")(
"\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>"); "\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>");
setType("builtin")( setType("builtin")(
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<", "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",

View file

@ -51,9 +51,10 @@ This is an example of EJS (embedded javascript)
}); });
</script> </script>
<p>Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on <p>Mode for html embedded scripts like JSP and ASP.NET. Depends on multiplex and HtmlMixed which in turn depends on
JavaScript, CSS and XML.<br />Other dependancies include those of the scriping language chosen.</p> JavaScript, CSS and XML.<br />Other dependencies include those of the scripting language chosen.</p>
<p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET), <p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET),
<code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)</p> <code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)
and <code>application/x-erb</code></p>
</article> </article>

View file

@ -14,7 +14,7 @@
var defaultTags = { var defaultTags = {
script: [ script: [
["lang", /(javascript|babel)/i, "javascript"], ["lang", /(javascript|babel)/i, "javascript"],
["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"], ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
["type", /./, "text/plain"], ["type", /./, "text/plain"],
[null, null, "javascript"] [null, null, "javascript"]
], ],
@ -44,13 +44,9 @@
return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
} }
function getAttrValue(stream, attr) { function getAttrValue(text, attr) {
var pos = stream.pos, match; var match = text.match(getAttrRegexp(attr))
while (pos >= 0 && stream.string.charAt(pos) !== "<") pos--; return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
if (pos < 0) return pos;
if (match = stream.string.slice(pos, stream.pos).match(getAttrRegexp(attr)))
return match[2];
return "";
} }
function getTagRegexp(tagName, anchored) { function getTagRegexp(tagName, anchored) {
@ -66,10 +62,10 @@
} }
} }
function findMatchingMode(tagInfo, stream) { function findMatchingMode(tagInfo, tagText) {
for (var i = 0; i < tagInfo.length; i++) { for (var i = 0; i < tagInfo.length; i++) {
var spec = tagInfo[i]; var spec = tagInfo[i];
if (!spec[0] || spec[1].test(getAttrValue(stream, spec[0]))) return spec[2]; if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
} }
} }
@ -89,15 +85,17 @@
tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
function html(stream, state) { function html(stream, state) {
var tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase(); var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
var tagInfo = tagName && tags.hasOwnProperty(tagName) && tags[tagName]; if (tag && !/[<>\s\/]/.test(stream.current()) &&
(tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
var style = htmlMode.token(stream, state.htmlState), modeSpec; tags.hasOwnProperty(tagName)) {
state.inTag = tagName + " "
if (tagInfo && /\btag\b/.test(style) && stream.current() === ">" && } else if (state.inTag && tag && />$/.test(stream.current())) {
(modeSpec = findMatchingMode(tagInfo, stream))) { var inTag = /^([\S]+) (.*)/.exec(state.inTag)
var mode = CodeMirror.getMode(config, modeSpec); state.inTag = null
var endTagA = getTagRegexp(tagName, true), endTag = getTagRegexp(tagName, false); var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
var mode = CodeMirror.getMode(config, modeSpec)
var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
state.token = function (stream, state) { state.token = function (stream, state) {
if (stream.match(endTagA, false)) { if (stream.match(endTagA, false)) {
state.token = html; state.token = html;
@ -108,14 +106,17 @@
}; };
state.localMode = mode; state.localMode = mode;
state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
} else if (state.inTag) {
state.inTag += stream.current()
if (stream.eol()) state.inTag += " "
} }
return style; return style;
}; };
return { return {
startState: function () { startState: function () {
var state = htmlMode.startState(); var state = CodeMirror.startState(htmlMode);
return {token: html, localMode: null, localState: null, htmlState: state}; return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
}, },
copyState: function (state) { copyState: function (state) {
@ -123,7 +124,8 @@
if (state.localState) { if (state.localState) {
local = CodeMirror.copyState(state.localMode, state.localState); local = CodeMirror.copyState(state.localMode, state.localState);
} }
return {token: state.token, localMode: state.localMode, localState: local, return {token: state.token, inTag: state.inTag,
localMode: state.localMode, localState: local,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
}, },

View file

@ -72,15 +72,26 @@
<p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p> <p>The HTML mixed mode depends on the XML, JavaScript, and CSS modes.</p>
<p>It takes an optional mode configuration <p>It takes an optional mode configuration
option, <code>scriptTypes</code>, which can be used to add custom option, <code>tags</code>, which can be used to add custom
behavior for specific <code>&lt;script type="..."></code> tags. If behavior for specific tags. When given, it should be an object
given, it should hold an array of <code>{matches, mode}</code> mapping tag names (for example <code>script</code>) to arrays or
objects, where <code>matches</code> is a string or regexp that three-element arrays. Those inner arrays indicate [attributeName,
matches the script type, and <code>mode</code> is valueRegexp, <a href="../../doc/manual.html#option_mode">modeSpec</a>]
either <code>null</code>, for script types that should stay in specifications. For example, you could use <code>["type", /^foo$/,
HTML mode, or a <a href="../../doc/manual.html#option_mode">mode "foo"]</code> to map the attribute <code>type="foo"</code> to
spec</a> corresponding to the mode that should be used for the the <code>foo</code> mode. When the first two fields are null
script.</p> (<code>[null, null, "mode"]</code>), the given mode is used for
any such tag that doesn't match any of the previously given
attributes. For example:</p>
<pre>var myModeSpec = {
name: "htmlmixed",
tags: {
style: [["type", /^text/(x-)?scss$/, "text/x-scss"],
[null, null, "css"]],
custom: [[null, null, "customMode"]]
}
}</pre>
<p><strong>MIME types defined:</strong> <code>text/html</code> <p><strong>MIME types defined:</strong> <code>text/html</code>
(redefined, only takes effect if you load this parser after the (redefined, only takes effect if you load this parser after the

View file

@ -56,9 +56,11 @@ option.</p>
<li><a href="ebnf/index.html">EBNF</a></li> <li><a href="ebnf/index.html">EBNF</a></li>
<li><a href="ecl/index.html">ECL</a></li> <li><a href="ecl/index.html">ECL</a></li>
<li><a href="eiffel/index.html">Eiffel</a></li> <li><a href="eiffel/index.html">Eiffel</a></li>
<li><a href="https://github.com/optick/codemirror-mode-elixir">Elixir</a></li>
<li><a href="elm/index.html">Elm</a></li> <li><a href="elm/index.html">Elm</a></li>
<li><a href="erlang/index.html">Erlang</a></li> <li><a href="erlang/index.html">Erlang</a></li>
<li><a href="factor/index.html">Factor</a></li> <li><a href="factor/index.html">Factor</a></li>
<li><a href="fcl/index.html">FCL</a></li>
<li><a href="forth/index.html">Forth</a></li> <li><a href="forth/index.html">Forth</a></li>
<li><a href="fortran/index.html">Fortran</a></li> <li><a href="fortran/index.html">Fortran</a></li>
<li><a href="mllike/index.html">F#</a></li> <li><a href="mllike/index.html">F#</a></li>
@ -68,15 +70,14 @@ option.</p>
<li><a href="groovy/index.html">Groovy</a></li> <li><a href="groovy/index.html">Groovy</a></li>
<li><a href="haml/index.html">HAML</a></li> <li><a href="haml/index.html">HAML</a></li>
<li><a href="handlebars/index.html">Handlebars</a></li> <li><a href="handlebars/index.html">Handlebars</a></li>
<li><a href="haskell/index.html">Haskell</a></li> <li><a href="haskell/index.html">Haskell</a> (<a href="haskell-literate/index.html">Literate</a>)</li>
<li><a href="haxe/index.html">Haxe</a></li> <li><a href="haxe/index.html">Haxe</a></li>
<li><a href="htmlembedded/index.html">HTML embedded</a> (JSP, ASP.NET)</li> <li><a href="htmlembedded/index.html">HTML embedded</a> (JSP, ASP.NET)</li>
<li><a href="htmlmixed/index.html">HTML mixed-mode</a></li> <li><a href="htmlmixed/index.html">HTML mixed-mode</a></li>
<li><a href="http/index.html">HTTP</a></li> <li><a href="http/index.html">HTTP</a></li>
<li><a href="idl/index.html">IDL</a></li> <li><a href="idl/index.html">IDL</a></li>
<li><a href="clike/index.html">Java</a></li> <li><a href="clike/index.html">Java</a></li>
<li><a href="jade/index.html">Jade</a></li> <li><a href="javascript/index.html">JavaScript</a> (<a href="jsx/index.html">JSX</a>)</li>
<li><a href="javascript/index.html">JavaScript</a></li>
<li><a href="jinja2/index.html">Jinja2</a></li> <li><a href="jinja2/index.html">Jinja2</a></li>
<li><a href="julia/index.html">Julia</a></li> <li><a href="julia/index.html">Julia</a></li>
<li><a href="kotlin/index.html">Kotlin</a></li> <li><a href="kotlin/index.html">Kotlin</a></li>
@ -85,6 +86,7 @@ option.</p>
<li><a href="lua/index.html">Lua</a></li> <li><a href="lua/index.html">Lua</a></li>
<li><a href="markdown/index.html">Markdown</a> (<a href="gfm/index.html">GitHub-flavour</a>)</li> <li><a href="markdown/index.html">Markdown</a> (<a href="gfm/index.html">GitHub-flavour</a>)</li>
<li><a href="mathematica/index.html">Mathematica</a></li> <li><a href="mathematica/index.html">Mathematica</a></li>
<li><a href="mbox/index.html">mbox</a></li>
<li><a href="mirc/index.html">mIRC</a></li> <li><a href="mirc/index.html">mIRC</a></li>
<li><a href="modelica/index.html">Modelica</a></li> <li><a href="modelica/index.html">Modelica</a></li>
<li><a href="mscgen/index.html">MscGen</a></li> <li><a href="mscgen/index.html">MscGen</a></li>
@ -102,7 +104,10 @@ option.</p>
<li><a href="asciiarmor/index.html">PGP (ASCII armor)</a></li> <li><a href="asciiarmor/index.html">PGP (ASCII armor)</a></li>
<li><a href="php/index.html">PHP</a></li> <li><a href="php/index.html">PHP</a></li>
<li><a href="pig/index.html">Pig Latin</a></li> <li><a href="pig/index.html">Pig Latin</a></li>
<li><a href="powershell/index.html">PowerShell</a></li>
<li><a href="properties/index.html">Properties files</a></li> <li><a href="properties/index.html">Properties files</a></li>
<li><a href="protobuf/index.html">ProtoBuf</a></li>
<li><a href="pug/index.html">Pug</a></li>
<li><a href="puppet/index.html">Puppet</a></li> <li><a href="puppet/index.html">Puppet</a></li>
<li><a href="python/index.html">Python</a></li> <li><a href="python/index.html">Python</a></li>
<li><a href="q/index.html">Q</a></li> <li><a href="q/index.html">Q</a></li>
@ -111,6 +116,7 @@ option.</p>
<li><a href="rst/index.html">reStructuredText</a></li> <li><a href="rst/index.html">reStructuredText</a></li>
<li><a href="ruby/index.html">Ruby</a></li> <li><a href="ruby/index.html">Ruby</a></li>
<li><a href="rust/index.html">Rust</a></li> <li><a href="rust/index.html">Rust</a></li>
<li><a href="sas/index.html">SAS</a></li>
<li><a href="sass/index.html">Sass</a></li> <li><a href="sass/index.html">Sass</a></li>
<li><a href="spreadsheet/index.html">Spreadsheet</a></li> <li><a href="spreadsheet/index.html">Spreadsheet</a></li>
<li><a href="clike/scala.html">Scala</a></li> <li><a href="clike/scala.html">Scala</a></li>
@ -146,8 +152,10 @@ option.</p>
<li><a href="verilog/index.html">Verilog/SystemVerilog</a></li> <li><a href="verilog/index.html">Verilog/SystemVerilog</a></li>
<li><a href="vhdl/index.html">VHDL</a></li> <li><a href="vhdl/index.html">VHDL</a></li>
<li><a href="vue/index.html">Vue.js app</a></li> <li><a href="vue/index.html">Vue.js app</a></li>
<li><a href="webidl/index.html">Web IDL</a></li>
<li><a href="xml/index.html">XML/HTML</a></li> <li><a href="xml/index.html">XML/HTML</a></li>
<li><a href="xquery/index.html">XQuery</a></li> <li><a href="xquery/index.html">XQuery</a></li>
<li><a href="yacas/index.html">Yacas</a></li>
<li><a href="yaml/index.html">YAML</a></li> <li><a href="yaml/index.html">YAML</a></li>
<li><a href="yaml-frontmatter/index.html">YAML frontmatter</a></li> <li><a href="yaml-frontmatter/index.html">YAML frontmatter</a></li>
<li><a href="z80/index.html">Z80</a></li> <li><a href="z80/index.html">Z80</a></li>

View file

@ -1,8 +1,6 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others // CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE // Distributed under an MIT license: http://codemirror.net/LICENSE
// TODO actually recognize syntax of TypeScript constructs
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror")); mod(require("../../lib/codemirror"));
@ -13,6 +11,11 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
function expressionAllowed(stream, state, backUp) {
return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
}
CodeMirror.defineMode("javascript", function(config, parserConfig) { CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit; var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent; var statementIndent = parserConfig.statementIndent;
@ -37,7 +40,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"in": operator, "typeof": operator, "instanceof": operator, "in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this"), "class": kw("class"), "super": kw("atom"), "this": kw("this"), "class": kw("class"), "super": kw("atom"),
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
"await": C, "async": kw("async")
}; };
// Extend the 'normal' keywords with the TypeScript language extensions // Extend the 'normal' keywords with the TypeScript language extensions
@ -50,6 +54,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"namespace": C, "namespace": C,
"module": kw("module"), "module": kw("module"),
"enum": kw("module"), "enum": kw("module"),
"type": kw("type"),
// scope modifiers // scope modifiers
"public": kw("modifier"), "public": kw("modifier"),
@ -126,8 +131,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} else if (stream.eat("/")) { } else if (stream.eat("/")) {
stream.skipToEnd(); stream.skipToEnd();
return ret("comment", "comment"); return ret("comment", "comment");
} else if (/^(?:operator|sof|keyword c|case|new|[\[{}\(,;:])$/.test(state.lastType) || } else if (expressionAllowed(stream, state, 1)) {
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - 1)))) {
readRegexp(stream); readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2"); return ret("regexp", "string-2");
@ -142,6 +146,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
stream.skipToEnd(); stream.skipToEnd();
return ret("error", "error"); return ret("error", "error");
} else if (isOperatorChar.test(ch)) { } else if (isOperatorChar.test(ch)) {
if (ch != ">" || !state.lexical || state.lexical.type != ">")
stream.eatWhile(isOperatorChar); stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current()); return ret("operator", "operator", stream.current());
} else if (wordRE.test(ch)) { } else if (wordRE.test(ch)) {
@ -205,13 +210,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var arrow = stream.string.indexOf("=>", stream.start); var arrow = stream.string.indexOf("=>", stream.start);
if (arrow < 0) return; if (arrow < 0) return;
if (isTS) { // Try to skip TypeScript return type declarations after the arguments
var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
if (m) arrow = m.index
}
var depth = 0, sawSomething = false; var depth = 0, sawSomething = false;
for (var pos = arrow - 1; pos >= 0; --pos) { for (var pos = arrow - 1; pos >= 0; --pos) {
var ch = stream.string.charAt(pos); var ch = stream.string.charAt(pos);
var bracket = brackets.indexOf(ch); var bracket = brackets.indexOf(ch);
if (bracket >= 0 && bracket < 3) { if (bracket >= 0 && bracket < 3) {
if (!depth) { ++pos; break; } if (!depth) { ++pos; break; }
if (--depth == 0) break; if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
} else if (bracket >= 3 && bracket < 6) { } else if (bracket >= 3 && bracket < 6) {
++depth; ++depth;
} else if (wordRE.test(ch)) { } else if (wordRE.test(ch)) {
@ -340,19 +350,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function statement(type, value) { function statement(type, value) {
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex); if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont(); if (type == ";") return cont();
if (type == "if") { if (type == "if") {
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
cx.state.cc.pop()(); cx.state.cc.pop()();
return cont(pushlex("form"), expression, statement, poplex, maybeelse); return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
} }
if (type == "function") return cont(functiondef); if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel); if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"),
block, poplex, poplex); block, poplex, poplex);
if (type == "case") return cont(expression, expect(":")); if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":")); if (type == "default") return cont(expect(":"));
@ -362,6 +372,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "export") return cont(pushlex("stat"), afterExport, poplex); if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
if (type == "import") return cont(pushlex("stat"), afterImport, poplex); if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex) if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
if (type == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
if (type == "async") return cont(statement)
return pass(pushlex("stat"), expression, expect(";"), poplex); return pass(pushlex("stat"), expression, expect(";"), poplex);
} }
function expression(type) { function expression(type) {
@ -370,6 +382,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function expressionNoComma(type) { function expressionNoComma(type) {
return expressionInner(type, true); return expressionInner(type, true);
} }
function parenExpr(type) {
if (type != "(") return pass()
return cont(pushlex(")"), expression, expect(")"), poplex)
}
function expressionInner(type, noComma) { function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) { if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody; var body = noComma ? arrowBodyNoComma : arrowBody;
@ -380,8 +396,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop); if (type == "function") return cont(functiondef, maybeop);
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); if (type == "class") return cont(pushlex("form"), classExpression, poplex);
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "{") return contCommasep(objprop, "}", null, maybeop);
@ -457,7 +474,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "variable") {cx.marked = "property"; return cont();} if (type == "variable") {cx.marked = "property"; return cont();}
} }
function objprop(type, value) { function objprop(type, value) {
if (type == "variable" || cx.style == "keyword") { if (type == "async") {
cx.marked = "property";
return cont(objprop);
} else if (type == "variable" || cx.style == "keyword") {
cx.marked = "property"; cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter); if (value == "get" || value == "set") return cont(getterSetter);
return cont(afterprop); return cont(afterprop);
@ -472,6 +492,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(expression, expect("]"), afterprop); return cont(expression, expect("]"), afterprop);
} else if (type == "spread") { } else if (type == "spread") {
return cont(expression); return cont(expression);
} else if (type == ":") {
return pass(afterprop)
} }
} }
function getterSetter(type) { function getterSetter(type) {
@ -483,18 +505,21 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == ":") return cont(expressionNoComma); if (type == ":") return cont(expressionNoComma);
if (type == "(") return pass(functiondef); if (type == "(") return pass(functiondef);
} }
function commasep(what, end) { function commasep(what, end, sep) {
function proceed(type) { function proceed(type, value) {
if (type == ",") { if (sep ? sep.indexOf(type) > -1 : type == ",") {
var lex = cx.state.lexical; var lex = cx.state.lexical;
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
return cont(what, proceed); return cont(function(type, value) {
if (type == end || value == end) return pass()
return pass(what)
}, proceed);
} }
if (type == end) return cont(); if (type == end || value == end) return cont();
return cont(expect(end)); return cont(expect(end));
} }
return function(type) { return function(type, value) {
if (type == end) return cont(); if (type == end || value == end) return cont();
return pass(what, proceed); return pass(what, proceed);
}; };
} }
@ -507,14 +532,39 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "}") return cont(); if (type == "}") return cont();
return pass(statement, block); return pass(statement, block);
} }
function maybetype(type) { function maybetype(type, value) {
if (isTS && type == ":") return cont(typedef); if (isTS) {
if (type == ":") return cont(typeexpr);
if (value == "?") return cont(maybetype);
} }
function maybedefault(_, value) {
if (value == "=") return cont(expressionNoComma);
} }
function typedef(type) { function typeexpr(type) {
if (type == "variable") {cx.marked = "variable-3"; return cont();} if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
if (type == "string" || type == "number" || type == "atom") return cont(afterType);
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex)
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
}
function maybeReturnType(type) {
if (type == "=>") return cont(typeexpr)
}
function typeprop(type, value) {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property"
return cont(typeprop)
} else if (value == "?") {
return cont(typeprop)
} else if (type == ":") {
return cont(typeexpr)
}
}
function typearg(type) {
if (type == "variable") return cont(typearg)
else if (type == ":") return cont(typeexpr)
}
function afterType(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
if (value == "|" || type == ".") return cont(typeexpr)
if (type == "[") return cont(expect("]"), afterType)
} }
function vardef() { function vardef() {
return pass(pattern, maybetype, maybeAssign, vardefCont); return pass(pattern, maybetype, maybeAssign, vardefCont);
@ -533,6 +583,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
if (type == "variable") cx.marked = "property"; if (type == "variable") cx.marked = "property";
if (type == "spread") return cont(pattern); if (type == "spread") return cont(pattern);
if (type == "}") return pass();
return cont(expect(":"), pattern, maybeAssign); return cont(expect(":"), pattern, maybeAssign);
} }
function maybeAssign(_type, value) { function maybeAssign(_type, value) {
@ -568,29 +619,38 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function functiondef(type, value) { function functiondef(type, value) {
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);} if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
} }
function funarg(type) { function funarg(type) {
if (type == "spread") return cont(funarg); if (type == "spread") return cont(funarg);
return pass(pattern, maybetype, maybedefault); return pass(pattern, maybetype, maybeAssign);
}
function classExpression(type, value) {
// Class expressions may have an optional name.
if (type == "variable") return className(type, value);
return classNameAfter(type, value);
} }
function className(type, value) { function className(type, value) {
if (type == "variable") {register(value); return cont(classNameAfter);} if (type == "variable") {register(value); return cont(classNameAfter);}
} }
function classNameAfter(type, value) { function classNameAfter(type, value) {
if (value == "extends") return cont(expression, classNameAfter); if (value == "extends" || value == "implements" || (isTS && type == ","))
return cont(isTS ? typeexpr : expression, classNameAfter);
if (type == "{") return cont(pushlex("}"), classBody, poplex); if (type == "{") return cont(pushlex("}"), classBody, poplex);
} }
function classBody(type, value) { function classBody(type, value) {
if (type == "variable" || cx.style == "keyword") { if (type == "variable" || cx.style == "keyword") {
if (value == "static") { if ((value == "async" || value == "static" || value == "get" || value == "set" ||
(isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) &&
cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) {
cx.marked = "keyword"; cx.marked = "keyword";
return cont(classBody); return cont(classBody);
} }
cx.marked = "property"; cx.marked = "property";
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); return cont(isTS ? classfield : functiondef, classBody);
return cont(functiondef, classBody);
} }
if (type == "[")
return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
if (value == "*") { if (value == "*") {
cx.marked = "keyword"; cx.marked = "keyword";
return cont(classBody); return cont(classBody);
@ -598,19 +658,24 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == ";") return cont(classBody); if (type == ";") return cont(classBody);
if (type == "}") return cont(); if (type == "}") return cont();
} }
function classGetterSetter(type) { function classfield(type, value) {
if (type != "variable") return pass(); if (value == "?") return cont(classfield)
cx.marked = "property"; if (type == ":") return cont(typeexpr, maybeAssign)
return cont(); return pass(functiondef)
} }
function afterExport(_type, value) { function afterExport(type, value) {
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
return pass(statement); return pass(statement);
} }
function exportField(type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
if (type == "variable") return pass(expressionNoComma, exportField);
}
function afterImport(type) { function afterImport(type) {
if (type == "string") return cont(); if (type == "string") return cont();
return pass(importSpec, maybeFrom); return pass(importSpec, maybeMoreImports, maybeFrom);
} }
function importSpec(type, value) { function importSpec(type, value) {
if (type == "{") return contCommasep(importSpec, "}"); if (type == "{") return contCommasep(importSpec, "}");
@ -618,6 +683,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (value == "*") cx.marked = "keyword"; if (value == "*") cx.marked = "keyword";
return cont(maybeAs); return cont(maybeAs);
} }
function maybeMoreImports(type) {
if (type == ",") return cont(importSpec, maybeMoreImports)
}
function maybeAs(_type, value) { function maybeAs(_type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
} }
@ -626,17 +694,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} }
function arrayLiteral(type) { function arrayLiteral(type) {
if (type == "]") return cont(); if (type == "]") return cont();
return pass(expressionNoComma, maybeArrayComprehension);
}
function maybeArrayComprehension(type) {
if (type == "for") return pass(comprehension, expect("]"));
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
return pass(commasep(expressionNoComma, "]")); return pass(commasep(expressionNoComma, "]"));
} }
function comprehension(type) {
if (type == "for") return cont(forspec, comprehension);
if (type == "if") return cont(expression, comprehension);
}
function isContinuedStatement(state, textAfter) { function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," || return state.lastType == "operator" || state.lastType == "," ||
@ -655,7 +714,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars, localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars}, context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0 indented: basecolumn || 0
}; };
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
state.globalVars = parserConfig.globalVars; state.globalVars = parserConfig.globalVars;
@ -679,14 +738,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
indent: function(state, textAfter) { indent: function(state, textAfter) {
if (state.tokenize == tokenComment) return CodeMirror.Pass; if (state.tokenize == tokenComment) return CodeMirror.Pass;
if (state.tokenize != tokenBase) return 0; if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
// Kludge to prevent 'maybelse' from blocking lexical scope pops // Kludge to prevent 'maybelse' from blocking lexical scope pops
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i]; var c = state.cc[i];
if (c == poplex) lexical = lexical.prev; if (c == poplex) lexical = lexical.prev;
else if (c != maybeelse) break; else if (c != maybeelse) break;
} }
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; while ((lexical.type == "stat" || lexical.type == "form") &&
(firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
(top == maybeoperatorComma || top == maybeoperatorNoComma) &&
!/^[,\.=+\-*:?[\(]/.test(textAfter))))
lexical = lexical.prev;
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
lexical = lexical.prev; lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type; var type = lexical.type, closing = firstChar == type;
@ -711,7 +774,13 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
helperType: jsonMode ? "json" : "javascript", helperType: jsonMode ? "json" : "javascript",
jsonldMode: jsonldMode, jsonldMode: jsonldMode,
jsonMode: jsonMode jsonMode: jsonMode,
expressionAllowed: expressionAllowed,
skipExpression: function(state) {
var top = state.cc[state.cc.length - 1]
if (top == expression || top == expressionNoComma) state.cc.pop()
}
}; };
}); });

View file

@ -17,6 +17,10 @@
" [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];",
"})();"); "})();");
MT("destructure_trailing_comma",
"[keyword let] {[def a], [def b],} [operator =] [variable foo];",
"[keyword let] [def c];"); // Parser still in good state?
MT("class_body", MT("class_body",
"[keyword class] [def Foo] {", "[keyword class] [def Foo] {",
" [property constructor]() {}", " [property constructor]() {}",
@ -27,19 +31,38 @@
MT("class", MT("class",
"[keyword class] [def Point] [keyword extends] [variable SuperThing] {", "[keyword class] [def Point] [keyword extends] [variable SuperThing] {",
" [property get] [property prop]() { [keyword return] [number 24]; }", " [keyword get] [property prop]() { [keyword return] [number 24]; }",
" [property constructor]([def x], [def y]) {", " [property constructor]([def x], [def y]) {",
" [keyword super]([string 'something']);", " [keyword super]([string 'something']);",
" [keyword this].[property x] [operator =] [variable-2 x];", " [keyword this].[property x] [operator =] [variable-2 x];",
" }", " }",
"}"); "}");
MT("anonymous_class_expression",
"[keyword const] [def Adder] [operator =] [keyword class] [keyword extends] [variable Arithmetic] {",
" [property add]([def a], [def b]) {}",
"};");
MT("named_class_expression",
"[keyword const] [def Subber] [operator =] [keyword class] [def Subtract] {",
" [property sub]([def a], [def b]) {}",
"};");
MT("class_async_method",
"[keyword class] [def Foo] {",
" [property sayName1]() {}",
" [keyword async] [property sayName2]() {}",
"}");
MT("import", MT("import",
"[keyword function] [def foo]() {", "[keyword function] [def foo]() {",
" [keyword import] [def $] [keyword from] [string 'jquery'];", " [keyword import] [def $] [keyword from] [string 'jquery'];",
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
"}"); "}");
MT("import_trailing_comma",
"[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']")
MT("const", MT("const",
"[keyword function] [def f]() {", "[keyword function] [def f]() {",
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
@ -71,12 +94,6 @@
" [variable something]([variable-2 a], [meta ...][variable-2 b]);", " [variable something]([variable-2 a], [meta ...][variable-2 b]);",
"}"); "}");
MT("comprehension",
"[keyword function] [def f]() {",
" [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
" ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
"}");
MT("quasi", MT("quasi",
"[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
@ -139,6 +156,19 @@
" [number 1];", " [number 1];",
"[number 2];"); "[number 2];");
MT("indent_semicolonless_if",
"[keyword function] [def foo]() {",
" [keyword if] ([variable x])",
" [variable foo]()",
"}")
MT("indent_semicolonless_if_with_statement",
"[keyword function] [def foo]() {",
" [keyword if] ([variable x])",
" [variable foo]()",
" [variable bar]()",
"}")
MT("multilinestring", MT("multilinestring",
"[keyword var] [def x] [operator =] [string 'foo\\]", "[keyword var] [def x] [operator =] [string 'foo\\]",
"[string bar'];"); "[string bar'];");
@ -166,6 +196,99 @@
" }", " }",
"}"); "}");
MT("async",
"[keyword async] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }");
MT("async_assignment",
"[keyword const] [def foo] [operator =] [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; };");
MT("async_object",
"[keyword let] [def obj] [operator =] { [property async]: [atom false] };");
// async be highlighet as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173
MT("async_object_function",
"[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };");
MT("async_object_properties",
"[keyword let] [def obj] [operator =] {",
" [property prop1]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },",
" [property prop2]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },",
" [property prop3]: [keyword async] [keyword function] [def prop3]([def args]) { [keyword return] [atom true]; },",
"};");
MT("async_arrow",
"[keyword const] [def foo] [operator =] [keyword async] ([def args]) [operator =>] { [keyword return] [atom true]; };");
MT("async_jquery",
"[variable $].[property ajax]({",
" [property url]: [variable url],",
" [property async]: [atom true],",
" [property method]: [string 'GET']",
"});");
var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript")
function TS(name) {
test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1))
}
TS("extend_type",
"[keyword class] [def Foo] [keyword extends] [variable-3 Some][operator <][variable-3 Type][operator >] {}")
TS("arrow_type",
"[keyword let] [def x]: ([variable arg]: [variable-3 Type]) [operator =>] [variable-3 ReturnType]")
TS("typescript_class",
"[keyword class] [def Foo] {",
" [keyword public] [keyword static] [property main]() {}",
" [keyword private] [property _foo]: [variable-3 string];",
"}")
TS("typescript_literal_types",
"[keyword import] [keyword *] [keyword as] [def Sequelize] [keyword from] [string 'sequelize'];",
"[keyword interface] [def MyAttributes] {",
" [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];",
" [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];",
"}",
"[keyword interface] [def MyInstance] [keyword extends] [variable-3 Sequelize].[variable-3 Instance] [operator <] [variable-3 MyAttributes] [operator >] {",
" [property rawAttributes]: [variable-3 MyAttributes];",
" [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];",
" [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];",
"}")
TS("typescript_extend_operators",
"[keyword export] [keyword interface] [def UserModel] [keyword extends]",
" [variable-3 Sequelize].[variable-3 Model] [operator <] [variable-3 UserInstance], [variable-3 UserAttributes] [operator >] {",
" [property findById]: (",
" [variable userId]: [variable-3 number]",
" ) [operator =>] [variable-3 Promise] [operator <] [variable-3 Array] [operator <] { [property id], [property name] } [operator >>];",
" [property updateById]: (",
" [variable userId]: [variable-3 number],",
" [variable isActive]: [variable-3 boolean]",
" ) [operator =>] [variable-3 Promise] [operator <] [variable-3 AccountHolderNotificationPreferenceInstance] [operator >];",
" }")
TS("typescript_interface_with_const",
"[keyword const] [def hello]: {",
" [property prop1][operator ?]: [variable-3 string];",
" [property prop2][operator ?]: [variable-3 string];",
"} [operator =] {};")
TS("typescript_double_extend",
"[keyword export] [keyword interface] [def UserAttributes] {",
" [property id][operator ?]: [variable-3 number];",
" [property createdAt][operator ?]: [variable-3 Date];",
"}",
"[keyword export] [keyword interface] [def UserInstance] [keyword extends] [variable-3 Sequelize].[variable-3 Instance][operator <][variable-3 UserAttributes][operator >], [variable-3 UserAttributes] {",
" [property id]: [variable-3 number];",
" [property createdAt]: [variable-3 Date];",
"}");
TS("typescript_index_signature",
"[keyword interface] [def A] {",
" [[ [variable prop]: [variable-3 string] ]]: [variable-3 any];",
" [property prop1]: [variable-3 any];",
"}");
var jsonld_mode = CodeMirror.getMode( var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2}, {indentUnit: 2},
{name: "javascript", jsonld: true} {name: "javascript", jsonld: true}

89
app/public/codemirror/mode/jsx/index.html vendored Executable file
View file

@ -0,0 +1,89 @@
<!doctype html>
<title>CodeMirror: JSX mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="../javascript/javascript.js"></script>
<script src="../xml/xml.js"></script>
<script src="jsx.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">JSX</a>
</ul>
</div>
<article>
<h2>JSX mode</h2>
<div><textarea id="code" name="code">// Code snippets from http://facebook.github.io/react/docs/jsx-in-depth.html
// Rendering HTML tags
var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));
// Rendering React components
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement, document.getElementById('example'));
// Namespaced components
var Form = MyFormComponent;
var App = (
<Form>
<Form.Row>
<Form.Label />
<Form.Input />
</Form.Row>
</Form>
);
// Attribute JavaScript expressions
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// Boolean attributes
<input type="button" disabled />;
<input type="button" disabled={true} />;
// Child JavaScript expressions
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
// Comments
var content = (
<Nav>
{/* child comment, put {} around */}
<Person
/* multi
line
comment */
name={window.isLoggedIn ? window.name : ''} // end of line comment
/>
</Nav>
);
</textarea></div>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
mode: "jsx"
})
</script>
<p>JSX Mode for <a href="http://facebook.github.io/react">React</a>'s
JavaScript syntax extension.</p>
<p><strong>MIME types defined:</strong> <code>text/jsx</code>, <code>text/typescript-jsx</code>.</p>
</article>

148
app/public/codemirror/mode/jsx/jsx.js vendored Executable file
View file

@ -0,0 +1,148 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"))
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript"], mod)
else // Plain browser env
mod(CodeMirror)
})(function(CodeMirror) {
"use strict"
// Depth means the amount of open braces in JS context, in XML
// context 0 means not in tag, 1 means in tag, and 2 means in tag
// and js block comment.
function Context(state, mode, depth, prev) {
this.state = state; this.mode = mode; this.depth = depth; this.prev = prev
}
function copyContext(context) {
return new Context(CodeMirror.copyState(context.mode, context.state),
context.mode,
context.depth,
context.prev && copyContext(context.prev))
}
CodeMirror.defineMode("jsx", function(config, modeConfig) {
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
function flatXMLIndent(state) {
var tagName = state.tagName
state.tagName = null
var result = xmlMode.indent(state, "")
state.tagName = tagName
return result
}
function token(stream, state) {
if (state.context.mode == xmlMode)
return xmlToken(stream, state, state.context)
else
return jsToken(stream, state, state.context)
}
function xmlToken(stream, state, cx) {
if (cx.depth == 2) { // Inside a JS /* */ comment
if (stream.match(/^.*?\*\//)) cx.depth = 1
else stream.skipToEnd()
return "comment"
}
if (stream.peek() == "{") {
xmlMode.skipAttribute(cx.state)
var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context
// If JS starts on same line as tag
if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) {
while (xmlContext.prev && !xmlContext.startOfLine)
xmlContext = xmlContext.prev
// If tag starts the line, use XML indentation level
if (xmlContext.startOfLine) indent -= config.indentUnit
// Else use JS indentation level
else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented
// Else if inside of tag
} else if (cx.depth == 1) {
indent += config.indentUnit
}
state.context = new Context(CodeMirror.startState(jsMode, indent),
jsMode, 0, state.context)
return null
}
if (cx.depth == 1) { // Inside of tag
if (stream.peek() == "<") { // Tag inside of tag
xmlMode.skipAttribute(cx.state)
state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)),
xmlMode, 0, state.context)
return null
} else if (stream.match("//")) {
stream.skipToEnd()
return "comment"
} else if (stream.match("/*")) {
cx.depth = 2
return token(stream, state)
}
}
var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop
if (/\btag\b/.test(style)) {
if (/>$/.test(cur)) {
if (cx.state.context) cx.depth = 0
else state.context = state.context.prev
} else if (/^</.test(cur)) {
cx.depth = 1
}
} else if (!style && (stop = cur.indexOf("{")) > -1) {
stream.backUp(cur.length - stop)
}
return style
}
function jsToken(stream, state, cx) {
if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) {
jsMode.skipExpression(cx.state)
state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")),
xmlMode, 0, state.context)
return null
}
var style = jsMode.token(stream, cx.state)
if (!style && cx.depth != null) {
var cur = stream.current()
if (cur == "{") {
cx.depth++
} else if (cur == "}") {
if (--cx.depth == 0) state.context = state.context.prev
}
}
return style
}
return {
startState: function() {
return {context: new Context(CodeMirror.startState(jsMode), jsMode)}
},
copyState: function(state) {
return {context: copyContext(state.context)}
},
token: token,
indent: function(state, textAfter, fullLine) {
return state.context.mode.indent(state.context.state, textAfter, fullLine)
},
innerMode: function(state) {
return state.context
}
}
}, "xml", "javascript")
CodeMirror.defineMIME("text/jsx", "jsx")
CodeMirror.defineMIME("text/typescript-jsx", {name: "jsx", base: {name: "javascript", typescript: true}})
});

69
app/public/codemirror/mode/jsx/test.js vendored Executable file
View file

@ -0,0 +1,69 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "jsx")
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)) }
MT("selfclose",
"[keyword var] [def x] [operator =] [bracket&tag <] [tag foo] [bracket&tag />] [operator +] [number 1];")
MT("openclose",
"([bracket&tag <][tag foo][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("attr",
"([bracket&tag <][tag foo] [attribute abc]=[string 'value'][bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("braced_attr",
"([bracket&tag <][tag foo] [attribute abc]={[number 10]}[bracket&tag >]hello [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("braced_text",
"([bracket&tag <][tag foo][bracket&tag >]hello {[number 10]} [atom &amp;][bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("nested_tag",
"([bracket&tag <][tag foo][bracket&tag ><][tag bar][bracket&tag ></][tag bar][bracket&tag ></][tag foo][bracket&tag >][operator ++])")
MT("nested_jsx",
"[keyword return] (",
" [bracket&tag <][tag foo][bracket&tag >]",
" say {[number 1] [operator +] [bracket&tag <][tag bar] [attribute attr]={[number 10]}[bracket&tag />]}!",
" [bracket&tag </][tag foo][bracket&tag >][operator ++]",
")")
MT("preserve_js_context",
"[variable x] [operator =] [string-2 `quasi${][bracket&tag <][tag foo][bracket&tag />][string-2 }quoted`]")
MT("line_comment",
"([bracket&tag <][tag foo] [comment // hello]",
" [bracket&tag ></][tag foo][bracket&tag >][operator ++])")
MT("line_comment_not_in_tag",
"([bracket&tag <][tag foo][bracket&tag >] // hello",
" [bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("block_comment",
"([bracket&tag <][tag foo] [comment /* hello]",
"[comment line 2]",
"[comment line 3 */] [bracket&tag ></][tag foo][bracket&tag >][operator ++])")
MT("block_comment_not_in_tag",
"([bracket&tag <][tag foo][bracket&tag >]/* hello",
" line 2",
" line 3 */ [bracket&tag </][tag foo][bracket&tag >][operator ++])")
MT("missing_attr",
"([bracket&tag <][tag foo] [attribute selected][bracket&tag />][operator ++])")
MT("indent_js",
"([bracket&tag <][tag foo][bracket&tag >]",
" [bracket&tag <][tag bar] [attribute baz]={[keyword function]() {",
" [keyword return] [number 10]",
" }}[bracket&tag />]",
" [bracket&tag </][tag foo][bracket&tag >])")
MT("spread",
"([bracket&tag <][tag foo] [attribute bar]={[meta ...][variable baz] [operator /][number 2]}[bracket&tag />])")
MT("tag_attribute",
"([bracket&tag <][tag foo] [attribute bar]=[bracket&tag <][tag foo][bracket&tag />/>][operator ++])")
})()

View file

@ -11,64 +11,87 @@
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
CodeMirror.defineMode("julia", function(_conf, parserConf) { CodeMirror.defineMode("julia", function(config, parserConf) {
var ERRORCLASS = 'error'; function wordRegexp(words, end) {
if (typeof end === "undefined") { end = "\\b"; }
function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))" + end);
return new RegExp("^((" + words.join(")|(") + "))\\b");
} }
var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b/; var octChar = "\\\\[0-7]{1,3}";
var hexChar = "\\\\x[A-Fa-f0-9]{1,2}";
var sChar = "\\\\[abefnrtv0%?'\"\\\\]";
var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])";
var operators = parserConf.operators || wordRegexp([
"\\.?[\\\\%*+\\-<>!=\\/^]=?", "\\.?[|&\\u00F7\\u2260\\u2264\\u2265]",
"\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2229",
"\\u222A", "\\u2286", "\\u2288", "\\u228A", "\\u22c5", "\\?", "~", ":",
"\\$", "\\.[<>]", "<<=?", ">>>?=?", "\\.[<>=]=", "->?", "\\/\\/", "=>",
"<:", "\\bin\\b(?!\\()"], "");
var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*!*/; var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"];
var blockClosers = ["end", "else", "elseif", "catch", "finally"];
var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall'];
var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf'];
//var stringPrefixes = new RegExp("^[br]?('|\")") var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'");
var stringPrefixes = /^(`|'|"{3}|([br]?"))/; var openers = wordRegexp(["begin", "function", "type", "immutable", "let",
var keywords = wordRegexp(keywordList); "macro", "for", "while", "quote", "if", "else", "elseif", "try",
var builtins = wordRegexp(builtinList); "finally", "catch", "do"]);
var openers = wordRegexp(blockOpeners); var closers = wordRegexp(["end", "else", "elseif", "catch", "finally"]);
var closers = wordRegexp(blockClosers); var keywords = wordRegexp(["if", "else", "elseif", "while", "for", "begin",
var macro = /^@[_A-Za-z][_A-Za-z0-9]*/; "let", "end", "do", "try", "catch", "finally", "return", "break",
var symbol = /^:[_A-Za-z][_A-Za-z0-9]*/; "continue", "global", "local", "const", "export", "import", "importall",
"using", "function", "macro", "module", "baremodule", "type",
"immutable", "quote", "typealias", "abstract", "bitstype"]);
var builtins = wordRegexp(["true", "false", "nothing", "NaN", "Inf"]);
function in_array(state) { var macro = /^@[_A-Za-z][\w]*/;
var ch = cur_scope(state); var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/;
if(ch=="[" || ch=="{") { var stringPrefixes = /^(`|"{3}|([_A-Za-z\u00A1-\uFFFF]*"))/;
function inArray(state) {
return inGenerator(state, '[')
}
function inGenerator(state, bracket) {
var curr = currentScope(state),
prev = currentScope(state, 1);
if (typeof(bracket) === "undefined") { bracket = '('; }
if (curr === bracket || (prev === bracket && curr === "for")) {
return true; return true;
} }
else {
return false; return false;
} }
}
function cur_scope(state) { function currentScope(state, n) {
if(state.scopes.length==0) { if (typeof(n) === "undefined") { n = 0; }
if (state.scopes.length <= n) {
return null; return null;
} }
return state.scopes[state.scopes.length - 1]; return state.scopes[state.scopes.length - (n + 1)];
} }
// tokenizers // tokenizers
function tokenBase(stream, state) { function tokenBase(stream, state) {
// Handle scope changes // Handle multiline comments
var leaving_expr = state.leaving_expr; if (stream.match(/^#=/, false)) {
if(stream.sol()) { state.tokenize = tokenComment;
leaving_expr = false; return state.tokenize(stream, state);
}
state.leaving_expr = false;
if(leaving_expr) {
if(stream.match(/^'+/)) {
return 'operator';
} }
// Handle scope changes
var leavingExpr = state.leavingExpr;
if (stream.sol()) {
leavingExpr = false;
}
state.leavingExpr = false;
if (leavingExpr) {
if (stream.match(/^'+/)) {
return "operator";
}
} }
if (stream.match(/^\.{2,3}/)) { if (stream.match(/^\.{2,3}/)) {
return 'operator'; return "operator";
} }
if (stream.eatSpace()) { if (stream.eatSpace()) {
@ -76,106 +99,103 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
} }
var ch = stream.peek(); var ch = stream.peek();
// Handle Comments
// Handle single line comments
if (ch === '#') { if (ch === '#') {
stream.skipToEnd(); stream.skipToEnd();
return 'comment'; return "comment";
} }
if (ch === '[') { if (ch === '[') {
state.scopes.push("["); state.scopes.push('[');
} }
if(ch==='{') { if (ch === '(') {
state.scopes.push("{"); state.scopes.push('(');
} }
var scope=cur_scope(state); var scope = currentScope(state);
if(scope==='[' && ch===']') { if (inArray(state) && ch === ']') {
if (scope === "for") { state.scopes.pop(); }
state.scopes.pop(); state.scopes.pop();
state.leaving_expr=true; state.leavingExpr = true;
} }
if(scope==='{' && ch==='}') { if (inGenerator(state) && ch === ')') {
if (scope === "for") { state.scopes.pop(); }
state.scopes.pop(); state.scopes.pop();
state.leaving_expr=true; state.leavingExpr = true;
}
if(ch===')') {
state.leaving_expr = true;
} }
var match; var match;
if(!in_array(state) && (match=stream.match(openers, false))) { if (match = stream.match(openers, false)) {
state.scopes.push(match); state.scopes.push(match[0]);
} }
if(!in_array(state) && stream.match(closers, false)) { if (stream.match(closers, false)) {
state.scopes.pop(); state.scopes.pop();
} }
if(in_array(state)) { if (inArray(state)) {
if (state.lastToken == "end" && stream.match(/^:/)) {
return "operator";
}
if (stream.match(/^end/)) { if (stream.match(/^end/)) {
return 'number'; return "number";
}
}
if(stream.match(/^=>/)) {
return 'operator';
}
// Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) {
var imMatcher = RegExp(/^im\b/);
var floatLiteral = false;
// Floats
if (stream.match(/^\d*\.(?!\.)\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; }
if (stream.match(/^\d+\.(?!\.)\d*/)) { floatLiteral = true; }
if (stream.match(/^\.\d+/)) { floatLiteral = true; }
if (floatLiteral) {
// Float literals may be "imaginary"
stream.match(imMatcher);
state.leaving_expr = true;
return 'number';
}
// Integers
var intLiteral = false;
// Hex
if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
// Binary
if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
// Octal
if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
// Decimal
if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
intLiteral = true;
}
// Zero by itself with no other piece of number.
if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
if (intLiteral) {
// Integer literals may be "long"
stream.match(imMatcher);
state.leaving_expr = true;
return 'number';
} }
} }
if(stream.match(/^(::)|(<:)/)) { // Handle type annotations
return 'operator'; if (stream.match(/^::(?![:\$])/)) {
state.tokenize = tokenAnnotation;
return state.tokenize(stream, state);
} }
// Handle symbols // Handle symbols
if(!leaving_expr && stream.match(symbol)) { if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) {
return 'string'; return "builtin";
}
// Handle parametric types
if (stream.match(/^{[^}]*}(?=\()/)) {
return "builtin";
} }
// Handle operators and Delimiters // Handle operators and Delimiters
if (stream.match(operators)) { if (stream.match(operators)) {
return 'operator'; return "operator";
} }
// Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) {
var imMatcher = RegExp(/^im\b/);
var numberLiteral = false;
// Floats
if (stream.match(/^\d*\.(?!\.)\d*([Eef][\+\-]?\d+)?/i)) { numberLiteral = true; }
if (stream.match(/^\d+\.(?!\.)\d*/)) { numberLiteral = true; }
if (stream.match(/^\.\d+/)) { numberLiteral = true; }
if (stream.match(/^0x\.[0-9a-f]+p[\+\-]?\d+/i)) { numberLiteral = true; }
// Integers
if (stream.match(/^0x[0-9a-f]+/i)) { numberLiteral = true; } // Hex
if (stream.match(/^0b[01]+/i)) { numberLiteral = true; } // Binary
if (stream.match(/^0o[0-7]+/i)) { numberLiteral = true; } // Octal
if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { numberLiteral = true; } // Decimal
// Zero by itself with no other piece of number.
if (stream.match(/^0(?![\dx])/i)) { numberLiteral = true; }
if (numberLiteral) {
// Integer literals may be "long"
stream.match(imMatcher);
state.leavingExpr = true;
return "number";
}
}
// Handle Chars
if (stream.match(/^'/)) {
state.tokenize = tokenChar;
return state.tokenize(stream, state);
}
// Handle Strings // Handle Strings
if (stream.match(stringPrefixes)) { if (stream.match(stringPrefixes)) {
@ -184,111 +204,202 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) {
} }
if (stream.match(macro)) { if (stream.match(macro)) {
return 'meta'; return "meta";
} }
if (stream.match(delimiters)) { if (stream.match(delimiters)) {
return null; return null;
} }
if (stream.match(keywords)) { if (stream.match(keywords)) {
return 'keyword'; return "keyword";
} }
if (stream.match(builtins)) { if (stream.match(builtins)) {
return 'builtin'; return "builtin";
} }
var isDefinition = state.isDefinition || state.lastToken == "function" ||
state.lastToken == "macro" || state.lastToken == "type" ||
state.lastToken == "immutable";
if (stream.match(identifiers)) { if (stream.match(identifiers)) {
state.leaving_expr=true; if (isDefinition) {
return 'variable'; if (stream.peek() === '.') {
state.isDefinition = true;
return "variable";
} }
state.isDefinition = false;
return "def";
}
if (stream.match(/^({[^}]*})*\(/, false)) {
return callOrDef(stream, state);
}
state.leavingExpr = true;
return "variable";
}
// Handle non-detected items // Handle non-detected items
stream.next(); stream.next();
return ERRORCLASS; return "error";
}
function callOrDef(stream, state) {
var match = stream.match(/^(\(\s*)/);
if (match) {
if (state.firstParenPos < 0)
state.firstParenPos = state.scopes.length;
state.scopes.push('(');
state.charsAdvanced += match[1].length;
}
if (currentScope(state) == '(' && stream.match(/^\)/)) {
state.scopes.pop();
state.charsAdvanced += 1;
if (state.scopes.length <= state.firstParenPos) {
var isDefinition = stream.match(/^\s*?=(?!=)/, false);
stream.backUp(state.charsAdvanced);
state.firstParenPos = -1;
state.charsAdvanced = 0;
if (isDefinition)
return "def";
return "builtin";
}
}
// Unfortunately javascript does not support multiline strings, so we have
// to undo anything done upto here if a function call or definition splits
// over two or more lines.
if (stream.match(/^$/g, false)) {
stream.backUp(state.charsAdvanced);
while (state.scopes.length > state.firstParenPos)
state.scopes.pop();
state.firstParenPos = -1;
state.charsAdvanced = 0;
return "builtin";
}
state.charsAdvanced += stream.match(/^([^()]*)/)[1].length;
return callOrDef(stream, state);
}
function tokenAnnotation(stream, state) {
stream.match(/.*?(?=,|;|{|}|\(|\)|=|$|\s)/);
if (stream.match(/^{/)) {
state.nestedLevels++;
} else if (stream.match(/^}/)) {
state.nestedLevels--;
}
if (state.nestedLevels > 0) {
stream.match(/.*?(?={|})/);
} else if (state.nestedLevels == 0) {
state.tokenize = tokenBase;
}
return "builtin";
}
function tokenComment(stream, state) {
if (stream.match(/^#=/)) {
state.nestedLevels++;
}
if (!stream.match(/.*?(?=(#=|=#))/)) {
stream.skipToEnd();
}
if (stream.match(/^=#/)) {
state.nestedLevels--;
if (state.nestedLevels == 0)
state.tokenize = tokenBase;
}
return "comment";
}
function tokenChar(stream, state) {
var isChar = false, match;
if (stream.match(chars)) {
isChar = true;
} else if (match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i)) {
var value = parseInt(match[1], 16);
if (value <= 55295 || value >= 57344) { // (U+0,U+D7FF), (U+E000,U+FFFF)
isChar = true;
stream.next();
}
} else if (match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/)) {
var value = parseInt(match[1], 16);
if (value <= 1114111) { // U+10FFFF
isChar = true;
stream.next();
}
}
if (isChar) {
state.leavingExpr = true;
state.tokenize = tokenBase;
return "string";
}
if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); }
if (stream.match(/^'/)) { state.tokenize = tokenBase; }
return "error";
} }
function tokenStringFactory(delimiter) { function tokenStringFactory(delimiter) {
while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { delimiter = (delimiter === '`' || delimiter === '"""') ? delimiter : '"';
delimiter = delimiter.substr(1);
}
var singleline = delimiter.length == 1;
var OUTCLASS = 'string';
function tokenString(stream, state) { function tokenString(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^'"\\]/);
if (stream.eat('\\')) { if (stream.eat('\\')) {
stream.next(); stream.next();
if (singleline && stream.eol()) {
return OUTCLASS;
}
} else if (stream.match(delimiter)) { } else if (stream.match(delimiter)) {
state.tokenize = tokenBase; state.tokenize = tokenBase;
return OUTCLASS; state.leavingExpr = true;
return "string";
} else { } else {
stream.eat(/['"]/); stream.eat(/[`"]/);
} }
stream.eatWhile(/[^\\`"]/);
return "string";
} }
if (singleline) {
if (parserConf.singleLineStringErrors) {
return ERRORCLASS;
} else {
state.tokenize = tokenBase;
}
}
return OUTCLASS;
}
tokenString.isString = true;
return tokenString; return tokenString;
} }
function tokenLexer(stream, state) {
var style = state.tokenize(stream, state);
var current = stream.current();
// Handle '.' connected identifiers
if (current === '.') {
style = stream.match(identifiers, false) ? null : ERRORCLASS;
if (style === null && state.lastStyle === 'meta') {
// Apply 'meta' style to '.' connected identifiers when
// appropriate.
style = 'meta';
}
return style;
}
return style;
}
var external = { var external = {
startState: function() { startState: function() {
return { return {
tokenize: tokenBase, tokenize: tokenBase,
scopes: [], scopes: [],
leaving_expr: false lastToken: null,
leavingExpr: false,
isDefinition: false,
nestedLevels: 0,
charsAdvanced: 0,
firstParenPos: -1
}; };
}, },
token: function(stream, state) { token: function(stream, state) {
var style = tokenLexer(stream, state); var style = state.tokenize(stream, state);
state.lastStyle = style; var current = stream.current();
if (current && style) {
state.lastToken = current;
}
// Handle '.' connected identifiers
if (current === '.') {
style = stream.match(identifiers, false) || stream.match(macro, false) ||
stream.match(/\(/, false) ? "operator" : "error";
}
return style; return style;
}, },
indent: function(state, textAfter) { indent: function(state, textAfter) {
var delta = 0; var delta = 0;
if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif" || textAfter=="catch" || textAfter=="finally") { if ( textAfter === ']' || textAfter === ')' || textAfter === "end" ||
textAfter === "else" || textAfter === "catch" || textAfter === "elseif" ||
textAfter === "finally" ) {
delta = -1; delta = -1;
} }
return (state.scopes.length + delta) * _conf.indentUnit; return (state.scopes.length + delta) * config.indentUnit;
}, },
electricInput: /\b(end|else|catch|finally)\b/,
blockCommentStart: "#=",
blockCommentEnd: "=#",
lineComment: "#", lineComment: "#",
fold: "indent", fold: "indent"
electricChars: "edlsifyh]}"
}; };
return external; return external;
}); });

View file

@ -50,7 +50,7 @@
startState: function(){ startState: function(){
return { return {
next: 'start', next: 'start',
lastToken: null lastToken: {style: null, indent: 0, content: ""}
}; };
}, },
token: function(stream, state){ token: function(stream, state){

View file

@ -13,8 +13,8 @@
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var htmlFound = CodeMirror.modes.hasOwnProperty("xml"); var htmlMode = CodeMirror.getMode(cmCfg, "text/html");
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain"); var htmlModeMissing = htmlMode.name == "null"
function getMode(name) { function getMode(name) {
if (CodeMirror.findModeByName) { if (CodeMirror.findModeByName) {
@ -55,8 +55,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (modeCfg.tokenTypeOverrides === undefined) if (modeCfg.tokenTypeOverrides === undefined)
modeCfg.tokenTypeOverrides = {}; modeCfg.tokenTypeOverrides = {};
var codeDepth = 0;
var tokenTypes = { var tokenTypes = {
header: "header", header: "header",
code: "comment", code: "comment",
@ -65,7 +63,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
list2: "variable-3", list2: "variable-3",
list3: "keyword", list3: "keyword",
hr: "hr", hr: "hr",
image: "tag", image: "image",
imageAltText: "image-alt-text",
imageMarker: "image-marker",
formatting: "formatting", formatting: "formatting",
linkInline: "link", linkInline: "link",
linkEmail: "link", linkEmail: "link",
@ -83,14 +83,13 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
} }
var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/ , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
, olRE = /^[0-9]+([.)])\s+/ , taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
, setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/ , textRE = /^[^#!\[\]*_\\<>` "'(~]+/
, fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) + , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) +
")[ \\t]*([\\w+#]*)"); ")[ \\t]*([\\w+#\-]*)");
function switchInline(stream, state, f) { function switchInline(stream, state, f) {
state.f = state.inline = f; state.f = state.inline = f;
@ -121,7 +120,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.quote = 0; state.quote = 0;
// Reset state.indentedCode // Reset state.indentedCode
state.indentedCode = false; state.indentedCode = false;
if (!htmlFound && state.f == htmlBlock) { if (htmlModeMissing && state.f == htmlBlock) {
state.f = inlineNormal; state.f = inlineNormal;
state.block = blockNormal; state.block = blockNormal;
} }
@ -151,10 +150,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.list = null; state.list = null;
} else if (state.indentation > 0) { } else if (state.indentation > 0) {
state.list = null; state.list = null;
state.listDepth = Math.floor(state.indentation / 4);
} else { // No longer a list } else { // No longer a list
state.list = false; state.list = false;
state.listDepth = 0;
} }
} }
@ -191,17 +188,21 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
} else if (stream.match(hrRE, true)) { } else if (stream.match(hrRE, true)) {
state.hr = true; state.hr = true;
return tokenTypes.hr; return tokenTypes.hr;
} else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { } else if (match = stream.match(listRE)) {
var listType = null; var listType = match[1] ? "ol" : "ul";
if (stream.match(ulRE, true)) {
listType = 'ul';
} else {
stream.match(olRE, true);
listType = 'ol';
}
state.indentation = stream.column() + stream.current().length; state.indentation = stream.column() + stream.current().length;
state.list = true; state.list = true;
state.listDepth++;
// While this list item's marker's indentation
// is less than the deepest list item's content's indentation,
// pop the deepest list item indentation off the stack.
while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) {
state.listStack.pop();
}
// Add this list item's content's indentation to the stack
state.listStack.push(state.indentation);
if (modeCfg.taskLists && stream.match(taskListRE, false)) { if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true; state.taskList = true;
} }
@ -212,10 +213,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.fencedChars = match[1] state.fencedChars = match[1]
// try switching mode // try switching mode
state.localMode = getMode(match[2]); state.localMode = getMode(match[2]);
if (state.localMode) state.localState = state.localMode.startState(); if (state.localMode) state.localState = CodeMirror.startState(state.localMode);
state.f = state.block = local; state.f = state.block = local;
if (modeCfg.highlightFormatting) state.formatting = "code-block"; if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true; state.code = -1
return getType(state); return getType(state);
} }
@ -224,21 +225,27 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
function htmlBlock(stream, state) { function htmlBlock(stream, state) {
var style = htmlMode.token(stream, state.htmlState); var style = htmlMode.token(stream, state.htmlState);
if ((htmlFound && state.htmlState.tagStart === null && if (!htmlModeMissing) {
(!state.htmlState.context && state.htmlState.tokenize.isInText)) || var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
if ((inner.mode.name == "xml" && inner.state.tagStart === null &&
(!inner.state.context && inner.state.tokenize.isInText)) ||
(state.md_inside && stream.current().indexOf(">") > -1)) { (state.md_inside && stream.current().indexOf(">") > -1)) {
state.f = inlineNormal; state.f = inlineNormal;
state.block = blockNormal; state.block = blockNormal;
state.htmlState = null; state.htmlState = null;
} }
}
return style; return style;
} }
function local(stream, state) { function local(stream, state) {
if (stream.sol() && state.fencedChars && stream.match(state.fencedChars, false)) { if (state.fencedChars && stream.match(state.fencedChars)) {
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.localMode = state.localState = null; state.localMode = state.localState = null;
state.f = state.block = leavingLocal; state.f = state.block = leavingLocal;
return null; return getType(state)
} else if (state.fencedChars && stream.skipTo(state.fencedChars)) {
return "comment"
} else if (state.localMode) { } else if (state.localMode) {
return state.localMode.token(stream, state.localState); return state.localMode.token(stream, state.localState);
} else { } else {
@ -253,9 +260,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.f = inlineNormal; state.f = inlineNormal;
state.fencedChars = null; state.fencedChars = null;
if (modeCfg.highlightFormatting) state.formatting = "code-block"; if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true; state.code = 1
var returnType = getType(state); var returnType = getType(state);
state.code = false; state.code = 0
return returnType; return returnType;
} }
@ -304,6 +311,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (state.strikethrough) { styles.push(tokenTypes.strikethrough); } if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
if (state.linkText) { styles.push(tokenTypes.linkText); } if (state.linkText) { styles.push(tokenTypes.linkText); }
if (state.code) { styles.push(tokenTypes.code); } if (state.code) { styles.push(tokenTypes.code); }
if (state.image) { styles.push(tokenTypes.image); }
if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); }
if (state.imageMarker) { styles.push(tokenTypes.imageMarker); }
} }
if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); } if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
@ -320,7 +330,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
} }
if (state.list !== false) { if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3; var listMod = (state.listStack.length - 1) % 3;
if (!listMod) { if (!listMod) {
styles.push(tokenTypes.list1); styles.push(tokenTypes.list1);
} else if (listMod === 1) { } else if (listMod === 1) {
@ -378,15 +388,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var ch = stream.next(); var ch = stream.next();
if (ch === '\\') {
stream.next();
if (modeCfg.highlightFormatting) {
var type = getType(state);
var formattingEscape = tokenTypes.formatting + "-escape";
return type ? type + " " + formattingEscape : formattingEscape;
}
}
// Matches link titles present on next line // Matches link titles present on next line
if (state.linkTitle) { if (state.linkTitle) {
state.linkTitle = false; state.linkTitle = false;
@ -405,39 +406,62 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (ch === '`') { if (ch === '`') {
var previousFormatting = state.formatting; var previousFormatting = state.formatting;
if (modeCfg.highlightFormatting) state.formatting = "code"; if (modeCfg.highlightFormatting) state.formatting = "code";
var t = getType(state);
var before = stream.pos;
stream.eatWhile('`'); stream.eatWhile('`');
var difference = 1 + stream.pos - before; var count = stream.current().length
if (!state.code) { if (state.code == 0) {
codeDepth = difference; state.code = count
state.code = true; return getType(state)
return getType(state); } else if (count == state.code) { // Must be exact
var t = getType(state)
state.code = 0
return t
} else { } else {
if (difference === codeDepth) { // Must be exact state.formatting = previousFormatting
state.code = false; return getType(state)
return t;
}
state.formatting = previousFormatting;
return getType(state);
} }
} else if (state.code) { } else if (state.code) {
return getType(state); return getType(state);
} }
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { if (ch === '\\') {
stream.match(/\[[^\]]*\]/); stream.next();
state.inline = state.f = linkHref; if (modeCfg.highlightFormatting) {
return tokenTypes.image; var type = getType(state);
var formattingEscape = tokenTypes.formatting + "-escape";
return type ? type + " " + formattingEscape : formattingEscape;
}
} }
if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) { if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
state.imageMarker = true;
state.image = true;
if (modeCfg.highlightFormatting) state.formatting = "image";
return getType(state);
}
if (ch === '[' && state.imageMarker && stream.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/, false)) {
state.imageMarker = false;
state.imageAltText = true
if (modeCfg.highlightFormatting) state.formatting = "image";
return getType(state);
}
if (ch === ']' && state.imageAltText) {
if (modeCfg.highlightFormatting) state.formatting = "image";
var type = getType(state);
state.imageAltText = false;
state.image = false;
state.inline = state.f = linkHref;
return type;
}
if (ch === '[' && stream.match(/[^\]]*\](\(.*\)| ?\[.*?\])/, false) && !state.image) {
state.linkText = true; state.linkText = true;
if (modeCfg.highlightFormatting) state.formatting = "link"; if (modeCfg.highlightFormatting) state.formatting = "link";
return getType(state); return getType(state);
} }
if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) { if (ch === ']' && state.linkText && stream.match(/\(.*?\)| ?\[.*?\]/, false)) {
if (modeCfg.highlightFormatting) state.formatting = "link"; if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state); var type = getType(state);
state.linkText = false; state.linkText = false;
@ -469,7 +493,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return type + tokenTypes.linkEmail; return type + tokenTypes.linkEmail;
} }
if (ch === '<' && stream.match(/^(!--|\w)/, false)) { if (ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) {
var end = stream.string.indexOf(">", stream.pos); var end = stream.string.indexOf(">", stream.pos);
if (end != -1) { if (end != -1) {
var atts = stream.string.substring(stream.start, end); var atts = stream.string.substring(stream.start, end);
@ -590,7 +614,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
} }
var ch = stream.next(); var ch = stream.next();
if (ch === '(' || ch === '[') { if (ch === '(' || ch === '[') {
state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]"); state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]", 0);
if (modeCfg.highlightFormatting) state.formatting = "link-string"; if (modeCfg.highlightFormatting) state.formatting = "link-string";
state.linkHref = true; state.linkHref = true;
return getType(state); return getType(state);
@ -598,6 +622,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return 'error'; return 'error';
} }
var linkRE = {
")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,
"]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\\]]|\\.)*\])*?(?=\])/
}
function getLinkHrefInside(endChar) { function getLinkHrefInside(endChar) {
return function(stream, state) { return function(stream, state) {
var ch = stream.next(); var ch = stream.next();
@ -610,10 +639,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return returnState; return returnState;
} }
if (stream.match(inlineRE(endChar), true)) { stream.match(linkRE[endChar])
stream.backUp(1);
}
state.linkHref = true; state.linkHref = true;
return getType(state); return getType(state);
}; };
@ -661,18 +687,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return tokenTypes.linkHref + " url"; return tokenTypes.linkHref + " url";
} }
var savedInlineRE = [];
function inlineRE(endChar) {
if (!savedInlineRE[endChar]) {
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
// Match any non-endChar, escaped character, as well as the closing
// endChar.
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
}
return savedInlineRE[endChar];
}
var mode = { var mode = {
startState: function() { startState: function() {
return { return {
@ -692,13 +706,14 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
linkText: false, linkText: false,
linkHref: false, linkHref: false,
linkTitle: false, linkTitle: false,
code: 0,
em: false, em: false,
strong: false, strong: false,
header: 0, header: 0,
hr: false, hr: false,
taskList: false, taskList: false,
list: false, list: false,
listDepth: 0, listStack: [],
quote: 0, quote: 0,
trailingSpace: 0, trailingSpace: 0,
trailingSpaceNewLine: false, trailingSpaceNewLine: false,
@ -733,7 +748,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
hr: s.hr, hr: s.hr,
taskList: s.taskList, taskList: s.taskList,
list: s.list, list: s.list,
listDepth: s.listDepth, listStack: s.listStack.slice(0),
quote: s.quote, quote: s.quote,
indentedCode: s.indentedCode, indentedCode: s.indentedCode,
trailingSpace: s.trailingSpace, trailingSpace: s.trailingSpace,
@ -773,11 +788,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.f = state.block; state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4; state.indentationDiff = Math.min(indentation - state.indentation, 4);
if (difference > 4) difference = 4; state.indentation = state.indentation + state.indentationDiff;
var adjustedIndentation = state.indentation + difference;
state.indentationDiff = adjustedIndentation - state.indentation;
state.indentation = adjustedIndentation;
if (indentation > 0) return null; if (indentation > 0) return null;
} }
return state.f(stream, state); return state.f(stream, state);
@ -793,6 +805,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
getType: getType, getType: getType,
closeBrackets: "()[]{}''\"\"``",
fold: "markdown" fold: "markdown"
}; };
return mode; return mode;

View file

@ -22,6 +22,8 @@
"list3" : "override-list3", "list3" : "override-list3",
"hr" : "override-hr", "hr" : "override-hr",
"image" : "override-image", "image" : "override-image",
"imageAltText": "override-image-alt-text",
"imageMarker": "override-image-marker",
"linkInline" : "override-link-inline", "linkInline" : "override-link-inline",
"linkEmail" : "override-link-email", "linkEmail" : "override-link-email",
"linkText" : "override-link-text", "linkText" : "override-link-text",
@ -89,6 +91,9 @@
FT("formatting_escape", FT("formatting_escape",
"[formatting-escape \\*]"); "[formatting-escape \\*]");
FT("formatting_image",
"[formatting&formatting-image&image&image-marker !][formatting&formatting-image&image&image-alt-text&link [[][image&image-alt-text&link alt text][formatting&formatting-image&image&image-alt-text&link ]]][formatting&formatting-link-string&string&url (][url&string http://link.to/image.jpg][formatting&formatting-link-string&string&url )]");
MT("plainText", MT("plainText",
"foo"); "foo");
@ -352,11 +357,10 @@
"[variable-2 1. foo]", "[variable-2 1. foo]",
"[variable-2 2. bar]"); "[variable-2 2. bar]");
// Lists require a preceding blank line (per Dingus) MT("listFromParagraph",
MT("listBogus",
"foo", "foo",
"1. bar", "[variable-2 1. bar]",
"2. hello"); "[variable-2 2. hello]");
// List after hr // List after hr
MT("listAfterHr", MT("listAfterHr",
@ -452,6 +456,18 @@
"", "",
"hello"); "hello");
MT("listCommonMarkIndentationCode",
"[variable-2 * Code blocks also affect]",
" [variable-3 * The next level starts where the contents start.]",
" [variable-3 * Anything less than that will keep the item on the same level.]",
" [variable-3 * Each list item can indent the first level further and further.]",
" [variable-3 * For the most part, this makes sense while writing a list.]",
" [keyword * This means two items with same indentation can be different levels.]",
" [keyword * Each level has an indent requirement that can change between items.]",
" [keyword * A list item that meets this will be part of the next level.]",
" [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
" [variable-2 * World]");
// Blockquote // Blockquote
MT("blockquote", MT("blockquote",
"[variable-2 * foo]", "[variable-2 * foo]",
@ -577,6 +593,20 @@
MT("hrDashLong", MT("hrDashLong",
"[hr ---------------------------------------]"); "[hr ---------------------------------------]");
//Images
MT("Images",
"[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]")
//Images with highlight alt text
MT("imageEm",
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&em&image&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
MT("imageStrong",
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&strong&image&link **alt text**][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
MT("imageEmStrong",
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&image&strong&link **][image&image-alt-text&em&strong&link *alt text**][image&image-alt-text&em&link *][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
// Inline link with title // Inline link with title
MT("linkTitle", MT("linkTitle",
"[link [[foo]]][string&url (http://example.com/ \"bar\")] hello"); "[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
@ -587,7 +617,7 @@
// Inline link with image // Inline link with image
MT("linkImage", MT("linkImage",
"[link [[][tag ![[foo]]][string&url (http://example.com/)][link ]]][string&url (http://example.com/)] bar"); "[link [[][link&image&image-marker !][link&image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)][link ]]][string&url (http://example.com/)] bar");
// Inline link with Em // Inline link with Em
MT("linkEm", MT("linkEm",
@ -603,15 +633,15 @@
// Image with title // Image with title
MT("imageTitle", MT("imageTitle",
"[tag ![[foo]]][string&url (http://example.com/ \"bar\")] hello"); "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello");
// Image without title // Image without title
MT("imageNoTitle", MT("imageNoTitle",
"[tag ![[foo]]][string&url (http://example.com/)] bar"); "[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar");
// Image with asterisks // Image with asterisks
MT("imageAsterisks", MT("imageAsterisks",
"[tag ![[*foo*]]][string&url (http://example.com/)] bar"); "[image&image-marker !][image&image-alt-text&link [[ ][image&image-alt-text&em&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)] bar");
// Not a link. Should be normal text due to square brackets being used // Not a link. Should be normal text due to square brackets being used
// regularly in text, especially in quoted material, and no space is allowed // regularly in text, especially in quoted material, and no space is allowed
@ -635,7 +665,7 @@
MT("linkReferenceEmStrong", MT("linkReferenceEmStrong",
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello"); "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello");
// Reference-style links with optional space separator (per docuentation) // Reference-style links with optional space separator (per documentation)
// "You can optionally use a space to separate the sets of brackets" // "You can optionally use a space to separate the sets of brackets"
MT("linkReferenceSpace", MT("linkReferenceSpace",
"[link [[foo]]] [string&url [[bar]]] hello"); "[link [[foo]]] [string&url [[bar]]] hello");
@ -671,7 +701,7 @@
MT("labelTitleSingleQuotes", MT("labelTitleSingleQuotes",
"[link [[foo]]:] [string&url http://example.com/ 'bar']"); "[link [[foo]]:] [string&url http://example.com/ 'bar']");
MT("labelTitleParenthese", MT("labelTitleParentheses",
"[link [[foo]]:] [string&url http://example.com/ (bar)]"); "[link [[foo]]:] [string&url http://example.com/ (bar)]");
MT("labelTitleInvalid", MT("labelTitleInvalid",
@ -688,7 +718,7 @@
"[link [[foo]]:] [string&url http://example.com/]", "[link [[foo]]:] [string&url http://example.com/]",
"[string 'bar'] hello"); "[string 'bar'] hello");
MT("labelTitleNextParenthese", MT("labelTitleNextParentheses",
"[link [[foo]]:] [string&url http://example.com/]", "[link [[foo]]:] [string&url http://example.com/]",
"[string (bar)] hello"); "[string (bar)] hello");
@ -770,6 +800,9 @@
MT("emStrongMixed", MT("emStrongMixed",
"[em *foo][em&strong __bar_hello** world]"); "[em *foo][em&strong __bar_hello** world]");
MT("linkWithNestedParens",
"[link [[foo]]][string&url (bar(baz))]")
// These characters should be escaped: // These characters should be escaped:
// \ backslash // \ backslash
// ` backtick // ` backtick
@ -863,7 +896,7 @@
"[override-hr * * *]"); "[override-hr * * *]");
TokenTypeOverrideTest("overrideImage", TokenTypeOverrideTest("overrideImage",
"[override-image ![[foo]]][override-link-href&url (http://example.com/)]") "[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]");
TokenTypeOverrideTest("overrideLinkText", TokenTypeOverrideTest("overrideLinkText",
"[override-link-text [[foo]]][override-link-href&url (http://example.com)]"); "[override-link-text [[foo]]][override-link-href&url (http://example.com)]");

View file

@ -126,6 +126,7 @@ CodeMirror.defineMode('mathematica', function(_config, _parserConfig) {
} }
// everything else is an error // everything else is an error
stream.next(); // advance the stream.
return 'error'; return 'error';
} }

44
app/public/codemirror/mode/mbox/index.html vendored Executable file
View file

@ -0,0 +1,44 @@
<!doctype html>
<title>CodeMirror: mbox mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="mbox.js"></script>
<style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">mbox</a>
</ul>
</div>
<article>
<h2>mbox mode</h2>
<form><textarea id="code" name="code">
From timothygu99@gmail.com Sun Apr 17 01:40:43 2016
From: Timothy Gu &lt;timothygu99@gmail.com&gt;
Date: Sat, 16 Apr 2016 18:40:43 -0700
Subject: mbox mode
Message-ID: &lt;Z8d+bTT50U/az94FZnyPkDjZmW0=@gmail.com&gt;
mbox mode is working!
Timothy
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>application/mbox</code>.</p>
</article>

129
app/public/codemirror/mode/mbox/mbox.js vendored Executable file
View file

@ -0,0 +1,129 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var rfc2822 = [
"From", "Sender", "Reply-To", "To", "Cc", "Bcc", "Message-ID",
"In-Reply-To", "References", "Resent-From", "Resent-Sender", "Resent-To",
"Resent-Cc", "Resent-Bcc", "Resent-Message-ID", "Return-Path", "Received"
];
var rfc2822NoEmail = [
"Date", "Subject", "Comments", "Keywords", "Resent-Date"
];
CodeMirror.registerHelper("hintWords", "mbox", rfc2822.concat(rfc2822NoEmail));
var whitespace = /^[ \t]/;
var separator = /^From /; // See RFC 4155
var rfc2822Header = new RegExp("^(" + rfc2822.join("|") + "): ");
var rfc2822HeaderNoEmail = new RegExp("^(" + rfc2822NoEmail.join("|") + "): ");
var header = /^[^:]+:/; // Optional fields defined in RFC 2822
var email = /^[^ ]+@[^ ]+/;
var untilEmail = /^.*?(?=[^ ]+?@[^ ]+)/;
var bracketedEmail = /^<.*?>/;
var untilBracketedEmail = /^.*?(?=<.*>)/;
function styleForHeader(header) {
if (header === "Subject") return "header";
return "string";
}
function readToken(stream, state) {
if (stream.sol()) {
// From last line
state.inSeparator = false;
if (state.inHeader && stream.match(whitespace)) {
// Header folding
return null;
} else {
state.inHeader = false;
state.header = null;
}
if (stream.match(separator)) {
state.inHeaders = true;
state.inSeparator = true;
return "atom";
}
var match;
var emailPermitted = false;
if ((match = stream.match(rfc2822HeaderNoEmail)) ||
(emailPermitted = true) && (match = stream.match(rfc2822Header))) {
state.inHeaders = true;
state.inHeader = true;
state.emailPermitted = emailPermitted;
state.header = match[1];
return "atom";
}
// Use vim's heuristics: recognize custom headers only if the line is in a
// block of legitimate headers.
if (state.inHeaders && (match = stream.match(header))) {
state.inHeader = true;
state.emailPermitted = true;
state.header = match[1];
return "atom";
}
state.inHeaders = false;
stream.skipToEnd();
return null;
}
if (state.inSeparator) {
if (stream.match(email)) return "link";
if (stream.match(untilEmail)) return "atom";
stream.skipToEnd();
return "atom";
}
if (state.inHeader) {
var style = styleForHeader(state.header);
if (state.emailPermitted) {
if (stream.match(bracketedEmail)) return style + " link";
if (stream.match(untilBracketedEmail)) return style;
}
stream.skipToEnd();
return style;
}
stream.skipToEnd();
return null;
};
CodeMirror.defineMode("mbox", function() {
return {
startState: function() {
return {
// Is in a mbox separator
inSeparator: false,
// Is in a mail header
inHeader: false,
// If bracketed email is permitted. Only applicable when inHeader
emailPermitted: false,
// Name of current header
header: null,
// Is in a region of mail headers
inHeaders: false
};
},
token: readToken,
blankLine: function(state) {
state.inHeaders = state.inSeparator = state.inHeader = false;
}
};
});
CodeMirror.defineMIME("application/mbox", "mbox");
});

View file

@ -3,9 +3,9 @@
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../codemirror")); mod(require("../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../codemirror"], mod); define(["../lib/codemirror"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
@ -21,7 +21,8 @@
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]}, {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
{name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
{name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
{name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
{name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
@ -40,12 +41,14 @@
{name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]}, {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
{name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"}, {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
{name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]}, {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
{name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]},
{name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
{name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]}, {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
{name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
{name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
{name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
{name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]}, {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
{name: "FCL", mime: "text/x-fcl", mode: "fcl"},
{name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]}, {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
{name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]}, {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
{name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
@ -53,22 +56,24 @@
{name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]}, {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
{name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i}, {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
{name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]}, {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
{name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]}, {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
{name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]}, {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
{name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]}, {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
{name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]},
{name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]}, {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
{name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]}, {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]}, {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]}, {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]},
{name: "HTTP", mime: "message/http", mode: "http"}, {name: "HTTP", mime: "message/http", mode: "http"},
{name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]}, {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
{name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]}, {name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]},
{name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]}, {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
{name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]}, {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
{name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"], {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]}, mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]},
{name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]}, {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
{name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]}, {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
{name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
{name: "Jinja2", mime: "null", mode: "jinja2"}, {name: "Jinja2", mime: "null", mode: "jinja2"},
{name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]}, {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
{name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]}, {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
@ -80,13 +85,14 @@
{name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"}, {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
{name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]}, {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
{name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]}, {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
{name: "MUMPS", mime: "text/x-mumps", mode: "mumps"}, {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
{name: "MS SQL", mime: "text/x-mssql", mode: "sql"}, {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
{name: "mbox", mime: "application/mbox", mode: "mbox", ext: ["mbox"]},
{name: "MySQL", mime: "text/x-mysql", mode: "sql"}, {name: "MySQL", mime: "text/x-mysql", mode: "sql"},
{name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i}, {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
{name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]}, {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
{name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]}, {name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
{name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]}, {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]},
{name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
{name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
{name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]}, {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
@ -97,16 +103,19 @@
{name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
{name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
{name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
{name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]}, {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
{name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/},
{name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
{name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
{name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]}, {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]},
{name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]}, {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
{name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"}, {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
{name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
{name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]}, {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
{name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]}, {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
{name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]},
{name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]}, {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
{name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
{name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
@ -122,8 +131,8 @@
{name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
{name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]}, {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
{name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]}, {name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
{name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]},
{name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]}, {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
{name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
{name: "sTeX", mime: "text/x-stex", mode: "stex"}, {name: "sTeX", mime: "text/x-stex", mode: "stex"},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]}, {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]}, {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
@ -133,20 +142,23 @@
{name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
{name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]}, {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
{name: "Tornado", mime: "text/x-tornado", mode: "tornado"}, {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
{name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]}, {name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
{name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]}, {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
{name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]}, {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
{name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
{name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]}, {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
{name: "Twig", mime: "text/x-twig", mode: "twig"}, {name: "Twig", mime: "text/x-twig", mode: "twig"},
{name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]},
{name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]}, {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
{name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]}, {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
{name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
{name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
{name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]}, {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]},
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]},
{name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
{name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]},
{name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
{name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}, {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
{name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]}, {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
{name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]}, {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
@ -166,6 +178,8 @@
if (info.mimes) for (var j = 0; j < info.mimes.length; j++) if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
if (info.mimes[j] == mime) return info; if (info.mimes[j] == mime) return info;
} }
if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml")
if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json")
}; };
CodeMirror.findModeByExtension = function(ext) { CodeMirror.findModeByExtension = function(ext) {

View file

@ -83,10 +83,13 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) {
if ( /[+\-*&%=<>!?|]/.test(ch)) { if ( /[+\-*&%=<>!?|]/.test(ch)) {
return 'operator'; return 'operator';
} }
stream.eatWhile(/\w/); if (/[\w\xa1-\uffff]/.test(ch)) {
stream.eatWhile(/[\w\xa1-\uffff]/);
var cur = stream.current(); var cur = stream.current();
return words.hasOwnProperty(cur) ? words[cur] : 'variable'; return words.hasOwnProperty(cur) ? words[cur] : 'variable';
} }
return null
}
function tokenString(stream, state) { function tokenString(stream, state) {
var next, end = false, escaped = false; var next, end = false, escaped = false;

View file

@ -59,7 +59,7 @@ msc {
# Xù - expansions to MscGen to support inline expressions # Xù - expansions to MscGen to support inline expressions
# https://github.com/sverweij/mscgen_js/blob/master/wikum/xu.md # https://github.com/sverweij/mscgen_js/blob/master/wikum/xu.md
# More samples: https://sverweij.github.io/mscgen_js # More samples: https://sverweij.github.io/mscgen_js
msc { xu {
hscale="0.8", hscale="0.8",
width="700"; width="700";

View file

@ -23,6 +23,7 @@
mscgen: { mscgen: {
"keywords" : ["msc"], "keywords" : ["msc"],
"options" : ["hscale", "width", "arcgradient", "wordwraparcs"], "options" : ["hscale", "width", "arcgradient", "wordwraparcs"],
"constants" : ["true", "false", "on", "off"],
"attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"],
"brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
"arcsWords" : ["note", "abox", "rbox", "box"], "arcsWords" : ["note", "abox", "rbox", "box"],
@ -31,8 +32,9 @@
"operators" : ["="] "operators" : ["="]
}, },
xu: { xu: {
"keywords" : ["msc"], "keywords" : ["msc", "xu"],
"options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"],
"constants" : ["true", "false", "on", "off", "auto"],
"attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"],
"brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists
"arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
@ -43,6 +45,7 @@
msgenny: { msgenny: {
"keywords" : null, "keywords" : null,
"options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"],
"constants" : ["true", "false", "on", "off", "auto"],
"attributes" : null, "attributes" : null,
"brackets" : ["\\{", "\\}"], "brackets" : ["\\{", "\\}"],
"arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"],
@ -146,6 +149,9 @@
if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true)) if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true))
return "operator"; return "operator";
if (!!pConfig.constants && pStream.match(wordRegexp(pConfig.constants), true, true))
return "variable";
/* attribute lists */ /* attribute lists */
if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) { if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) {
pConfig.inAttributeList = true; pConfig.inAttributeList = true;

View file

@ -29,6 +29,14 @@
"[base alt loop opt ref else break par seq assert]" "[base alt loop opt ref else break par seq assert]"
); );
MT("xù/ msgenny constants classify as 'base'",
"[base auto]"
);
MT("mscgen constants classify as 'variable'",
"[variable true]", "[variable false]", "[variable on]", "[variable off]"
);
MT("mscgen options classify as keyword", MT("mscgen options classify as keyword",
"[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
); );
@ -63,7 +71,7 @@
MT("a typical program", MT("a typical program",
"[comment # typical mscgen program]", "[comment # typical mscgen program]",
"[keyword msc][base ][bracket {]", "[keyword msc][base ][bracket {]",
"[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]",
"[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
"[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
"[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",

View file

@ -23,6 +23,11 @@
"[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
); );
MT("xù/ msgenny constants classify as 'variable'",
"[variable auto]",
"[variable true]", "[variable false]", "[variable on]", "[variable off]"
);
MT("mscgen options classify as keyword", MT("mscgen options classify as keyword",
"[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
); );
@ -56,7 +61,7 @@
MT("a typical program", MT("a typical program",
"[comment # typical msgenny program]", "[comment # typical msgenny program]",
"[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]", "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]",
"[base a : ][string \"Entity A\"][base ,]", "[base a : ][string \"Entity A\"][base ,]",
"[base b : Entity B,]", "[base b : Entity B,]",
"[base c : Entity C;]", "[base c : Entity C;]",

View file

@ -11,6 +11,12 @@
"[bracket }]" "[bracket }]"
); );
MT("empty chart",
"[keyword xu][bracket {]",
"[base ]",
"[bracket }]"
);
MT("comments", MT("comments",
"[comment // a single line comment]", "[comment // a single line comment]",
"[comment # another single line comment /* and */ ignored here]", "[comment # another single line comment /* and */ ignored here]",
@ -29,6 +35,11 @@
"[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]"
); );
MT("xù/ msgenny constants classify as 'variable'",
"[variable auto]",
"[variable true]", "[variable false]", "[variable on]", "[variable off]"
);
MT("mscgen options classify as keyword", MT("mscgen options classify as keyword",
"[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]"
); );
@ -61,9 +72,9 @@
); );
MT("a typical program", MT("a typical program",
"[comment # typical mscgen program]", "[comment # typical xu program]",
"[keyword msc][base ][bracket {]", "[keyword xu][base ][bracket {]",
"[keyword wordwraparcs][operator =][string \"true\"][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30, ][keyword width][operator =][variable auto][base ;]",
"[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]",
"[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]",
"[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]",

View file

@ -1,4 +1,4 @@
<!doctype html> <!doctype html>
<title>CodeMirror: MUMPS mode</title> <title>CodeMirror: MUMPS mode</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
@ -73,7 +73,7 @@ SET2() ;EF. Return error code (also called from XUSRB)
IF '$LENGTH($PIECE(XUSER(1),U,2)) QUIT 21 ;p419, p434 IF '$LENGTH($PIECE(XUSER(1),U,2)) QUIT 21 ;p419, p434
Q 0 Q 0
; ;
</textarea> </textarea></div>
<script> <script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), { var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "mumps", mode: "mumps",

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<head>
<title>CodeMirror: NGINX mode</title> <title>CodeMirror: NGINX mode</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css"> <link rel=stylesheet href="../../doc/docs.css">

View file

@ -173,6 +173,6 @@ CodeMirror.defineMode("nginx", function(config) {
}; };
}); });
CodeMirror.defineMIME("text/nginx", "text/x-nginx-conf"); CodeMirror.defineMIME("text/x-nginx-conf", "nginx");
}); });

View file

@ -24,16 +24,16 @@ CodeMirror.defineSimpleMode("nsis",{
{ regex: /`(?:[^\\`]|\\.)*`?/, token: "string" }, { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" },
// Compile Time Commands // Compile Time Commands
{regex: /(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"}, {regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"},
// Conditional Compilation // Conditional Compilation
{regex: /(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true}, {regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true},
{regex: /(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true}, {regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true},
// Runtime Commands // Runtime Commands
{regex: /\b(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetPluginUnload|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"},
{regex: /\b(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true}, {regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true},
{regex: /\b(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true}, {regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true},
// Command Options // Command Options
{regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"}, {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"},
@ -71,13 +71,13 @@ CodeMirror.defineSimpleMode("nsis",{
{regex: /[-+\/*=<>!]+/, token: "operator"}, {regex: /[-+\/*=<>!]+/, token: "operator"},
// Variable // Variable
{regex: /\$[\w]+/, token: "variable"}, {regex: /\$\w+/, token: "variable"},
// Constant // Constant
{regex: /\${[\w]+}/,token: "variable-2"}, {regex: /\${[\w\.:-]+}/, token: "variable-2"},
// Language String // Language String
{regex: /\$\([\w]+\)/,token: "variable-3"} {regex: /\$\([\w\.:-]+\)/, token: "variable-3"}
], ],
comment: [ comment: [
{regex: /.*?\*\//, token: "comment", next: "start"}, {regex: /.*?\*\//, token: "comment", next: "start"},

Some files were not shown because too many files have changed in this diff Show more