diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js
index da89af58c9fd3edb3f83958ff147ecb51f2b83c1..2bbc6f2a387164330130fdd7f42ae91e9e2056dd 100644
--- a/addon/edit/closebrackets.js
+++ b/addon/edit/closebrackets.js
@@ -9,11 +9,11 @@
   else // Plain browser env
     mod(CodeMirror);
 })(function(CodeMirror) {
-  var DEFAULT_BRACKETS = "()[]{}''\"\"";
-  var BIND = DEFAULT_BRACKETS + "`";
-  var DEFAULT_TRIPLES = "'\"";
-  var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
-  var SPACE_CHAR_REGEX = /\s/;
+  var defaults = {
+    pairs: "()[]{}''\"\"",
+    triples: "",
+    explode: "[]{}"
+  };
 
   var Pos = CodeMirror.Pos;
 
@@ -22,39 +22,44 @@
       cm.removeKeyMap(keyMap);
       cm.state.closeBrackets = null;
     }
-    if (!val) return;
-    var config = cm.state.closeBrackets = {
-      pairs: DEFAULT_BRACKETS,
-      triples: DEFAULT_TRIPLES,
-      explode: DEFAULT_EXPLODE_ON_ENTER
-    };
-    if (typeof val == "string") {
-      config.pairs = val;
-    } else if (typeof val == "object") {
-      if (val.pairs != null) config.pairs = val.pairs;
-      if (val.triples != null) config.triples = val.triples;
-      if (val.explode != null) config.explode = val.explode;
+    if (val) {
+      cm.state.closeBrackets = val;
+      cm.addKeyMap(keyMap);
     }
-    cm.addKeyMap(keyMap);
   });
 
+  function getOption(conf, name) {
+    if (name == "pairs" && typeof conf == "string") return conf;
+    if (typeof conf == "object" && conf[name] != null) return conf[name];
+    return defaults[name];
+  }
+
+  var bind = defaults.pairs + "`";
   var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
-  for (var i = 0; i < BIND.length; i++)
-    keyMap["'" + BIND.charAt(i) + "'"] = handler(BIND.charAt(i));
+  for (var i = 0; i < bind.length; i++)
+    keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
 
   function handler(ch) {
     return function(cm) { return handleChar(cm, ch); };
   }
 
