diff --git a/AUTHORS b/AUTHORS index 67fd2fdcb0..ad2ec99576 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ alexey-k Alex Piggott Amy Ananya Sen +AndersMad Andre von Houck Andrey Lushnikov Andy Kimball @@ -36,6 +37,7 @@ Ben Keen boomyjee borawjm Brandon Frohs +Brett Zamir Brian Sletten Bruce Mitchener Chandra Sekhar Pydi @@ -44,6 +46,7 @@ Chris Coyier Chris Granger Chris Morgan Christopher Brown +ciaranj CodeAnimal ComFreek dagsta @@ -76,6 +79,7 @@ Felipe Lalanne Felix Raab Filip Noetzel flack +ForbesLindesay Ford_Lawnmower Gabriel Nahmias galambalazs @@ -85,6 +89,7 @@ Golevka Gordon Smith greengiant Guillaume Massé +Guillaume Massé Hans Engel Hardest Hasan Karahan @@ -137,11 +142,11 @@ komakino Konstantin Lopuhin koops ks-ifware +kubelsmieci Lanny leaf corcoran Leonya Khachaturov Liam Newman -List of contributors. Updated before every release. LM Lorenzo Stoakes lynschinzer @@ -152,6 +157,8 @@ Marco Aurélio Marijn Haverbeke Mario Pietsch Mark Lentczner +Martin Balek +Martín Gaitán Mason Malone Mateusz Paprocki mats cronqvist @@ -220,6 +227,7 @@ Stas Kobzar Stefan Borsje Steffen Beyer Steve O'Hara +stoskov Tarmil tfjgeorge Thaddee Tyl @@ -229,6 +237,8 @@ Thomas Schmid Tim Baumann Timothy Farrell Timothy Hatcher +TobiasBg +Tomas-A Tomas Varaneckas Tom Erik Støwer Tom MacWright diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e040ff193..8938f62046 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,12 +4,12 @@ - [Submitting bug reports](#submitting-bug-reports-) - [Contributing code](#contributing-code-) -## Getting help [^](#how-to-contribute) +## Getting help Community discussion, questions, and informal bug reporting is done on the [CodeMirror Google group](http://groups.google.com/group/codemirror). -## Submitting bug reports [^](#how-to-contribute) +## Submitting bug reports The preferred way to report bugs is to use the [GitHub issue tracker](http://github.com/marijnh/CodeMirror/issues). Before @@ -45,7 +45,7 @@ should be asked on the [jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and include the resulting link in your bug report. -## Contributing code [^](#how-to-contribute) +## Contributing code - Make sure you have a [GitHub Account](https://github.com/signup/free) - Fork [CodeMirror](https://github.com/marijnh/CodeMirror/) diff --git a/LICENSE b/LICENSE index ade341ca6e..442d11cdce 100644 --- a/LICENSE +++ b/LICENSE @@ -17,7 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Please note that some subdirectories of the CodeMirror distribution -include their own LICENSE files, and are released under different -licences. diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index 9dba156189..94e5a3760f 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -1,35 +1,43 @@ (function() { var modes = ["clike", "css", "javascript"]; for (var i = 0; i < modes.length; ++i) - CodeMirror.extendMode(modes[i], {blockCommentStart: "/*", - blockCommentEnd: "*/", - blockCommentContinue: " * "}); + CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); function continueComment(cm) { var pos = cm.getCursor(), token = cm.getTokenAt(pos); + if (token.type != "comment") return CodeMirror.Pass; var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode; - var space; - if (token.type == "comment" && mode.blockCommentStart && mode.blockCommentContinue) { + var insert; + if (mode.blockCommentStart && mode.blockCommentContinue) { var end = token.string.indexOf(mode.blockCommentEnd); var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; if (end != -1 && end == token.string.length - mode.blockCommentEnd.length) { // Comment ended, don't continue it } else if (token.string.indexOf(mode.blockCommentStart) == 0) { - space = full.slice(0, token.start); - if (!/^\s*$/.test(space)) { - space = ""; - for (var i = 0; i < token.start; ++i) space += " "; + insert = full.slice(0, token.start); + if (!/^\s*$/.test(insert)) { + insert = ""; + for (var i = 0; i < token.start; ++i) insert += " "; } } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && found + mode.blockCommentContinue.length > token.start && /^\s*$/.test(full.slice(0, found))) { - space = full.slice(0, found); + insert = full.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue; + } + if (insert == null && mode.lineComment) { + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); + if (found > -1) { + insert = line.slice(0, found); + if (/\S/.test(insert)) insert = null; + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; } } - if (space != null) - cm.replaceSelection("\n" + space + mode.blockCommentContinue, "end"); + if (insert != null) + cm.replaceSelection("\n" + insert, "end"); else return CodeMirror.Pass; } @@ -37,8 +45,10 @@ CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { if (prev && prev != CodeMirror.Init) cm.removeKeyMap("continueComment"); - var map = {name: "continueComment"}; - map[typeof val == "string" ? val : "Enter"] = continueComment; - cm.addKeyMap(map); + if (val) { + var map = {name: "continueComment"}; + map[typeof val == "string" ? val : "Enter"] = continueComment; + cm.addKeyMap(map); + } }); })(); diff --git a/addon/display/fullscreen.css b/addon/display/fullscreen.css index 00ad677ff5..437acd89be 100644 --- a/addon/display/fullscreen.css +++ b/addon/display/fullscreen.css @@ -2,5 +2,5 @@ position: fixed; top: 0; left: 0; right: 0; bottom: 0; height: auto; - z-index: 9999; + z-index: 9; } diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 454dfea5e6..0bc3e8be17 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -27,9 +27,9 @@ if (val && (old == CodeMirror.Init || !old)) { var map = {name: "autoCloseTags"}; if (typeof val != "object" || val.whenClosing) - map["'/'"] = function(cm) { return autoCloseTag(cm, '/'); }; + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; if (typeof val != "object" || val.whenOpening) - map["'>'"] = function(cm) { return autoCloseTag(cm, '>'); }; + map["'>'"] = function(cm) { return autoCloseGT(cm); }; cm.addKeyMap(map); } else if (!val && (old != CodeMirror.Init && old)) { cm.removeKeyMap("autoCloseTags"); @@ -41,40 +41,41 @@ var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; - function autoCloseTag(cm, ch) { + function autoCloseGT(cm) { var pos = cm.getCursor(), tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; - if (inner.mode.name != "xml") return CodeMirror.Pass; + if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); - if (ch == ">" && state.tagName) { - var tagName = state.tagName; - if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); - var lowerTagName = tagName.toLowerCase(); - // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "tag" && state.type == "closeTag" || - tok.string.indexOf("/") == (tok.string.length - 1) || // match something like - dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) - return CodeMirror.Pass; + var tagName = state.tagName; + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (tok.type == "tag" && state.type == "closeTag" || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) + return CodeMirror.Pass; - var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; - var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); - cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "", - {head: curPos, anchor: curPos}); - if (doIndent) { - cm.indentLine(pos.line + 1); - cm.indentLine(pos.line + 2); - } - return; - } else if (ch == "/" && tok.string == "<") { - var tagName = state.context && state.context.tagName; - if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); - return; + var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; + var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); + cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "", + {head: curPos, anchor: curPos}); + if (doIndent) { + cm.indentLine(pos.line + 1); + cm.indentLine(pos.line + 2); } - return CodeMirror.Pass; + } + + function autoCloseSlash(cm) { + var pos = cm.getCursor(), tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + if (tok.string.charAt(0) != "<" || inner.mode.name != "xml") return CodeMirror.Pass; + + var tagName = state.context && state.context.tagName; + if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); } function indexOf(collection, elt) { diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js index 3eabfeb8d3..f189c1f8ef 100644 --- a/addon/edit/matchtags.js +++ b/addon/edit/matchtags.js @@ -8,6 +8,7 @@ clear(cm); } if (val) { + cm.state.matchBothTags = typeof val == "object" && val.bothTags; cm.on("cursorActivity", doMatchTags); cm.on("viewportChange", maybeUpdateMatch); doMatchTags(cm); @@ -15,23 +16,27 @@ }); function clear(cm) { - if (cm.state.matchedTag) { - cm.state.matchedTag.clear(); - cm.state.matchedTag = null; - } + if (cm.state.tagHit) cm.state.tagHit.clear(); + if (cm.state.tagOther) cm.state.tagOther.clear(); + cm.state.tagHit = cm.state.tagOther = null; } function doMatchTags(cm) { cm.state.failedTagMatch = false; cm.operation(function() { clear(cm); + if (cm.somethingSelected()) return; var cur = cm.getCursor(), range = cm.getViewport(); range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); var match = CodeMirror.findMatchingTag(cm, cur, range); if (!match) return; + if (cm.state.matchBothTags) { + var hit = match.at == "open" ? match.open : match.close; + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); + } var other = match.at == "close" ? match.open : match.close; if (other) - cm.state.matchedTag = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); else cm.state.failedTagMatch = true; }); diff --git a/addon/hint/css-hint.js b/addon/hint/css-hint.js new file mode 100644 index 0000000000..2b15300d0c --- /dev/null +++ b/addon/hint/css-hint.js @@ -0,0 +1,50 @@ +(function () { + "use strict"; + + function getHints(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css") return; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_-]*$/.test(token.string)) { + token = { + start: cur.ch, end: cur.ch, string: "", state: token.state, + type: null + }; + var stack = token.state.stack; + var lastToken = stack && stack.length > 0 ? stack[stack.length - 1] : ""; + if (token.string == ":" || lastToken.indexOf("property") == 0) + token.type = "variable"; + else if (token.string == "{" || lastToken.indexOf("rule") == 0) + token.type = "property"; + } + + if (!token.type) + return; + + var spec = CodeMirror.resolveMode("text/css"); + var keywords = null; + if (token.type.indexOf("property") == 0) + keywords = spec.propertyKeywords; + else if (token.type.indexOf("variable") == 0) + keywords = spec.valueKeywords; + + if (!keywords) + return; + + var result = []; + for (var name in keywords) { + if (name.indexOf(token.string) == 0 /* > -1 */) + result.push(name); + } + + return { + list: result, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + } + + CodeMirror.registerHelper("hint", "css", getHints); +})(); diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index a33c4c3559..dbf415527a 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -111,10 +111,10 @@ var baseMap = { Up: function() {handle.moveFocus(-1);}, Down: function() {handle.moveFocus(1);}, - PageUp: function() {handle.moveFocus(-handle.menuSize());}, - PageDown: function() {handle.moveFocus(handle.menuSize());}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, Home: function() {handle.setFocus(0);}, - End: function() {handle.setFocus(handle.length);}, + End: function() {handle.setFocus(handle.length - 1);}, Enter: handle.pick, Tab: handle.pick, Esc: handle.close @@ -167,6 +167,7 @@ // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + (options.container || document.body).appendChild(hints); var box = hints.getBoundingClientRect(); var overlapX = box.right - winW, overlapY = box.bottom - winH; if (overlapX > 0) { @@ -187,10 +188,9 @@ } hints.style.top = (top = pos.bottom - overlapY) + "px"; } - (options.container || document.body).appendChild(hints); cm.addKeyMap(this.keyMap = buildKeyMap(options, { - moveFocus: function(n) { widget.changeActive(widget.selectedHint + n); }, + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, setFocus: function(n) { widget.changeActive(n); }, menuSize: function() { return widget.screenAmount(); }, length: completions.length, @@ -250,8 +250,11 @@ this.completion.pick(this.data, this.selectedHint); }, - changeActive: function(i) { - i = Math.max(0, Math.min(i, this.data.list.length - 1)); + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; if (this.selectedHint == i) return; var node = this.hints.childNodes[this.selectedHint]; node.className = node.className.replace(" CodeMirror-hint-active", ""); diff --git a/addon/lint/css-lint.js b/addon/lint/css-lint.js new file mode 100644 index 0000000000..ba650f6a22 --- /dev/null +++ b/addon/lint/css-lint.js @@ -0,0 +1,17 @@ +// Depends on csslint.js from https://github.com/stubbornella/csslint + +CodeMirror.registerHelper("lint", "css", function(text) { + var found = []; + var results = CSSLint.verify(text), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); diff --git a/addon/lint/lint.css b/addon/lint/lint.css index eb15381f02..e592b3672a 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -57,40 +57,16 @@ } .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { - background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs="); + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); } .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { - background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); } .CodeMirror-lint-marker-multiple { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: right bottom; width: 100%; height: 100%; } - -/* Styles for the overview ruler -.annotationOverview { - cursor: pointer; - border-radius: 2px; - left: 2px; - width: 8px; -} -.annotationOverview.error { - background-color: lightcoral; - border: 1px solid darkred; -} -.annotationOverview.warning { - background-color: Gold; - border: 1px solid black; -} - -.annotationHTML.overlay { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); - background-position: right bottom; - position: relative; - top: -16px; -} -*/ \ No newline at end of file diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 67a92970a3..b502ee41f1 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -112,7 +112,7 @@ if (options.async) options.getAnnotations(cm, updateLinting, options); else - updateLinting(cm, options.getAnnotations(cm.getValue())); + updateLinting(cm, options.getAnnotations(cm.getValue(), options)); } function updateLinting(cm, annotationsNotSorted) { diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 16c3356c20..ceb48032b1 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -31,9 +31,17 @@ this.diff = getDiff(orig, options.value); this.diffOutOfDate = false; + this.showDifferences = options.showDifferences !== false; this.forceUpdate = registerUpdate(this); setScrollLock(this, true, false); registerScroll(this); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } } }; @@ -41,26 +49,38 @@ var edit = {from: 0, to: 0, marked: []}; var orig = {from: 0, to: 0, marked: []}; var debounceChange; - function update() { + function update(mode) { + if (mode == "full") { + if (dv.svg) clear(dv.svg); + clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } if (dv.diffOutOfDate) { dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue()); dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); } - updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); - updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); drawConnectors(dv); } function set(slow) { clearTimeout(debounceChange); debounceChange = setTimeout(update, slow == true ? 250 : 100); } - dv.edit.on("change", function() { + function change() { if (!dv.diffOutOfDate) { dv.diffOutOfDate = true; edit.from = edit.to = orig.from = orig.to = 0; } set(true); - }); + } + dv.edit.on("change", change); + dv.orig.on("change", change); dv.edit.on("viewportChange", set); dv.orig.on("viewportChange", set); update(); @@ -211,6 +231,8 @@ // Updating the gap between editor and original function drawConnectors(dv) { + if (!dv.showDifferences) return; + if (dv.svg) { clear(dv.svg); var w = dv.gap.offsetWidth; @@ -322,7 +344,11 @@ constuctor: MergeView, editor: function() { return this.edit; }, rightOriginal: function() { return this.right && this.right.orig; }, - leftOriginal: function() { return this.left && this.left.orig; } + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + } }; // Operations on diffs diff --git a/addon/runmode/runmode-standalone.js b/addon/runmode/runmode-standalone.js index 5be7d74405..0fb98a9e3b 100644 --- a/addon/runmode/runmode-standalone.js +++ b/addon/runmode/runmode-standalone.js @@ -125,7 +125,7 @@ CodeMirror.runMode = function (string, modespec, callback, options) { var stream = new CodeMirror.StringStream(lines[i]); while (!stream.eol()) { var style = mode.token(stream, state); - callback(stream.current(), style, i, stream.start); + callback(stream.current(), style, i, stream.start, state); stream.start = stream.pos; } } diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js index a7da6d718f..7aafa2ad8f 100644 --- a/addon/runmode/runmode.js +++ b/addon/runmode/runmode.js @@ -49,7 +49,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var stream = new CodeMirror.StringStream(lines[i]); while (!stream.eol()) { var style = mode.token(stream, state); - callback(stream.current(), style, i, stream.start); + callback(stream.current(), style, i, stream.start, state); stream.start = stream.pos; } } diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js index ffdcc16a83..0f1088fa2e 100644 --- a/addon/runmode/runmode.node.js +++ b/addon/runmode/runmode.node.js @@ -96,7 +96,7 @@ exports.runMode = function(string, modespec, callback) { var stream = new exports.StringStream(lines[i]); while (!stream.eol()) { var style = mode.token(stream, state); - callback(stream.current(), style, i, stream.start); + callback(stream.current(), style, i, stream.start, state); stream.start = stream.pos; } } diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index 3da3f04e8f..c034d5865b 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -69,8 +69,8 @@ this.matches = function(reverse, pos) { var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln)); var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match)); - if (reverse ? offsetA >= pos.ch || offsetA != match.length - : offsetA <= pos.ch || offsetA != line.length - match.length) + if (reverse ? offsetA > pos.ch || offsetA != match.length + : offsetA < pos.ch || offsetA != line.length - match.length) return; for (;;) { if (reverse ? !ln : ln == doc.lineCount() - 1) return; diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 1be5ba7f5d..5084539993 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -24,6 +24,9 @@ // no tip should be shown. By default the docstring is shown. // * typeTip: Like completionTip, but for the tooltips shown for type // queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// // // It is possible to run the Tern server in a web worker by specifying // these additional options: @@ -102,8 +105,16 @@ rename: function(cm) { rename(this, cm); }, - request: function(cm, query, c) { - this.server.request(buildRequest(this, findDoc(this, cm.getDoc()), query), c); + request: function (cm, query, c) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query); + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); } }; @@ -233,12 +244,24 @@ closeArgHints(ts); if (cm.somethingSelected()) return; - var lex = cm.getTokenAt(cm.getCursor()).state.lexical; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; if (lex.info != "call") return; - var ch = lex.column, pos = lex.pos || 0; - for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) - if (cm.getLine(line).charAt(ch) == "(") {found = true; break;} + var ch, pos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } if (!found) return; var start = Pos(line, ch); diff --git a/bin/lint b/bin/lint index bbb85b6c26..4f70994c51 100755 --- a/bin/lint +++ b/bin/lint @@ -1,11 +1,12 @@ #!/usr/bin/env node -var lint = require("../test/lint/lint"); +var lint = require("../test/lint/lint"), + path = require("path"); if (process.argv.length > 2) { lint.checkDir(process.argv[2]); } else { - process.chdir(__dirname.slice(0, __dirname.lastIndexOf("/"))); + process.chdir(path.resolve(__dirname, "..")); lint.checkDir("lib"); lint.checkDir("mode"); lint.checkDir("addon"); diff --git a/bower.json b/bower.json index 451d654c0c..2aeffb8990 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "CodeMirror", - "version": "3.16.0", + "version": "3.17.0", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ "**/.*", diff --git a/demo/complete.html b/demo/complete.html index 56999b9cc9..e256a908b4 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -71,7 +71,7 @@ + + + @@ -82,6 +85,66 @@ ]

+

diff --git a/demo/marker.html b/demo/marker.html index 5cbd16257e..ac4dfda893 100644 --- a/demo/marker.html +++ b/demo/marker.html @@ -34,35 +34,19 @@ }); editor.on("gutterClick", function(cm, n) { var info = cm.lineInfo(n); - cm.setGutterMarker(n, "breakpoints", info.markers ? null : makeMarker()); + cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker()); }); function makeMarker() { var marker = document.createElement("div"); + marker.style.color = "#822"; marker.innerHTML = "●"; - marker.className = "breakpoint"; return marker; }

