browser/devtools/sourceeditor/codemirror/closebrackets.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 (function(mod) {
michael@0 2 if (typeof exports == "object" && typeof module == "object") // CommonJS
michael@0 3 mod(require("../../lib/codemirror"));
michael@0 4 else if (typeof define == "function" && define.amd) // AMD
michael@0 5 define(["../../lib/codemirror"], mod);
michael@0 6 else // Plain browser env
michael@0 7 mod(CodeMirror);
michael@0 8 })(function(CodeMirror) {
michael@0 9 var DEFAULT_BRACKETS = "()[]{}''\"\"";
michael@0 10 var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
michael@0 11 var SPACE_CHAR_REGEX = /\s/;
michael@0 12
michael@0 13 CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
michael@0 14 if (old != CodeMirror.Init && old)
michael@0 15 cm.removeKeyMap("autoCloseBrackets");
michael@0 16 if (!val) return;
michael@0 17 var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
michael@0 18 if (typeof val == "string") pairs = val;
michael@0 19 else if (typeof val == "object") {
michael@0 20 if (val.pairs != null) pairs = val.pairs;
michael@0 21 if (val.explode != null) explode = val.explode;
michael@0 22 }
michael@0 23 var map = buildKeymap(pairs);
michael@0 24 if (explode) map.Enter = buildExplodeHandler(explode);
michael@0 25 cm.addKeyMap(map);
michael@0 26 });
michael@0 27
michael@0 28 function charsAround(cm, pos) {
michael@0 29 var str = cm.getRange(CodeMirror.Pos(pos.line, pos.ch - 1),
michael@0 30 CodeMirror.Pos(pos.line, pos.ch + 1));
michael@0 31 return str.length == 2 ? str : null;
michael@0 32 }
michael@0 33
michael@0 34 function buildKeymap(pairs) {
michael@0 35 var map = {
michael@0 36 name : "autoCloseBrackets",
michael@0 37 Backspace: function(cm) {
michael@0 38 if (cm.getOption("disableInput")) return CodeMirror.Pass;
michael@0 39 var ranges = cm.listSelections();
michael@0 40 for (var i = 0; i < ranges.length; i++) {
michael@0 41 if (!ranges[i].empty()) return CodeMirror.Pass;
michael@0 42 var around = charsAround(cm, ranges[i].head);
michael@0 43 if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
michael@0 44 }
michael@0 45 for (var i = ranges.length - 1; i >= 0; i--) {
michael@0 46 var cur = ranges[i].head;
michael@0 47 cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
michael@0 48 }
michael@0 49 }
michael@0 50 };
michael@0 51 var closingBrackets = "";
michael@0 52 for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
michael@0 53 if (left != right) closingBrackets += right;
michael@0 54 map["'" + left + "'"] = function(cm) {
michael@0 55 if (cm.getOption("disableInput")) return CodeMirror.Pass;
michael@0 56 var ranges = cm.listSelections(), type, next;
michael@0 57 for (var i = 0; i < ranges.length; i++) {
michael@0 58 var range = ranges[i], cur = range.head, curType;
michael@0 59 if (left == "'" && cm.getTokenTypeAt(cur) == "comment")
michael@0 60 return CodeMirror.Pass;
michael@0 61 var next = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1));
michael@0 62 if (!range.empty())
michael@0 63 curType = "surround";
michael@0 64 else if (left == right && next == right)
michael@0 65 curType = "skip";
michael@0 66 else if (left == right && CodeMirror.isWordChar(next))
michael@0 67 return CodeMirror.Pass;
michael@0 68 else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) >= 0 || SPACE_CHAR_REGEX.test(next))
michael@0 69 curType = "both";
michael@0 70 else
michael@0 71 return CodeMirror.Pass;
michael@0 72 if (!type) type = curType;
michael@0 73 else if (type != curType) return CodeMirror.Pass;
michael@0 74 }
michael@0 75
michael@0 76 if (type == "skip") {
michael@0 77 cm.execCommand("goCharRight");
michael@0 78 } else if (type == "surround") {
michael@0 79 var sels = cm.getSelections();
michael@0 80 for (var i = 0; i < sels.length; i++)
michael@0 81 sels[i] = left + sels[i] + right;
michael@0 82 cm.replaceSelections(sels, "around");
michael@0 83 } else if (type == "both") {
michael@0 84 cm.replaceSelection(left + right, null);
michael@0 85 cm.execCommand("goCharLeft");
michael@0 86 }
michael@0 87 };
michael@0 88 if (left != right) map["'" + right + "'"] = function(cm) {
michael@0 89 var ranges = cm.listSelections();
michael@0 90 for (var i = 0; i < ranges.length; i++) {
michael@0 91 var range = ranges[i];
michael@0 92 if (!range.empty() ||
michael@0 93 cm.getRange(range.head, CodeMirror.Pos(range.head.line, range.head.ch + 1)) != right)
michael@0 94 return CodeMirror.Pass;
michael@0 95 }
michael@0 96 cm.execCommand("goCharRight");
michael@0 97 };
michael@0 98 })(pairs.charAt(i), pairs.charAt(i + 1));
michael@0 99 return map;
michael@0 100 }
michael@0 101
michael@0 102 function buildExplodeHandler(pairs) {
michael@0 103 return function(cm) {
michael@0 104 if (cm.getOption("disableInput")) return CodeMirror.Pass;
michael@0 105 var ranges = cm.listSelections();
michael@0 106 for (var i = 0; i < ranges.length; i++) {
michael@0 107 if (!ranges[i].empty()) return CodeMirror.Pass;
michael@0 108 var around = charsAround(cm, ranges[i].head);
michael@0 109 if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
michael@0 110 }
michael@0 111 cm.operation(function() {
michael@0 112 cm.replaceSelection("\n\n", null);
michael@0 113 cm.execCommand("goCharLeft");
michael@0 114 ranges = cm.listSelections();
michael@0 115 for (var i = 0; i < ranges.length; i++) {
michael@0 116 var line = ranges[i].head.line;
michael@0 117 cm.indentLine(line, null, true);
michael@0 118 cm.indentLine(line + 1, null, true);
michael@0 119 }
michael@0 120 });
michael@0 121 };
michael@0 122 }
michael@0 123 });

mercurial