+  function getConfig(cm) {
+    var deflt = cm.state.closeBrackets;
+    if (!deflt) return null;
+    var mode = cm.getModeAt(cm.getCursor());
+    return mode.closeBrackets || deflt;
+  }
+
   function handleBackspace(cm) {
-    var data = cm.state.closeBrackets;
-    if (!data || cm.getOption("disableInput")) return CodeMirror.Pass;
+    var conf = getConfig(cm);
+    if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
 
+    var pairs = getOption(conf, "pairs");
     var ranges = cm.listSelections();
     for (var i = 0; i < ranges.length; i++) {
       if (!ranges[i].empty()) return CodeMirror.Pass;
       var around = charsAround(cm, ranges[i].head);
-      if (!around || data.pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
+      if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
     }
     for (var i = ranges.length - 1; i >= 0; i--) {
       var cur = ranges[i].head;
@@ -63,14 +68,15 @@
   }
 
   function handleEnter(cm) {
-    var data = cm.state.closeBrackets;
-    if (!data || !data.explode || cm.getOption("disableInput")) return CodeMirror.Pass;
+    var conf = getConfig(cm);
+    var explode = conf && getOption(conf, "explode");
+    if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
 
     var ranges = cm.listSelections();
     for (var i = 0; i < ranges.length; i++) {
       if (!ranges[i].empty()) return CodeMirror.Pass;
       var around = charsAround(cm, ranges[i].head);
-      if (!around || data.explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
+      if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
     }
     cm.operation(function() {
       cm.replaceSelection("\n\n", null);
@@ -84,19 +90,16 @@
     });
   }
 
-  function isClosingBracket(ch, pairs) {
-    var pos = pairs.lastIndexOf(ch);
-    return pos > -1 && pos % 2 == 1;
-  }
-
   function handleChar(cm, ch) {
-    var data = cm.state.closeBrackets;
-    if (!data || cm.getOption("disableInput")) return CodeMirror.Pass;
+    var conf = getConfig(cm);
+    if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
 
-    var pos = data.pairs.indexOf(ch);
+    var pairs = getOption(conf, "pairs");
+    var pos = pairs.indexOf(ch);
     if (pos == -1) return CodeMirror.Pass;
+    var triples = getOption(conf, "triples");
 
-    var identical = data.pairs.charAt(pos + 1) == ch;
+    var identical = pairs.charAt(pos + 1) == ch;
     var ranges = cm.listSelections();
     var opening = pos % 2 == 0;
 
@@ -107,11 +110,11 @@
       if (opening && !range.empty()) {
         curType = "surround";
       } else if ((identical || !opening) && next == ch) {
-        if (data.triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
+        if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
           curType = "skipThree";
         else
           curType = "skip";
-      } else if (identical && cur.ch > 1 && data.triples.indexOf(ch) >= 0 &&
+      } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
                  cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
                  (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
         curType = "addFour";
@@ -119,8 +122,8 @@
         if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
         else return CodeMirror.Pass;
       } else if (opening && (cm.getLine(cur.line).length == cur.ch ||
-                             isClosingBracket(next, data.pairs) ||
-                             SPACE_CHAR_REGEX.test(next))) {
+                             isClosingBracket(next, pairs) ||
+                             /\s/.test(next))) {
         curType = "both";
       } else {
         return CodeMirror.Pass;
@@ -129,8 +132,8 @@
       else if (type != curType) return CodeMirror.Pass;
     }
 
-    var left = pos % 2 ? data.pairs.charAt(pos - 1) : ch;
-    var right = pos % 2 ? ch : data.pairs.charAt(pos + 1);
+    var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
+    var right = pos % 2 ? ch : pairs.charAt(pos + 1);
     cm.operation(function() {
       if (type == "skip") {
         cm.execCommand("goCharRight");
@@ -152,6 +155,11 @@
     });
   }
 
+  function isClosingBracket(ch, pairs) {
+    var pos = pairs.lastIndexOf(ch);
+    return pos > -1 && pos % 2 == 1;
+  }
+
   function charsAround(cm, pos) {
     var str = cm.getRange(Pos(pos.line, pos.ch - 1),
                           Pos(pos.line, pos.ch + 1));
diff --git a/lib/codemirror.js b/lib/codemirror.js
index 6806c084c37d72d4edfc41b19c6051117df070fc..197c40df30dea82d31942bafc95614c2b7b266a9 100644
--- a/lib/codemirror.js
+++ b/lib/codemirror.js
@@ -4841,7 +4841,7 @@
 
     getHelpers: function(pos, type) {
       var found = [];
-      if (!helpers.hasOwnProperty(type)) return helpers;
+      if (!helpers.hasOwnProperty(type)) return found;
       var help = helpers[type], mode = this.getModeAt(pos);
       if (typeof mode[type] == "string") {
         if (help[mode[type]]) found.push(help[mode[type]]);
diff --git a/mode/clike/clike.js b/mode/clike/clike.js
index e2223ccd1533a85cb28162c55c9f65c17c4e615f..f996f019dcf0ed50c6d1fbcda5cbc7c279c571a9 100644
--- a/mode/clike/clike.js
+++ b/mode/clike/clike.js
@@ -403,7 +403,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
         stream.eatWhile(/[\w\$_\xa1-\uffff]/);
         return "atom";
       }
-    }
+    },
+    modeProps: {closeBrackets: {triples: '"'}}
   });
 
   def(["x-shader/x-vertex", "x-shader/x-fragment"], {
diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js
index c334de730077ab0f71415a3bf5d115bce701dbcb..d531022a2ebfea07f75ea881988fbf5f768c30cb 100644
--- a/mode/clojure/clojure.js
+++ b/mode/clojure/clojure.js
@@ -234,6 +234,7 @@ CodeMirror.defineMode("clojure", function (options) {
             return state.indentStack.indent;
         },
 
+        closeBrackets: {pairs: "()[]{}\"\""},
         lineComment: ";;"
     };
 });
diff --git a/mode/commonlisp/commonlisp.js b/mode/commonlisp/commonlisp.js
index 5f50b352de73c37c12fe667756e65b866ab0af00..fb1f99c631020cd3ab52260e81aa6d7084ad433b 100644
--- a/mode/commonlisp/commonlisp.js
+++ b/mode/commonlisp/commonlisp.js
@@ -111,6 +111,7 @@ CodeMirror.defineMode("commonlisp", function (config) {
       return typeof i == "number" ? i : state.ctx.start + 1;
     },
 
+    closeBrackets: {pairs: "()[]{}\"\""},
     lineComment: ";;",
     blockCommentStart: "#|",
     blockCommentEnd: "|#"
diff --git a/mode/groovy/groovy.js b/mode/groovy/groovy.js
index 89b8224cf5dff7b5674f9fe4892998d294269e14..e3a1db869b4969cd21f04104cec1b52f2e1dac02 100644
--- a/mode/groovy/groovy.js
+++ b/mode/groovy/groovy.js
@@ -217,6 +217,7 @@ CodeMirror.defineMode("groovy", function(config) {
     },
 
     electricChars: "{}",
+    closeBrackets: {triples: "'\""},
     fold: "brace"
   };
 });
diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js
index 3f05ac46c3326054c0f6cdcac851e0a06e388b54..ddaa01ef47e26968e55c4b6bb11d0e0a17d764dc 100644
--- a/mode/javascript/javascript.js
+++ b/mode/javascript/javascript.js
@@ -669,6 +669,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
     blockCommentEnd: jsonMode ? null : "*/",
     lineComment: jsonMode ? null : "//",
     fold: "brace",
+    closeBrackets: "()[]{}''\"\"``",
 
     helperType: jsonMode ? "json" : "javascript",
     jsonldMode: jsonldMode,
diff --git a/mode/kotlin/kotlin.js b/mode/kotlin/kotlin.js
index 73c84f6c4f8af5fb5c7ba6c89fc6eba7533fb9ac..1efec85dffc8cf6cb6e4e2b2c3192112315d64f8 100644
--- a/mode/kotlin/kotlin.js
+++ b/mode/kotlin/kotlin.js
@@ -271,6 +271,7 @@ CodeMirror.defineMode("kotlin", function (config, parserConfig) {
       else return ctx.indented + (closing ? 0 : config.indentUnit);
     },
 
+    closeBrackets: {triples: "'\""},
     electricChars: "{}"
   };
 });
diff --git a/mode/python/python.js b/mode/python/python.js
index 98c0409ae2e014b8df8c4c928fd31b8e27f0235e..979e84982294aff10478b5a490a53fc61d91514c 100644
--- a/mode/python/python.js
+++ b/mode/python/python.js
@@ -339,6 +339,7 @@
           return scope.offset;
       },
 
+      closeBrackets: {triples: "'\""},
       lineComment: "#",
       fold: "indent"
     };
diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js
index 979edc0963c430f6107d6eb29c30977d0adc66eb..22346459115d01de8adf4e6c84a3c706f2c63755 100644
--- a/mode/scheme/scheme.js
+++ b/mode/scheme/scheme.js
@@ -239,6 +239,7 @@ CodeMirror.defineMode("scheme", function () {
             return state.indentStack.indent;
         },
 
+        closeBrackets: {pairs: "()[]{}\"\""},
         lineComment: ";;"
     };
 });