Click the line-number gutter to add or remove 'breakpoints'.

- + diff --git a/demo/markselection.html b/demo/markselection.html index 2e52af930f..454933264f 100644 --- a/demo/markselection.html +++ b/demo/markselection.html @@ -1,6 +1,6 @@ -CodeMirror: Match Highlighter Demo +CodeMirror: Match Selection Demo @@ -22,12 +22,12 @@
  • Code
    -

    Match Highlighter Demo

    +

    Match Selection Demo

    + + +

    MIME types defined: application/xml-dtd.

    +
    diff --git a/mode/fortran/fortran.js b/mode/fortran/fortran.js new file mode 100644 index 0000000000..83fd8fde85 --- /dev/null +++ b/mode/fortran/fortran.js @@ -0,0 +1,173 @@ +CodeMirror.defineMode("fortran", function() { + function words(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var keywords = words([ + "abstract", "accept", "allocatable", "allocate", + "array", "assign", "asynchronous", "backspace", + "bind", "block", "byte", "call", "case", + "class", "close", "common", "contains", + "continue", "cycle", "data", "deallocate", + "decode", "deferred", "dimension", "do", + "elemental", "else", "encode", "end", + "endif", "entry", "enumerator", "equivalence", + "exit", "external", "extrinsic", "final", + "forall", "format", "function", "generic", + "go", "goto", "if", "implicit", "import", "include", + "inquire", "intent", "interface", "intrinsic", + "module", "namelist", "non_intrinsic", + "non_overridable", "none", "nopass", + "nullify", "open", "optional", "options", + "parameter", "pass", "pause", "pointer", + "print", "private", "program", "protected", + "public", "pure", "read", "recursive", "result", + "return", "rewind", "save", "select", "sequence", + "stop", "subroutine", "target", "then", "to", "type", + "use", "value", "volatile", "where", "while", + "write"]); + var builtins = words(["abort", "abs", "access", "achar", "acos", + "adjustl", "adjustr", "aimag", "aint", "alarm", + "all", "allocated", "alog", "amax", "amin", + "amod", "and", "anint", "any", "asin", + "associated", "atan", "besj", "besjn", "besy", + "besyn", "bit_size", "btest", "cabs", "ccos", + "ceiling", "cexp", "char", "chdir", "chmod", + "clog", "cmplx", "command_argument_count", + "complex", "conjg", "cos", "cosh", "count", + "cpu_time", "cshift", "csin", "csqrt", "ctime", + "c_funloc", "c_loc", "c_associated", "c_null_ptr", + "c_null_funptr", "c_f_pointer", "c_null_char", + "c_alert", "c_backspace", "c_form_feed", + "c_new_line", "c_carriage_return", + "c_horizontal_tab", "c_vertical_tab", "dabs", + "dacos", "dasin", "datan", "date_and_time", + "dbesj", "dbesj", "dbesjn", "dbesy", "dbesy", + "dbesyn", "dble", "dcos", "dcosh", "ddim", "derf", + "derfc", "dexp", "digits", "dim", "dint", "dlog", + "dlog", "dmax", "dmin", "dmod", "dnint", + "dot_product", "dprod", "dsign", "dsinh", + "dsin", "dsqrt", "dtanh", "dtan", "dtime", + "eoshift", "epsilon", "erf", "erfc", "etime", + "exit", "exp", "exponent", "extends_type_of", + "fdate", "fget", "fgetc", "float", "floor", + "flush", "fnum", "fputc", "fput", "fraction", + "fseek", "fstat", "ftell", "gerror", "getarg", + "get_command", "get_command_argument", + "get_environment_variable", "getcwd", + "getenv", "getgid", "getlog", "getpid", + "getuid", "gmtime", "hostnm", "huge", "iabs", + "iachar", "iand", "iargc", "ibclr", "ibits", + "ibset", "ichar", "idate", "idim", "idint", + "idnint", "ieor", "ierrno", "ifix", "imag", + "imagpart", "index", "int", "ior", "irand", + "isatty", "ishft", "ishftc", "isign", + "iso_c_binding", "is_iostat_end", "is_iostat_eor", + "itime", "kill", "kind", "lbound", "len", "len_trim", + "lge", "lgt", "link", "lle", "llt", "lnblnk", "loc", + "log", "logical", "long", "lshift", "lstat", "ltime", + "matmul", "max", "maxexponent", "maxloc", "maxval", + "mclock", "merge", "move_alloc", "min", "minexponent", + "minloc", "minval", "mod", "modulo", "mvbits", + "nearest", "new_line", "nint", "not", "or", "pack", + "perror", "precision", "present", "product", "radix", + "rand", "random_number", "random_seed", "range", + "real", "realpart", "rename", "repeat", "reshape", + "rrspacing", "rshift", "same_type_as", "scale", + "scan", "second", "selected_int_kind", + "selected_real_kind", "set_exponent", "shape", + "short", "sign", "signal", "sinh", "sin", "sleep", + "sngl", "spacing", "spread", "sqrt", "srand", "stat", + "sum", "symlnk", "system", "system_clock", "tan", + "tanh", "time", "tiny", "transfer", "transpose", + "trim", "ttynam", "ubound", "umask", "unlink", + "unpack", "verify", "xor", "zabs", "zcos", "zexp", + "zlog", "zsin", "zsqrt"]); + + var dataTypes = words(["c_bool", "c_char", "c_double", "c_double_complex", + "c_float", "c_float_complex", "c_funptr", "c_int", + "c_int16_t", "c_int32_t", "c_int64_t", "c_int8_t", + "c_int_fast16_t", "c_int_fast32_t", "c_int_fast64_t", + "c_int_fast8_t", "c_int_least16_t", "c_int_least32_t", + "c_int_least64_t", "c_int_least8_t", "c_intmax_t", + "c_intptr_t", "c_long", "c_long_double", + "c_long_double_complex", "c_long_long", "c_ptr", + "c_short", "c_signed_char", "c_size_t", "character", + "complex", "double", "integer", "logical", "real"]); + var isOperatorChar = /[+\-*&=<>\/\:]/; + var litOperator = new RegExp("(\.and\.|\.or\.|\.eq\.|\.lt\.|\.le\.|\.gt\.|\.ge\.|\.ne\.|\.not\.|\.eqv\.|\.neqv\.)", "i"); + + function tokenBase(stream, state) { + + if (stream.match(litOperator)){ + return 'operator'; + } + + var ch = stream.next(); + if (ch == "!") { + stream.skipToEnd(); + return "comment"; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]\(\),]/.test(ch)) { + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var word = stream.current().toLowerCase(); + + if (keywords.hasOwnProperty(word)){ + return 'keyword'; + } + if (builtins.hasOwnProperty(word) || dataTypes.hasOwnProperty(word)) { + return 'builtin'; + } + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end || !escaped) state.tokenize = null; + return "string"; + }; + } + + // Interface + + return { + startState: function() { + return {tokenize: null}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-fortran", "fortran"); diff --git a/mode/fortran/index.html b/mode/fortran/index.html new file mode 100644 index 0000000000..efa55ec89a --- /dev/null +++ b/mode/fortran/index.html @@ -0,0 +1,81 @@ + + +CodeMirror: Fortran mode + + + + + + + + + +
    +

    Fortran mode

    + + +
    + + + +

    MIME types defined: text/x-Fortran.

    +
    diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index b18d5ced1a..59ca7f0baa 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("haskell", function() { +CodeMirror.defineMode("haskell", function(_config, modeConfig) { function switchState(source, setState, f) { setState(f); @@ -221,6 +221,10 @@ CodeMirror.defineMode("haskell", function() { "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip", "zip3", "zipWith", "zipWith3"); + var override = modeConfig.overrideKeywords; + if (override) for (var word in override) if (override.hasOwnProperty(word)) + wkw[word] = override[word]; + return wkw; })(); diff --git a/mode/index.html b/mode/index.html index e228c343ef..063e69b6c7 100644 --- a/mode/index.html +++ b/mode/index.html @@ -41,8 +41,10 @@
  • Cython
  • D
  • diff
  • +
  • DTD
  • ECL
  • Erlang
  • +
  • Fortran
  • Gas (AT&T-style assembly)
  • Go
  • Groovy
  • @@ -64,6 +66,7 @@
  • Nginx
  • NTriples
  • OCaml
  • +
  • Octave (MATLAB)
  • Pascal
  • Perl
  • PHP
  • @@ -91,6 +94,7 @@
  • Tcl
  • Tiddlywiki
  • Tiki wiki
  • +
  • TOML
  • Turtle
  • VB.NET
  • VBScript
  • diff --git a/mode/less/less.js b/mode/less/less.js index 09f510e032..8384b3cd76 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -1,7 +1,8 @@ /* LESS mode - http://www.lesscss.org/ Ported to CodeMirror by Peter Kroon - Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues GitHub: @peterkroon + Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues + GitHub: @peterkroon */ CodeMirror.defineMode("less", function(config) { @@ -17,68 +18,60 @@ CodeMirror.defineMode("less", function(config) { else if (ch == "/" && stream.eat("*")) { state.tokenize = tokenCComment; return tokenCComment(stream, state); - } - else if (ch == "<" && stream.eat("!")) { + } else if (ch == "<" && stream.eat("!")) { state.tokenize = tokenSGMLComment; return tokenSGMLComment(stream, state); - } - else if (ch == "=") ret(null, "compare"); + } else if (ch == "=") ret(null, "compare"); else if (ch == "|" && stream.eat("=")) return ret(null, "compare"); else if (ch == "\"" || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); - } - else if (ch == "/") { // e.g.: .png will not be parsed as a class + } else if (ch == "/") { // e.g.: .png will not be parsed as a class if(stream.eat("/")){ state.tokenize = tokenSComment; return tokenSComment(stream, state); - }else{ - if(type == "string" || type == "(")return ret("string", "string"); - if(state.stack[state.stack.length-1] != undefined)return ret(null, ch); + } else { + if(type == "string" || type == "(") return ret("string", "string"); + if(state.stack[state.stack.length-1] != undefined) return ret(null, ch); stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/); if( /\/|\)|#/.test(stream.peek() || (stream.eatSpace() && stream.peek() == ")")) || stream.eol() )return ret("string", "string"); // let url(/images/logo.png) without quotes return as string } - } - else if (ch == "!") { + } else if (ch == "!") { stream.match(/^\s*\w*/); return ret("keyword", "important"); - } - else if (/\d/.test(ch)) { + } else if (/\d/.test(ch)) { stream.eatWhile(/[\w.%]/); return ret("number", "unit"); - } - else if (/[,+<>*\/]/.test(ch)) { + } else if (/[,+<>*\/]/.test(ch)) { if(stream.peek() == "=" || type == "a")return ret("string", "string"); + if(ch === ",")return ret(null, ch); return ret(null, "select-op"); - } - else if (/[;{}:\[\]()~\|]/.test(ch)) { + } else if (/[;{}:\[\]()~\|]/.test(ch)) { if(ch == ":"){ stream.eatWhile(/[a-z\\\-]/); if( selectors.test(stream.current()) ){ return ret("tag", "tag"); - }else if(stream.peek() == ":"){//::-webkit-search-decoration + } else if(stream.peek() == ":"){//::-webkit-search-decoration stream.next(); stream.eatWhile(/[a-z\\\-]/); if(stream.current().match(/\:\:\-(o|ms|moz|webkit)\-/))return ret("string", "string"); if( selectors.test(stream.current().substring(1)) )return ret("tag", "tag"); return ret(null, ch); - }else{ + } else { return ret(null, ch); } - }else if(ch == "~"){ + } else if(ch == "~"){ if(type == "r")return ret("string", "string"); - }else{ + } else { return ret(null, ch); } - } - else if (ch == ".") { + } else if (ch == ".") { if(type == "(" || type == "string")return ret("string", "string"); // allow url(../image.png) stream.eatWhile(/[\a-zA-Z0-9\-_]/); if(stream.peek() == " ")stream.eatSpace(); if(stream.peek() == ")")return ret("number", "unit");//rgba(0,0,0,.25); return ret("tag", "tag"); - } - else if (ch == "#") { + } else if (ch == "#") { //we don't eat white-space, we want the hex color and or id only stream.eatWhile(/[A-Za-z0-9]/); //check if there is a proper hex color length e.g. #eee || #eeeEEE @@ -93,43 +86,41 @@ CodeMirror.defineMode("less", function(config) { //#time { color: #aaa } else if(stream.peek() == "}" )return ret("number", "unit"); //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa - else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag"); + else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag"); //when a hex value is on the end of a line, parse as id - else if(stream.eol())return ret("atom", "tag"); + else if(stream.eol())return ret("atom", "tag"); //default - else return ret("number", "unit"); - }else{//when not a valid hexvalue in the current stream e.g. #footer + else return ret("number", "unit"); + } else {//when not a valid hexvalue in the current stream e.g. #footer stream.eatWhile(/[\w\\\-]/); return ret("atom", "tag"); } - }else{//when not a valid hexvalue length + } else {//when not a valid hexvalue length stream.eatWhile(/[\w\\\-]/); return ret("atom", "tag"); } - } - else if (ch == "&") { + } else if (ch == "&") { stream.eatWhile(/[\w\-]/); return ret(null, ch); - } - else { + } else { stream.eatWhile(/[\w\\\-_%.{]/); if(type == "string"){ return ret("string", "string"); - }else if(stream.current().match(/(^http$|^https$)/) != null){ + } else if(stream.current().match(/(^http$|^https$)/) != null){ stream.eatWhile(/[\w\\\-_%.{:\/]/); return ret("string", "string"); - }else if(stream.peek() == "<" || stream.peek() == ">"){ + } else if(stream.peek() == "<" || stream.peek() == ">" || stream.peek() == "+"){ return ret("tag", "tag"); - }else if( /\(/.test(stream.peek()) ){ + } else if( /\(/.test(stream.peek()) ){ return ret(null, ch); - }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) + } else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) return ret("string", "string"); - }else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign + } else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign //commment out these 2 comment if you want the minus sign to be parsed as null -500px //stream.backUp(stream.current().length-1); - //return ret(null, ch); //console.log( stream.current() ); + //return ret(null, ch); return ret("number", "unit"); - }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){ + } else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){ stream.backUp(1); return ret("tag", "tag"); @@ -137,14 +128,15 @@ CodeMirror.defineMode("less", function(config) { stream.eatSpace(); if( /[{<>.a-zA-Z\/]/.test(stream.peek()) || stream.eol() )return ret("tag", "tag"); // e.g. button.icon-plus return ret("string", "string"); // let url(/images/logo.png) without quotes return as string - }else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){ + } else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1); return ret("tag", "tag"); - }else if(type == "compare" || type == "a" || type == "("){ + } else if(type == "compare" || type == "a" || type == "("){ return ret("string", "string"); - }else if(type == "|" || stream.current() == "-" || type == "["){ + } else if(type == "|" || stream.current() == "-" || type == "["){ + if(type == "|" )return ret("tag", "tag"); return ret(null, ch); - }else if(stream.peek() == ":") { + } else if(stream.peek() == ":") { stream.next(); var t_v = stream.peek() == ":" ? true : false; if(!t_v){ @@ -156,11 +148,14 @@ CodeMirror.defineMode("less", function(config) { stream.backUp(new_pos-(old_pos-1)); return ret("tag", "tag"); } else stream.backUp(new_pos-(old_pos-1)); - }else{ + } else { stream.backUp(1); } if(t_v)return ret("tag", "tag"); else return ret("variable", "variable"); - }else{ + } else if(state.stack[state.stack.length-1] === "font-family"){ + return ret(null, null); + } else { + if(state.stack[state.stack.length-1] === "{" || type === "select-op" || (state.stack[state.stack.length-1] === "rule" && type === ",") )return ret("tag", "tag"); return ret("variable", "variable"); } } @@ -238,12 +233,15 @@ CodeMirror.defineMode("less", function(config) { } else if (type == "}") state.stack.pop(); else if (type == "@media") state.stack.push("@media"); - else if (context == "{" && type != "comment") state.stack.push("rule"); + else if (stream.current() === "font-family") state.stack[state.stack.length-1] = "font-family"; + else if (context == "{" && type != "comment" && type !== "tag") state.stack.push("rule"); + else if (stream.peek() === ":" && stream.current().match(/@|#/) === null) style = type; return style; }, indent: function(state, textAfter) { var n = state.stack.length; + if (/^\}/.test(textAfter)) n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; return state.baseIndent + n * indentUnit; diff --git a/mode/meta.js b/mode/meta.js index 9c5d986f66..ce51c8ae19 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -13,12 +13,15 @@ CodeMirror.modeInfo = [ {name: 'CSS', mime: 'text/css', mode: 'css'}, {name: 'D', mime: 'text/x-d', mode: 'd'}, {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, + {name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'}, {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, + {name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'}, {name: 'Gas', mime: 'text/x-gas', mode: 'gas'}, {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'}, {name: 'GO', mime: 'text/x-go', mode: 'go'}, {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, + {name: 'HAML', mime: 'text/x-haml', mode: 'haml'}, {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'}, {name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'}, {name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'}, @@ -40,6 +43,7 @@ CodeMirror.modeInfo = [ {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'}, {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, + {name: 'Octave', mime: 'text/x-octave', mode: 'octave'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, {name: 'PHP', mime: 'text/x-php', mode: 'php'}, @@ -69,6 +73,8 @@ CodeMirror.modeInfo = [ {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'}, {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'}, {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, + {name: 'TOML', mime: 'text/x-toml', mode: 'toml'}, + {name: 'Turtle', mime: 'text/turtle', mode: 'turtle'}, {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'}, {name: 'Velocity', mime: 'text/velocity', mode: 'velocity'}, diff --git a/mode/octave/index.html b/mode/octave/index.html new file mode 100644 index 0000000000..bd5a523294 --- /dev/null +++ b/mode/octave/index.html @@ -0,0 +1,95 @@ + + +CodeMirror: Octave mode + + + + + + + + + +
    +

    Octave mode

    + +
    + + +

    MIME types defined: text/x-octave.

    +
    diff --git a/mode/octave/octave.js b/mode/octave/octave.js new file mode 100644 index 0000000000..23cd2fe222 --- /dev/null +++ b/mode/octave/octave.js @@ -0,0 +1,118 @@ +CodeMirror.defineMode("octave", function() { + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]"); + var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]'); + var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))"); + var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((>>=)|(<<=))"); + var expressionEnd = new RegExp("^[\\]\\)]"); + var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + + var builtins = wordRegexp([ + 'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos', + 'cosh', 'exp', 'log', 'prod', 'log10', 'max', 'min', 'sign', 'sin', 'sinh', + 'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones', + 'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov', + 'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot', + 'title', 'xlabel', 'ylabel', 'legend', 'text', 'meshgrid', 'mesh', 'num2str' + ]); + + var keywords = wordRegexp([ + 'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction', + 'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events', + 'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'disp', 'until', 'continue' + ]); + + + // tokenizers + function tokenTranspose(stream, state) { + if (!stream.sol() && stream.peek() === '\'') { + stream.next(); + state.tokenize = tokenBase; + return 'operator'; + } + state.tokenize = tokenBase; + return tokenBase(stream, state); + } + + + function tokenComment(stream, state) { + if (stream.match(/^.*%}/)) { + state.tokenize = tokenBase; + return 'comment'; + }; + stream.skipToEnd(); + return 'comment'; + } + + function tokenBase(stream, state) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match('%{')){ + state.tokenize = tokenComment; + stream.skipToEnd(); + return 'comment'; + } + + if (stream.match(/^(%)|(\.\.\.)/)){ + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) { + stream.tokenize = tokenBase; + return 'number'; }; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + } + if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; }; + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ; + if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ; + + // Handle words + if (stream.match(keywords)) { return 'keyword'; } ; + if (stream.match(builtins)) { return 'builtin'; } ; + if (stream.match(identifiers)) { return 'variable'; } ; + + if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; }; + if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; }; + + if (stream.match(expressionEnd)) { + state.tokenize = tokenTranspose; + return null; + }; + + + // Handle non-detected items + stream.next(); + return 'error'; + }; + + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + var style = state.tokenize(stream, state); + if (style === 'number' || style === 'variable'){ + state.tokenize = tokenTranspose; + } + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-octave", "octave"); diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 9016cc7aae..63ce3fa843 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -180,7 +180,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { if (!cx) return CodeMirror.Pass; if (cx.align) return cx.col + (textAfter.charAt(0) == cx.type ? 0 : 1); else return cx.indent + config.indentUnit; - } + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null }; }); @@ -262,7 +266,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), @@ -278,7 +282,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), @@ -309,8 +313,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), - functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), - builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), + builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2 abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), operatorChars: /^[*+\-%<>!=~]/, dateSQL: set("date time timestamp"), support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") diff --git a/mode/toml/index.html b/mode/toml/index.html new file mode 100644 index 0000000000..c59b4cc085 --- /dev/null +++ b/mode/toml/index.html @@ -0,0 +1,73 @@ + + +CodeMirror: TOML Mode + + + + + + + + + +
    +

    TOML Mode

    +
    + +

    The TOML Mode

    +

    Created by Forbes Lindesay.

    +

    MIME type defined: text/x-toml.

    +
    diff --git a/mode/toml/toml.js b/mode/toml/toml.js new file mode 100644 index 0000000000..1d163f13bf --- /dev/null +++ b/mode/toml/toml.js @@ -0,0 +1,71 @@ +CodeMirror.defineMode("toml", function () { + return { + startState: function () { + return { + inString: false, + stringType: "", + lhs: true, + inArray: 0 + }; + }, + token: function (stream, state) { + //check for state changes + if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (stream.sol() && state.inArray === 0) { + state.lhs = true; + } + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inArray && stream.peek() === ']') { + stream.next(); + state.inArray--; + return 'bracket'; + } else if (state.lhs && stream.peek() === '[' && stream.skipTo(']')) { + stream.next();//skip closing ] + return "atom"; + } else if (stream.peek() === "#") { + stream.skipToEnd(); + return "comment"; + } else if (stream.eatSpace()) { + return null; + } else if (state.lhs && stream.eatWhile(function (c) { return c != '=' && c != ' '; })) { + return "property"; + } else if (state.lhs && stream.peek() === "=") { + stream.next(); + state.lhs = false; + return null; + } else if (!state.lhs && stream.match(/^\d\d\d\d[\d\-\:\.T]*Z/)) { + return 'atom'; //date + } else if (!state.lhs && (stream.match('true') || stream.match('false'))) { + return 'atom'; + } else if (!state.lhs && stream.peek() === '[') { + state.inArray++; + stream.next(); + return 'bracket'; + } else if (!state.lhs && stream.match(/^\-?\d+(?:\.\d+)?/)) { + return 'number'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME('text/x-toml', 'toml'); diff --git a/package.json b/package.json index 3d436b0f78..f5c28e0c41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"3.16.0", + "version":"3.17.0", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", diff --git a/test/test.js b/test/test.js index 1c37b4dfe1..e5d9afdedd 100644 --- a/test/test.js +++ b/test/test.js @@ -1,5 +1,7 @@ var Pos = CodeMirror.Pos; +CodeMirror.defaults.rtlMoveVisually = true; + function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } @@ -529,10 +531,10 @@ testCM("multiBookmarkCursor", function(cm) { } var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left; add(true); - eq(base1, cm.cursorCoords(Pos(0, 1)).left); + is(Math.abs(base1 - cm.cursorCoords(Pos(0, 1)).left) < .1); while (m = ms.pop()) m.clear(); add(false); - eq(base4, cm.cursorCoords(Pos(0, 1)).left); + is(Math.abs(base4 - cm.cursorCoords(Pos(0, 1)).left) < .1); }, {value: "abcdefg"}); testCM("getAllMarks", function(cm) { @@ -1159,7 +1161,7 @@ testCM("rtlMovement", function(cm) { prevX = cursor.offsetLeft; } }); -}, {rtlMoveVisually: true}); +}); // Verify that updating a line clears its bidi ordering testCM("bidiUpdate", function(cm) { @@ -1340,6 +1342,7 @@ testCM("atomicMarker", function(cm) { eqPos(cm.getCursor(), Pos(8, 3)); m.clear(); m = atom(1, 1, 3, 8); + cm.setCursor(Pos(0, 0)); cm.setCursor(Pos(2, 0)); eqPos(cm.getCursor(), Pos(3, 8)); cm.execCommand("goCharLeft"); @@ -1538,3 +1541,22 @@ testCM("change_removedText", function(cm) { eq(removedText[0].join("\n"), "abc\nd"); eq(removedText[1].join("\n"), ""); }); + +testCM("lineStyleFromMode", function(cm) { + CodeMirror.defineMode("test_mode", function() { + return {token: function(stream) { + if (stream.match(/^\[[^\]]*\]/)) return "line-brackets"; + if (stream.match(/^\([^\]]*\)/)) return "line-background-parens"; + stream.match(/^\s+|^\S+/); + }}; + }); + cm.setOption("mode", "test_mode"); + var bracketElts = byClassName(cm.getWrapperElement(), "brackets"); + eq(bracketElts.length, 1); + eq(bracketElts[0].nodeName, "PRE"); + is(!/brackets.*brackets/.test(bracketElts[0].className)); + var parenElts = byClassName(cm.getWrapperElement(), "parens"); + eq(parenElts.length, 1); + eq(parenElts[0].nodeName, "DIV"); + is(!/parens.*parens/.test(parenElts[0].className)); +}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: nothing"}); diff --git a/theme/solarized.css b/theme/solarized.css index f6b2a3f277..1a87d2d801 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -99,36 +99,14 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png color: #586e75; } -.cm-s-solarized.cm-s-dark .CodeMirror-focused .CodeMirror-selected { - background: #386774; - color: inherit; -} - -.cm-s-solarized.cm-s-dark ::selection { - background: #386774; - color: inherit; -} - .cm-s-solarized.cm-s-dark .CodeMirror-selected { - background: #586e75; -} - -.cm-s-solarized.cm-s-light .CodeMirror-focused .CodeMirror-selected { - background: #eee8d5; - color: inherit; -} - -.cm-s-solarized.cm-s-light ::selection { - background: #eee8d5; - color: inherit; + background: #073642; } .cm-s-solarized.cm-s-light .CodeMirror-selected { - background: #93a1a1; + background: #eee8d5; } - - /* Editor styling */