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" : "") + "" + tagName + ">",
- {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" : "") + "" + tagName + ">",
+ {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