diff --git a/addon/comment/comment.js b/addon/comment/comment.js new file mode 100644 index 0000000000..4f590f2870 --- /dev/null +++ b/addon/comment/comment.js @@ -0,0 +1,144 @@ +(function() { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + var from = cm.getCursor("start"), to = cm.getCursor("end"); + cm.uncomment(from, to) || cm.lineComment(from, to); + }; + + CodeMirror.defineExtension("lineComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + 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 pad = options.padding == null ? " " : options.padding; + var blankLines = options.commentBlankLines; + + self.operation(function() { + if (options.indent) { + var baseString = firstLine.slice(0, firstNonWS(firstLine)); + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i), cut = baseString.length; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + CodeMirror.defineExtension("blockComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + CodeMirror.defineExtension("uncomment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding; + lineComment: for(;;) { + if (!lineString) break; + for (var i = start; i <= end; ++i) { + var line = self.getLine(i); + var found = line.indexOf(lineString); + if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; + if (i != start && nonWS.test(line.slice(0, found))) break lineComment; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); + var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); + if (close == -1 && start != end) { + endLine = self.getLine(--end); + close = endLine.lastIndexOf(endString); + } + if (open == -1 || close == -1) return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +})(); diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index f85f2df127..18f9dff3ab 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -19,14 +19,14 @@ }); function clearPlaceholder(cm) { - if (cm._placeholder) { - cm._placeholder.parentNode.removeChild(cm._placeholder); - cm._placeholder = null; + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; } } function setPlaceholder(cm) { clearPlaceholder(cm); - var elt = cm._placeholder = document.createElement("pre"); + var elt = cm.state.placeholder = document.createElement("pre"); elt.style.cssText = "height: 0; overflow: visible"; elt.className = "CodeMirror-placeholder"; elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 43902aee68..2abc8c5fe6 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -23,9 +23,9 @@ return CodeMirror.Pass; } }; - var closingBrackets = []; + var closingBrackets = ""; for (var i = 0; i < pairs.length; i += 2) (function(left, right) { - if (left != right) closingBrackets.push(right); + if (left != right) closingBrackets += right; function surround(cm) { var selection = cm.getSelection(); cm.replaceSelection(left + selection + right); diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index dc78883f35..efdffb877c 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -3,17 +3,23 @@ CodeMirror.braceRangeFinder = function(cm, start) { var at = lineText.length, startChar, tokenType; for (; at > 0;) { var found = lineText.lastIndexOf("{", at); - if (found < start.ch) break; + var startToken = '{', endToken = '}'; + if (found < start.ch) { + found = lineText.lastIndexOf("[", at); + if (found < start.ch) break; + startToken = '['; endToken = ']'; + } + tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; } at = found - 1; } - if (startChar == null || lineText.lastIndexOf("}") > startChar) return; + if (startChar == null || lineText.lastIndexOf(startToken) > startChar) return; var count = 1, lastLine = cm.lineCount(), end, endCh; outer: for (var i = line + 1; i < lastLine; ++i) { var text = cm.getLine(i), pos = 0; for (;;) { - var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos); + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); if (nextOpen < 0) nextOpen = text.length; if (nextClose < 0) nextClose = text.length; pos = Math.min(nextOpen, nextClose); diff --git a/addon/lint/lint.css b/addon/lint/lint.css index 4fd72e774a..eb15381f02 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -24,18 +24,18 @@ -ms-transition: opacity .4s; } -.CodeMirror-lint-span-error, .CodeMirror-lint-span-warning { +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; } -.CodeMirror-lint-span-error { +.CodeMirror-lint-mark-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") ; } -.CodeMirror-lint-span-warning { +.CodeMirror-lint-mark-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 231eb2f567..2e7cea1925 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -59,7 +59,7 @@ CodeMirror.validate = (function() { } function clearMarks(cm) { - var state = cm._lintState; + var state = cm.state.lint; if (state.hasGutter) cm.clearGutter(GUTTER_ID); for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); @@ -105,16 +105,16 @@ CodeMirror.validate = (function() { } function startLinting(cm) { - var state = cm._lintState, options = state.options; - if (options.async) - options.getAnnotations(cm, updateLinting, options); - else - updateLinting(cm, options.getAnnotations(cm.getValue())); + var state = cm.state.lint, options = state.options; + if (options.async) + options.getAnnotations(cm, updateLinting, options); + else + updateLinting(cm, options.getAnnotations(cm.getValue())); } function updateLinting(cm, annotationsNotSorted) { clearMarks(cm); - var state = cm._lintState, options = state.options; + var state = cm.state.lint, options = state.options; var annotations = groupByLine(annotationsNotSorted); @@ -135,7 +135,7 @@ CodeMirror.validate = (function() { if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { - className: "CodeMirror-lint-span-" + severity, + className: "CodeMirror-lint-mark-" + severity, __annotation: ann })); } @@ -148,7 +148,7 @@ CodeMirror.validate = (function() { } function onChange(cm) { - var state = cm._lintState; + var state = cm.state.lint; clearTimeout(state.timeout); state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); } @@ -164,7 +164,7 @@ CodeMirror.validate = (function() { var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0]; function onMouseOver(cm, e) { - if (!/\bCodeMirror-lint-span-/.test((e.target || e.srcElement).className)) return; + if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return; for (var i = 0; i < nearby.length; i += 2) { var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i], top: e.clientY + nearby[i + 1]})); @@ -179,14 +179,14 @@ CodeMirror.validate = (function() { if (old && old != CodeMirror.Init) { clearMarks(cm); cm.off("change", onChange); - CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver); - delete cm._lintState; + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + delete cm.state.lint; } if (val) { var gutters = cm.getOption("gutters"), hasLintGutter = false; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; - var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter); + var state = cm.state.lint = new LintState(cm, parseOptions(val), hasLintGutter); cm.on("change", onChange); if (state.options.tooltips != false) CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js index 3e1bed7361..a7da6d718f 100644 --- a/addon/runmode/runmode.js +++ b/addon/runmode/runmode.js @@ -1,5 +1,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); if (callback.nodeType == 1) { var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; @@ -7,7 +9,9 @@ CodeMirror.runMode = function(string, modespec, callback, options) { node.innerHTML = ""; callback = function(text, style) { if (text == "\n") { - node.appendChild(document.createElement("br")); + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); col = 0; return; } diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js index 6449e77c84..a6ea919d83 100644 --- a/addon/runmode/runmode.node.js +++ b/addon/runmode/runmode.node.js @@ -60,8 +60,20 @@ exports.startState = function(mode, a1, a2) { }; var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; -exports.defineMode = function(name, mode) { modes[name] = mode; }; +exports.defineMode = function(name, mode) { + if (arguments.length > 2) { + mode.dependencies = []; + for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]); + } + modes[name] = mode; +}; exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; + +exports.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +exports.defineMIME("text/plain", "null"); + exports.getMode = function(options, spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) spec = mimeModes[spec]; diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 14c1dab5b6..0800f4c638 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -24,19 +24,19 @@ CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { - cm._matchHighlightState = new State(val); + cm.state.matchHighlighter = new State(val); cm.on("cursorActivity", highlightMatches); } else if (!val && prev) { - var over = cm._matchHighlightState.overlay; + var over = cm.state.matchHighlighter.overlay; if (over) cm.removeOverlay(over); - cm._matchHighlightState = null; + cm.state.matchHighlighter = null; cm.off("cursorActivity", highlightMatches); } }); function highlightMatches(cm) { cm.operation(function() { - var state = cm._matchHighlightState; + var state = cm.state.matchHighlighter; if (state.overlay) { cm.removeOverlay(state.overlay); state.overlay = null; diff --git a/addon/search/search.js b/addon/search/search.js index 6331b86555..eb9ab8bede 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -27,7 +27,7 @@ this.overlay = null; } function getSearchState(cm) { - return cm._searchState || (cm._searchState = new SearchState()); + return cm.state.search || (cm.state.search = new SearchState()); } function getSearchCursor(cm, query, pos) { // Heuristic: if the query string is all lowercase, do a case insensitive search. diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index a590e84443..3da3f04e8f 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -24,16 +24,26 @@ if (!newMatch) break; match = newMatch; start = match.index; - cutOff = match.index + 1; + cutOff = match.index + (match[0].length || 1); + if (cutOff == line.length) break; + } + var matchLen = (match && match[0].length) || 0; + if (!matchLen) { + if (start == 0 && line.length == 0) {match = undefined;} + else if (start != doc.getLine(pos.line).length) { + matchLen++; + } } } else { query.lastIndex = pos.ch; - var line = doc.getLine(pos.line), match = query.exec(line), - start = match && match.index; + var line = doc.getLine(pos.line), match = query.exec(line); + var matchLen = (match && match[0].length) || 0; + var start = match && match.index; + if (start + matchLen != line.length && !matchLen) matchLen = 1; } - if (match && match[0]) + if (match && matchLen) return {from: Pos(pos.line, start), - to: Pos(pos.line, start + match[0].length), + to: Pos(pos.line, start + matchLen), match: match}; }; } else { // String query diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index 211de0fefd..65fab6f162 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -17,23 +17,23 @@ } else if (!val && prev) { cm.off("cursorActivity", updateActiveLine); clearActiveLine(cm); - delete cm._activeLine; + delete cm.state.activeLine; } }); function clearActiveLine(cm) { - if ("_activeLine" in cm) { - cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS); - cm.removeLineClass(cm._activeLine, "background", BACK_CLASS); + if ("activeLine" in cm.state) { + cm.removeLineClass(cm.state.activeLine, "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLine, "background", BACK_CLASS); } } function updateActiveLine(cm) { var line = cm.getLineHandle(cm.getCursor().line); - if (cm._activeLine == line) return; + if (cm.state.activeLine == line) return; clearActiveLine(cm); cm.addLineClass(line, "wrap", WRAP_CLASS); cm.addLineClass(line, "background", BACK_CLASS); - cm._activeLine = line; + cm.state.activeLine = line; } })(); diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index d7ff30c9a9..c97776e492 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -1,7 +1,8 @@ // Because sometimes you need to mark the selected *text*. // // Adds an option 'styleSelectedText' which, when enabled, gives -// selected text the CSS class "CodeMirror-selectedtext". +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. (function() { "use strict"; @@ -9,26 +10,99 @@ CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { - updateSelectedText(cm); - cm.on("cursorActivity", updateSelectedText); + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); } else if (!val && prev) { - cm.off("cursorActivity", updateSelectedText); - clearSelectedText(cm); - delete cm._selectionMark; + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; } }); - function clearSelectedText(cm) { - if (cm._selectionMark) cm._selectionMark.clear(); + function onCursorActivity(cm) { + cm.operation(function() { update(cm); }); } - function updateSelectedText(cm) { - clearSelectedText(cm); + function onChange(cm) { + if (cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + + function cmp(pos1, pos2) { + return pos1.line - pos2.line || pos1.ch - pos2.ch; + } + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } - if (cm.somethingSelected()) - cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"), - {className: "CodeMirror-selectedtext"}); - else - cm._selectionMark = null; + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var from = cm.getCursor("start"), to = cm.getCursor("end"); + coverRange(cm, from, to); + } + + function update(cm) { + var from = cm.getCursor("start"), to = cm.getCursor("end"); + if (cmp(from, to) == 0) return clear(cm); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } } })(); diff --git a/bin/compress b/bin/compress index d059b618ba..809fbe83d4 100755 --- a/bin/compress +++ b/bin/compress @@ -29,14 +29,15 @@ function help(ok) { process.exit(ok ? 0 : 1); } -var local = null, args = null, files = [], blob = ""; +var local = null, args = [], extraArgs = null, files = [], blob = ""; for (var i = 2; i < process.argv.length; ++i) { var arg = process.argv[i]; if (arg == "--local" && i + 1 < process.argv.length) { var parts = process.argv[++i].split(/\s+/); local = parts[0]; - args = parts.slice(1); + extraArgs = parts.slice(1); + if (!extraArgs.length) extraArgs = ["-c", "-m"]; } else if (arg == "--help") { help(true); } else if (arg[0] != "-") { @@ -73,7 +74,7 @@ if (files.length) { } if (local) { - require("child_process").spawn(local, args, {stdio: ["ignore", process.stdout, process.stderr]}); + require("child_process").spawn(local, args.concat(extraArgs), {stdio: ["ignore", process.stdout, process.stderr]}); } else { var data = new Buffer("js_code=" + require("querystring").escape(blob), "utf8"); var req = require("http").request({ diff --git a/bin/source-highlight b/bin/source-highlight new file mode 100755 index 0000000000..7596ed776c --- /dev/null +++ b/bin/source-highlight @@ -0,0 +1,61 @@ +#!/usr/bin/env node + +// Simple command-line code highlighting tool. Reads code from stdin, +// spits html to stdout. For example: +// +// echo 'function foo(a) { return a; }' | bin/source-highlight -s javascript +// bin/source-highlight -s + +var fs = require("fs"); + +CodeMirror = require("../addon/runmode/runmode.node.js"); +require("../mode/meta.js"); + +var sPos = process.argv.indexOf("-s"); +if (sPos == -1 || sPos == process.argv.length - 1) { + console.error("Usage: source-highlight -s language"); + process.exit(1); +} +var lang = process.argv[sPos + 1].toLowerCase(), modeName = lang; +CodeMirror.modeInfo.forEach(function(info) { + if (info.mime == lang) { + modeName = info.mode; + } else if (info.name.toLowerCase() == lang) { + modeName = info.mode; + lang = info.mime; + } +}); + +function ensureMode(name) { + if (CodeMirror.modes[name] || name == "null") return; + try { + require("../mode/" + name + "/" + name + ".js"); + } catch(e) { + console.error("Could not load mode " + name + "."); + process.exit(1); + } + var obj = CodeMirror.modes[name]; + if (obj.dependencies) obj.dependencies.forEach(ensureMode); +} +ensureMode(modeName); + +function esc(str) { + return str.replace(/[<&]/, function(ch) { return ch == "&" ? "&" : "<"; }); +} + +var code = fs.readFileSync("/dev/stdin", "utf8"); +var curStyle = null, accum = ""; +function flush() { + if (curStyle) process.stdout.write("" + esc(accum) + ""); + else process.stdout.write(esc(accum)); +} + +CodeMirror.runMode(code, lang, function(text, style) { + if (style != curStyle) { + flush(); + curStyle = style; accum = text; + } else { + accum += text; + } +}); +flush(); diff --git a/doc/compress.html b/doc/compress.html index f1fa218def..9c0fafec18 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

Version: + + + + + + + + + + + + + + + + + + + + Select Font Size + + + + +

+ + + + diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index cf1cf4f246..509d9207bb 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -337,8 +337,9 @@ CodeMirror.defineMode('coffeescript', function(conf) { } return state.scopes[0].offset; - } + }, + lineComment: "#" }; return external; }); diff --git a/mode/commonlisp/commonlisp.js b/mode/commonlisp/commonlisp.js index eeba759668..8fa08c8ac2 100644 --- a/mode/commonlisp/commonlisp.js +++ b/mode/commonlisp/commonlisp.js @@ -94,7 +94,11 @@ CodeMirror.defineMode("commonlisp", function (config) { indent: function (state, _textAfter) { var i = state.ctx.indentTo; return typeof i == "number" ? i : state.ctx.start + 1; - } + }, + + lineComment: ";;", + blockCommentStart: "#|", + blockCommentEnd: "|#" }; }); diff --git a/mode/css/css.js b/mode/css/css.js index 1ef72b517d..27c97f37eb 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -165,26 +165,27 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { if (type == "variable-definition") state.stack.push("propertyValue"); return "variable-2"; } else if (style == "property") { - if (context == "propertyValue"){ - if (valueKeywords[stream.current()]) { + var word = stream.current().toLowerCase(); + if (context == "propertyValue") { + if (valueKeywords.hasOwnProperty(word)) { style = "string-2"; - } else if (colorKeywords[stream.current()]) { + } else if (colorKeywords.hasOwnProperty(word)) { style = "keyword"; } else { style = "variable-2"; } } else if (context == "rule") { - if (!propertyKeywords[stream.current()]) { + if (!propertyKeywords.hasOwnProperty(word)) { style += " error"; } } else if (context == "block") { // if a value is present in both property, value, or color, the order // of preference is property -> color -> value - if (propertyKeywords[stream.current()]) { + if (propertyKeywords.hasOwnProperty(word)) { style = "property"; - } else if (colorKeywords[stream.current()]) { + } else if (colorKeywords.hasOwnProperty(word)) { style = "keyword"; - } else if (valueKeywords[stream.current()]) { + } else if (valueKeywords.hasOwnProperty(word)) { style = "string-2"; } else { style = "tag"; @@ -194,42 +195,42 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } else if (context == "@media") { if (atMediaTypes[stream.current()]) { style = "attribute"; // Known attribute - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "keyword"; - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "error"; // "and" is only allowed in @mediaType - } else if (atMediaFeatures[stream.current()]) { + } else if (atMediaFeatures.hasOwnProperty(word)) { style = "error"; // Known property, should be in @mediaType( } else { // Unknown, expecting keyword or attribute, assuming attribute style = "attribute error"; } } else if (context == "@mediaType") { - if (atMediaTypes[stream.current()]) { + if (atMediaTypes.hasOwnProperty(word)) { style = "attribute"; - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "operator"; - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "error"; // Only allowed in @media - } else if (atMediaFeatures[stream.current()]) { - style = "error"; // Known property, should be in parentheses } else { // Unknown attribute or property, but expecting property (preceded // by "and"). Should be in parentheses style = "error"; } } else if (context == "@mediaType(") { - if (propertyKeywords[stream.current()]) { + if (propertyKeywords.hasOwnProperty(word)) { // do nothing, remains "property" - } else if (atMediaTypes[stream.current()]) { + } else if (atMediaTypes.hasOwnProperty(word)) { style = "error"; // Known property, should be in parentheses - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "operator"; - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "error"; // Only allowed in @media } else { style += " error"; } + } else if (context == "@import") { + style = "tag"; } else { style = "error"; } @@ -266,6 +267,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } else if (type == "interpolation") state.stack.push("interpolation"); else if (type == "@media") state.stack.push("@media"); + else if (type == "@import") state.stack.push("@import"); else if (context == "@media" && /\b(keyword|attribute)\b/.test(style)) state.stack.push("@mediaType"); else if (context == "@mediaType" && stream.current() == ",") state.stack.pop(); @@ -273,6 +275,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { else if (context == "@mediaType(" && type == ")") state.stack.pop(); else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue"); else if (context == "propertyValue" && type == ";") state.stack.pop(); + else if (context == "@import" && type == ";") state.stack.pop(); return style; }, @@ -283,7 +286,9 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { return state.baseIndent + n * indentUnit; }, - electricChars: "}" + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/" }; }); @@ -387,12 +392,46 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", - "word-spacing", "word-wrap", "z-index" + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", "color-profile", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode" ]); var colorKeywords = keySet([ - "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", - "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua" + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", + "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" ]); var valueKeywords = keySet([ @@ -475,7 +514,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", - "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", "window", "windowframe", "windowtext", "x-large", "x-small", "xor", "xx-large", "xx-small" ]); diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index 029b8e5561..79e0434d1f 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -456,8 +456,9 @@ CodeMirror.defineMode("erlang", function(cmCfg) { indent: function(state, textAfter) { -// console.log(state.tokenStack); return myIndent(state,textAfter); - } + }, + + lineComment: "%" }; }); diff --git a/mode/gas/gas.js b/mode/gas/gas.js index 6604f01820..a6e6892908 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -321,6 +321,10 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { return style; } } - } + }, + + lineComment: lineCommentStartSymbol, + blockCommentStart: "/*", + blockCommentEnd: "*/" }; }); diff --git a/mode/go/go.js b/mode/go/go.js index 8b84a5ca42..6a458a6fe9 100644 --- a/mode/go/go.js +++ b/mode/go/go.js @@ -158,7 +158,10 @@ CodeMirror.defineMode("go", function(config) { else return ctx.indented + (closing ? 0 : indentUnit); }, - electricChars: "{}:" + electricChars: "{}:", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" }; }); diff --git a/mode/haml/haml.js b/mode/haml/haml.js new file mode 100644 index 0000000000..793308f6fb --- /dev/null +++ b/mode/haml/haml.js @@ -0,0 +1,153 @@ +(function() { + "use strict"; + + // full haml mode. This handled embeded ruby and html fragments too + CodeMirror.defineMode("haml", function(config) { + var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); + var rubyMode = CodeMirror.getMode(config, "ruby"); + + function rubyInQuote(endQuote) { + return function(stream, state) { + var ch = stream.peek(); + if (ch == endQuote && state.rubyState.tokenize.length == 1) { + // step out of ruby context as it seems to complete processing all the braces + stream.next(); + state.tokenize = html; + return "closeAttributeTag"; + } else { + return ruby(stream, state); + } + }; + } + + function ruby(stream, state) { + if (stream.match("-#")) { + stream.skipToEnd(); + return "comment"; + } + return rubyMode.token(stream, state.rubyState); + } + + function html(stream, state) { + var ch = stream.peek(); + + // handle haml declarations. All declarations that cant be handled here + // will be passed to html mode + if (state.previousToken.style == "comment" ) { + if (state.indented > state.previousToken.indented) { + stream.skipToEnd(); + return "commentLine"; + } + } + + if (state.startOfLine) { + if (ch == "!" && stream.match("!!")) { + stream.skipToEnd(); + return "tag"; + } else if (stream.match(/^%[\w:#\.]+=/)) { + state.tokenize = ruby; + return "hamlTag"; + } else if (stream.match(/^%[\w:]+/)) { + return "hamlTag"; + } else if (ch == "/" ) { + stream.skipToEnd(); + return "comment"; + } + } + + if (state.startOfLine || state.previousToken.style == "hamlTag") { + if ( ch == "#" || ch == ".") { + stream.match(/[\w-#\.]*/); + return "hamlAttribute"; + } + } + + // donot handle --> as valid ruby, make it HTML close comment instead + if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { + state.tokenize = ruby; + return null; + } + + if (state.previousToken.style == "hamlTag" || + state.previousToken.style == "closeAttributeTag" || + state.previousToken.style == "hamlAttribute") { + if (ch == "(") { + state.tokenize = rubyInQuote(")"); + return null; + } else if (ch == "{") { + state.tokenize = rubyInQuote("}"); + return null; + } + } + + return htmlMode.token(stream, state.htmlState); + } + + return { + // default to html mode + startState: function() { + var htmlState = htmlMode.startState(); + var rubyState = rubyMode.startState(); + return { + htmlState: htmlState, + rubyState: rubyState, + indented: 0, + previousToken: { style: null, indented: 0}, + tokenize: html + }; + }, + + copyState: function(state) { + return { + htmlState : CodeMirror.copyState(htmlMode, state.htmlState), + rubyState: CodeMirror.copyState(rubyMode, state.rubyState), + indented: state.indented, + previousToken: state.previousToken, + tokenize: state.tokenize + }; + }, + + token: function(stream, state) { + if (stream.sol()) { + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + state.startOfLine = false; + // dont record comment line as we only want to measure comment line with + // the opening comment block + if (style && style != "commentLine") { + state.previousToken = { style: style, indented: state.indented }; + } + // if current state is ruby and the previous token is not `,` reset the + // tokenize to html + if (stream.eol() && state.tokenize == ruby) { + stream.backUp(1); + var ch = stream.peek(); + stream.next(); + if (ch && ch != ",") { + state.tokenize = html; + } + } + // reprocess some of the specific style tag when finish setting previousToken + if (style == "hamlTag") { + style = "tag"; + } else if (style == "commentLine") { + style = "comment"; + } else if (style == "hamlAttribute") { + style = "attribute"; + } else if (style == "closeAttributeTag") { + style = null; + } + return style; + }, + + indent: function(state) { + return state.indented; + } + }; + }, "htmlmixed", "ruby"); + + CodeMirror.defineMIME("text/x-haml", "haml"); +})(); diff --git a/mode/haml/index.html b/mode/haml/index.html new file mode 100644 index 0000000000..7da378fc80 --- /dev/null +++ b/mode/haml/index.html @@ -0,0 +1,67 @@ + + + + + CodeMirror: HAML mode + + + + + + + + + + + +

CodeMirror: HAML mode

+
+ + +

MIME types defined: text/x-haml.

+ +

Parsing/Highlighting Tests: normal, verbose.

+ + + diff --git a/mode/haml/test.js b/mode/haml/test.js new file mode 100644 index 0000000000..b7178d40fb --- /dev/null +++ b/mode/haml/test.js @@ -0,0 +1,94 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "haml"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Requires at least one media query + MT("elementName", + "[tag %h1] Hey There"); + + MT("oneElementPerLine", + "[tag %h1] Hey There %h2"); + + MT("idSelector", + "[tag %h1][attribute #test] Hey There"); + + MT("classSelector", + "[tag %h1][attribute .hello] Hey There"); + + MT("docType", + "[tag !!! XML]"); + + MT("comment", + "[comment / Hello WORLD]"); + + MT("notComment", + "[tag %h1] This is not a / comment "); + + MT("attributes", + "[tag %a]([variable title][operator =][string \"test\"]){[atom :title] [operator =>] [string \"test\"]}"); + + MT("htmlCode", + "[tag

]Title[tag

]"); + + MT("rubyBlock", + "[operator =][variable-2 @item]"); + + MT("selectorRubyBlock", + "[tag %a.selector=] [variable-2 @item]"); + + MT("nestedRubyBlock", + "[tag %a]", + " [operator =][variable puts] [string \"test\"]"); + + MT("multilinePlaintext", + "[tag %p]", + " Hello,", + " World"); + + MT("multilineRuby", + "[tag %p]", + " [comment -# this is a comment]", + " [comment and this is a comment too]", + " Date/Time", + " [operator -] [variable now] [operator =] [tag DateTime][operator .][variable now]", + " [tag %strong=] [variable now]", + " [operator -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][variable parse]([string \"December 31, 2006\"])", + " [operator =][string \"Happy\"]", + " [operator =][string \"Belated\"]", + " [operator =][string \"Birthday\"]"); + + MT("multilineComment", + "[comment /]", + " [comment Multiline]", + " [comment Comment]"); + + MT("hamlComment", + "[comment -# this is a comment]"); + + MT("multilineHamlComment", + "[comment -# this is a comment]", + " [comment and this is a comment too]"); + + MT("multilineHTMLComment", + "[comment ]"); + + MT("hamlAfterRubyTag", + "[attribute .block]", + " [tag %strong=] [variable now]", + " [attribute .test]", + " [operator =][variable now]", + " [attribute .right]"); + + MT("stretchedRuby", + "[operator =] [variable puts] [string \"Hello\"],", + " [string \"World\"]"); + + MT("interpolationInHashAttribute", + //"[tag %div]{[atom :id] [operator =>] [string \"#{][variable test][string }_#{][variable ting][string }\"]} test"); + "[tag %div]{[atom :id] [operator =>] [string \"#{][variable test][string }_#{][variable ting][string }\"]} test"); + + MT("interpolationInHTMLAttribute", + "[tag %div]([variable title][operator =][string \"#{][variable test][string }_#{][variable ting]()[string }\"]) Test"); +})(); diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index faec08dc33..b18d5ced1a 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -234,7 +234,11 @@ CodeMirror.defineMode("haskell", function() { var t = state.f(stream, function(s) { state.f = s; }); var w = stream.current(); return (w in wellKnownWords) ? wellKnownWords[w] : t; - } + }, + + blockCommentStart: "{-", + blockCommentEnd: "-}", + lineComment: "--" }; }); diff --git a/mode/javascript/index.html b/mode/javascript/index.html index dd0ca220d8..db063b772d 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -7,6 +7,7 @@ + @@ -68,7 +69,8 @@ var editor = CodeMirror.fromTextArea(document.getElementById("code"), { lineNumbers: true, matchBrackets: true, - continueComments: "Enter" + continueComments: "Enter", + extraKeys: {"Ctrl-Q": "toggleComment"} }); diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 08c1cb1f4f..fabe1c42b9 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -291,7 +291,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); + if (type == ",") return pass(); return maybeoperatorNoComma(type, value, maybeoperatorComma); } function maybeoperatorNoComma(type, value, me) { @@ -453,6 +453,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }, electricChars: ":{}", + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", jsonMode: jsonMode }; @@ -463,5 +466,6 @@ CodeMirror.defineMIME("text/ecmascript", "javascript"); CodeMirror.defineMIME("application/javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); diff --git a/mode/less/less.js b/mode/less/less.js index 6df4790995..09f510e032 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -7,12 +7,6 @@ CodeMirror.defineMode("less", function(config) { var indentUnit = config.indentUnit, type; function ret(style, tp) {type = tp; return style;} - //html tags - var tags = "a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption cite code col colgroup command datalist dd del details dfn dir div dl dt em embed fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins keygen kbd label legend li link map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr".split(' '); - - function inTagsArray(val){ - for(var i=0; i", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"]; var opRegexp = tokenRegexp(operators); - function htmlTag(val){ - for(var i=0; i=@%|&?!.:;^]/; + var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/; var keywords = /true|false|nil|self|super|thisContext/; var Context = function(tokenizer, parent) { @@ -36,11 +36,14 @@ CodeMirror.defineMode('smalltalk', function(config) { token = nextString(stream, new Context(nextString, context)); } else if (aChar === '#') { - stream.eatWhile(/[^ .]/); + stream.eatWhile(/[^ .\[\]()]/); token.name = 'string-2'; } else if (aChar === '$') { - stream.eatWhile(/[^ ]/); + if (stream.next() === '<') { + stream.eatWhile(/[^ >]/); + stream.next(); + } token.name = 'string-2'; } else if (aChar === '|' && state.expectVariable) { @@ -118,7 +121,6 @@ CodeMirror.defineMode('smalltalk', function(config) { state.context = token.context; state.expectVariable = token.eos; - state.lastToken = token; return token.name; }, diff --git a/mode/sql/index.html b/mode/sql/index.html index 7ec938a121..8a2495ca24 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -6,7 +6,6 @@ -