diff --git a/AUTHORS b/AUTHORS
index 03b1ac5b0a..f64cb6d103 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -45,6 +45,7 @@ Andre von Houck
Andrey Fedorov
Andrey Klyuchnikov
Andrey Lushnikov
+Andrey Shchekin
Andy Joslin
Andy Kimball
Andy Li
@@ -75,9 +76,11 @@ benbro
Beni Cherniavsky-Paskin
Benjamin DeCoste
Ben Keen
+Ben Miller
Ben Mosher
Bernhard Sirlinger
Bert Chang
+Bharad
Billy Moon
binny
B Krishna Chaitanya
@@ -183,6 +186,7 @@ Gabriel Gheorghian
Gabriel Horner
Gabriel Nahmias
galambalazs
+Gary Sheng
Gautam Mehta
Gavin Douglas
gekkoe
@@ -199,6 +203,7 @@ Gordon Smith
Grant Skinner
greengiant
Gregory Koberger
+Grzegorz Mazur
Guillaume Massé
Guillaume Massé
guraga
@@ -230,6 +235,7 @@ Jakob Miland
Jakub Vrana
Jakub Vrána
James Campos
+James Howard
James Thorne
Jamie Hill
Jan Jongboom
@@ -238,6 +244,7 @@ Jan Keromnes
Jan Odvarko
Jan Schär
Jan T. Sott
+Jared Dean
Jared Forsyth
Jason
Jason Barnabe
@@ -256,6 +263,7 @@ Jim
JobJob
jochenberger
Jochen Berger
+joelpinheiro
Johan Ask
John Connor
John Engler
@@ -271,6 +279,7 @@ Jon Sangster
Joost-Wim Boekesteijn
Joseph Pecoraro
Josh Cohen
+Josh Soref
Joshua Newman
Josh Watzman
jots
@@ -297,6 +306,7 @@ Koh Zi Han, Cliff
komakino
Konstantin Lopuhin
koops
+Kris Ciccarello
ks-ifware
kubelsmieci
KwanEsq
@@ -314,6 +324,7 @@ LM
lochel
Lorenzo Stoakes
Luciano Longo
+Lu Fangjian
Luke Stagner
lynschinzer
M1cha
@@ -321,6 +332,7 @@ Madhura Jayaratne
Maksim Lin
Maksym Taran
Malay Majithia
+Manideep
Manuel Rego Casasnovas
Marat Dreizin
Marcel Gerber
@@ -475,6 +487,7 @@ Scott Aikin
Scott Goodhew
Sebastian Zaha
Sergey Goder
+Sergey Tselovalnikov
Se-Won Kim
shaund
shaun gilchrist
@@ -519,6 +532,7 @@ Thomas Schmid
Tim Alby
Tim Baumann
Timothy Farrell
+Timothy Gu
Timothy Hatcher
TobiasBg
Tomas-A
@@ -531,6 +545,7 @@ Triangle717
Tristan Tarrant
TSUYUSATO Kitsune
twifkak
+VapidWorx
Vestimir Markov
vf
Victor Bocharsky
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0a6ab57ff..d6e39cce9a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,33 @@
+## 5.14.0 (2016-04-20)
+
+### Bugfixes
+
+[`posFromIndex`](http://codemirror.net/doc/manual.html#posFromIndex) and [`indexFromPos`](http://codemirror.net/doc/manual.html#indexFromPos) now take [`lineSeparator`](http://codemirror.net/doc/manual.html#option_lineSeparator) into account.
+
+[vim bindings](http://codemirror.net/demo/vim.html): Only call `.save()` when it is actually available.
+
+[commend addon](http://codemirror.net/doc/manual.html#addon_comment): Be careful not to mangle multi-line strings.
+
+[Python mode](http://codemirror.net/mode/python/index.html): Improve distinguishing of decorators from `@` operators.
+
+[`findMarks`](http://codemirror.net/doc/manual.html#findMarks): No longer return marks that touch but don't overlap given range.
+
+### New features
+
+[vim bindings](http://codemirror.net/demo/vim.html): Add yank command.
+
+[match-highlighter addon](http://codemirror.net/doc/manual.html#addon_match-highlighter): Add `trim` option to disable ignoring of whitespace.
+
+[PowerShell mode](http://codemirror.net/mode/powershell/index.html): Added.
+
+[Yacas mode](http://codemirror.net/mode/yacas/index.html): Added.
+
+[Web IDL mode](http://codemirror.net/mode/webidl/index.html): Added.
+
+[SAS mode](http://codemirror.net/mode/sas/index.html): Added.
+
+[mbox mode](http://codemirror.net/mode/mbox/index.html): Added.
+
## 5.13.2 (2016-03-23)
### Bugfixes
diff --git a/addon/comment/comment.js b/addon/comment/comment.js
index 3aa468089e..2c4f975d08 100644
--- a/addon/comment/comment.js
+++ b/addon/comment/comment.js
@@ -44,9 +44,17 @@
}
});
+ // Rough heuristic to try and detect lines that are part of multi-line string
+ function probablyInsideString(cm, pos, line) {
+ return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line)
+ }
+
CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = self.getModeAt(from);
+ var firstLine = self.getLine(from.line);
+ if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
+
var commentString = options.lineComment || mode.lineComment;
if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) {
@@ -55,8 +63,7 @@
}
return;
}
- var firstLine = self.getLine(from.line);
- if (firstLine == null) return;
+
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line;
diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js
index 7661f6c2cd..f426b5c8ca 100644
--- a/addon/hint/show-hint.js
+++ b/addon/hint/show-hint.js
@@ -108,15 +108,11 @@
},
update: function(first) {
- if (this.tick == null) return;
- if (!this.options.hint.async) {
- this.finishUpdate(this.options.hint(this.cm, this.options), first);
- } else {
- var myTick = ++this.tick, self = this;
- this.options.hint(this.cm, function(data) {
- if (self.tick == myTick) self.finishUpdate(data, first);
- }, this.options);
- }
+ if (this.tick == null) return
+ var self = this, myTick = ++this.tick
+ fetchHints(this.options.hint, this.cm, this.options, function(data) {
+ if (self.tick == myTick) self.finishUpdate(data, first)
+ })
},
finishUpdate: function(data, first) {
@@ -362,40 +358,31 @@
return result
}
+ function fetchHints(hint, cm, options, callback) {
+ if (hint.async) {
+ hint(cm, callback, options)
+ } else {
+ var result = hint(cm, options)
+ if (result && result.then) result.then(callback)
+ else callback(result)
+ }
+ }
+
function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) {
- var async = false, resolved
- for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true
- if (async) {
- resolved = function(cm, callback, options) {
- var app = applicableHelpers(cm, helpers)
- function run(i, result) {
- if (i == app.length) return callback(null)
- var helper = app[i]
- if (helper.async) {
- helper(cm, function(result) {
- if (result) callback(result)
- else run(i + 1)
- }, options)
- } else {
- var result = helper(cm, options)
- if (result) callback(result)
- else run(i + 1)
- }
- }
- run(0)
- }
- resolved.async = true
- } else {
- resolved = function(cm, options) {
- var app = applicableHelpers(cm, helpers)
- for (var i = 0; i < app.length; i++) {
- var cur = app[i](cm, options)
- if (cur && cur.list.length) return cur
- }
+ var resolved = function(cm, callback, options) {
+ var app = applicableHelpers(cm, helpers);
+ function run(i) {
+ if (i == app.length) return callback(null)
+ fetchHints(app[i], cm, options, function(result) {
+ if (result && result.list.length > 0) callback(result)
+ else run(i + 1)
+ })
}
+ run(0)
}
+ resolved.async = true
resolved.supportsSelection = true
return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js
index 798fbb1f38..62c4f68d64 100644
--- a/addon/hint/sql-hint.js
+++ b/addon/hint/sql-hint.js
@@ -105,7 +105,7 @@
}
function nameCompletion(cur, token, result, editor) {
- // Try to complete table, colunm names and return start position of completion
+ // Try to complete table, column names and return start position of completion
var useBacktick = false;
var nameParts = [];
var start = token.start;
diff --git a/addon/lint/lint.js b/addon/lint/lint.js
index 01f322b5d5..e3a452766d 100644
--- a/addon/lint/lint.js
+++ b/addon/lint/lint.js
@@ -204,7 +204,8 @@
var annotations = [];
for (var i = 0; i < spans.length; ++i) {
- annotations.push(spans[i].__annotation);
+ var ann = spans[i].__annotation;
+ if (ann) annotations.push(ann);
}
if (annotations.length) popupTooltips(annotations, e);
}
diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js
index 8f02f01c87..2c2914a9d0 100644
--- a/addon/search/match-highlighter.js
+++ b/addon/search/match-highlighter.js
@@ -16,7 +16,7 @@
// highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before
-// highlighting the matches. If annotateScrollbar is enabled, the occurances
+// highlighting the matches. If annotateScrollbar is enabled, the occurences
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) {
@@ -29,24 +29,20 @@
})(function(CodeMirror) {
"use strict";
- var DEFAULT_MIN_CHARS = 2;
- var DEFAULT_TOKEN_STYLE = "matchhighlight";
- var DEFAULT_DELAY = 100;
- var DEFAULT_WORDS_ONLY = false;
+ var defaults = {
+ style: "matchhighlight",
+ minChars: 2,
+ delay: 100,
+ wordsOnly: false,
+ annotateScrollbar: false,
+ showToken: false,
+ trim: true
+ }
function State(options) {
- if (typeof options == "object") {
- this.minChars = options.minChars;
- this.style = options.style;
- this.showToken = options.showToken;
- this.delay = options.delay;
- this.wordsOnly = options.wordsOnly;
- this.annotateScrollbar = options.annotateScrollbar;
- }
- if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
- if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
- if (this.delay == null) this.delay = DEFAULT_DELAY;
- if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY;
+ this.options = {}
+ for (var name in defaults)
+ this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.overlay = this.timeout = null;
this.matchesonscroll = null;
}
@@ -68,13 +64,13 @@
function cursorActivity(cm) {
var state = cm.state.matchHighlighter;
clearTimeout(state.timeout);
- state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);
+ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
}
function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
- if (state.annotateScrollbar) {
+ if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, true,
{className: "CodeMirror-selection-highlight-scrollbar"});
@@ -86,7 +82,7 @@
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
- if (state.annotateScrollbar) {
+ if (state.matchesonscroll) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
}
@@ -97,21 +93,22 @@
cm.operation(function() {
var state = cm.state.matchHighlighter;
removeOverlay(cm);
- if (!cm.somethingSelected() && state.showToken) {
- var re = state.showToken === true ? /[\w$]/ : state.showToken;
+ if (!cm.somethingSelected() && state.options.showToken) {
+ var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end)
- addOverlay(cm, line.slice(start, end), re, state.style);
+ addOverlay(cm, line.slice(start, end), re, state.options.style);
return;
}
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return;
- if (state.wordsOnly && !isWord(cm, from, to)) return;
- var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, "");
- if (selection.length >= state.minChars)
- addOverlay(cm, selection, false, state.style);
+ if (state.options.wordsOnly && !isWord(cm, from, to)) return;
+ var selection = cm.getRange(from, to)
+ if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
+ if (selection.length >= state.options.minChars)
+ addOverlay(cm, selection, false, state.options.style);
});
}
diff --git a/addon/search/search.js b/addon/search/search.js
index 93e90b36ed..e6b4f85a05 100644
--- a/addon/search/search.js
+++ b/addon/search/search.js
@@ -121,7 +121,10 @@
persistentDialog(cm, queryDialog, q, function(query, event) {
CodeMirror.e_stop(event);
if (!query) return;
- if (query != state.queryText) startSearch(cm, state, query);
+ if (query != state.queryText) {
+ startSearch(cm, state, query);
+ state.posFrom = state.posTo = cm.getCursor();
+ }
if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) {
var dialog
@@ -193,7 +196,7 @@
replaceAll(cm, query, text)
} else {
clearSearch(cm);
- var cursor = getSearchCursor(cm, query, cm.getCursor());
+ var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
var advance = function() {
var start = cursor.from(), match;
if (!(match = cursor.findNext())) {
diff --git a/addon/tern/tern.js b/addon/tern/tern.js
index c345c49781..efdf2ed628 100644
--- a/addon/tern/tern.js
+++ b/addon/tern/tern.js
@@ -179,7 +179,7 @@
var data = findDoc(ts, doc);
var argHints = ts.cachedArgHints;
- if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0)
+ if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0)
ts.cachedArgHints = null;
var changed = data.changed;
@@ -306,7 +306,7 @@
ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
if (error || !data.type || !(/^fn\(/).test(data.type)) return;
ts.cachedArgHints = {
- start: pos,
+ start: start,
type: parseFnType(data.type),
name: data.exprName || data.name || "fn",
guess: data.guess,
diff --git a/bin/compress b/bin/compress
index 809fbe83d4..d358f9c3a0 100755
--- a/bin/compress
+++ b/bin/compress
@@ -18,7 +18,7 @@
// Script files are specified without .js ending. Prefixing them with
// their full (local) path is optional. So you may say lib/codemirror
// or mode/xml/xml to be more precise. In fact, even the .js suffix
-// may be speficied, if wanted.
+// may be specified, if wanted.
"use strict";
@@ -68,7 +68,7 @@ walk("mode/");
if (!local && !blob) help(false);
if (files.length) {
- console.log("Some speficied files were not found: " +
+ console.log("Some specified files were not found: " +
files.map(function(a){return a.name;}).join(", "));
process.exit(1);
}
diff --git a/demo/complete.html b/demo/complete.html
index cdf49dbeb9..18e17c8126 100644
--- a/demo/complete.html
+++ b/demo/complete.html
@@ -10,6 +10,7 @@
+
CodeMirror

@@ -69,11 +70,57 @@
Autocomplete Demo
and
javascript-hint
addons.
-
-
+
+
+
+
+
diff --git a/doc/compress.html b/doc/compress.html
index 47d689429f..1e507c6c7a 100644
--- a/doc/compress.html
+++ b/doc/compress.html
@@ -36,6 +36,7 @@
Script compression helper
Version:
- Get the current version:
5.13.
+ Get the current version:
5.13.2.
You can see the
code or
read the
release notes.
There is a
minification helper.
@@ -106,7 +106,7 @@
This is CodeMirror
maintainers need to subsist.
Current funding status =

You can help
per month or
-
once.
+
once.
+
+
+
+
+
+
+ PowerShell mode
+
+
+
+
+ MIME types defined: application/x-powershell.
+
+
+