From 40c6eb2c06b34f65a74d59ef9687251952858bab Mon Sep 17 00:00:00 2001
From: Kris Kowal
Date: Fri, 6 Jul 2012 12:47:27 -0700
Subject: Normalize HTML doctype
---
imports/codemirror/mode/xquery/test/index.html | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'imports/codemirror')
diff --git a/imports/codemirror/mode/xquery/test/index.html b/imports/codemirror/mode/xquery/test/index.html
index ba82e54f..09238a19 100644
--- a/imports/codemirror/mode/xquery/test/index.html
+++ b/imports/codemirror/mode/xquery/test/index.html
@@ -1,5 +1,4 @@
-
+
--
cgit v1.2.3
From 0e04fff0ea80fa5cbe96b8354db38bd334aea83a Mon Sep 17 00:00:00 2001
From: Ananya Sen
Date: Mon, 16 Jul 2012 16:04:05 -0700
Subject: upgrade to codemirror 2.3
Signed-off-by: Ananya Sen
Conflicts:
js/code-editor/codemirror-ninja/theme/lesser-dark-ninja.css
Signed-off-by: Ananya Sen
---
imports/codemirror/LICENSE | 2 +-
imports/codemirror/keymap/emacs.js | 4 +-
imports/codemirror/keymap/vim.js | 927 +++++++++++++++------
imports/codemirror/lib/codemirror.css | 64 +-
imports/codemirror/lib/codemirror.js | 619 +++++++++-----
imports/codemirror/lib/util/closetag.js | 28 -
imports/codemirror/lib/util/foldcode.js | 36 +-
imports/codemirror/lib/util/formatting.js | 9 +-
imports/codemirror/lib/util/loadmode.js | 51 ++
imports/codemirror/lib/util/match-highlighter.js | 2 +-
imports/codemirror/lib/util/multiplex.js | 72 ++
imports/codemirror/lib/util/overlay.js | 5 +-
imports/codemirror/lib/util/pig-hint.js | 123 +++
imports/codemirror/lib/util/search.js | 32 +-
imports/codemirror/lib/util/searchcursor.js | 2 +-
imports/codemirror/mode/clike/clike.js | 39 +-
imports/codemirror/mode/clike/scala.html | 765 +++++++++++++++++
.../codemirror/mode/coffeescript/coffeescript.js | 6 +
imports/codemirror/mode/coffeescript/index.html | 6 +
imports/codemirror/mode/diff/diff.css | 3 -
imports/codemirror/mode/diff/diff.js | 29 +-
imports/codemirror/mode/diff/index.html | 13 +-
imports/codemirror/mode/ecl/ecl.js | 2 +-
imports/codemirror/mode/erlang/erlang.js | 251 ++++++
imports/codemirror/mode/erlang/index.html | 61 ++
imports/codemirror/mode/gfm/gfm.js | 42 +-
.../codemirror/mode/htmlembedded/htmlembedded.js | 2 +-
imports/codemirror/mode/htmlmixed/htmlmixed.js | 4 +-
imports/codemirror/mode/javascript/javascript.js | 9 +-
imports/codemirror/mode/less/index.html | 25 +-
imports/codemirror/mode/less/less.js | 42 +-
imports/codemirror/mode/markdown/markdown.js | 2 +-
imports/codemirror/mode/php/php.js | 2 +-
imports/codemirror/mode/pig/index.html | 42 +
imports/codemirror/mode/pig/pig.js | 172 ++++
imports/codemirror/mode/python/python.js | 30 +-
imports/codemirror/mode/rst/rst.js | 2 +-
imports/codemirror/mode/ruby/ruby.js | 11 +-
imports/codemirror/mode/scheme/scheme.js | 120 ++-
imports/codemirror/mode/shell/index.html | 50 ++
imports/codemirror/mode/shell/shell.js | 103 +++
imports/codemirror/mode/stex/stex.js | 10 +-
imports/codemirror/mode/stex/test.html | 12 +
imports/codemirror/mode/tiddlywiki/tiddlywiki.css | 35 +-
imports/codemirror/mode/tiddlywiki/tiddlywiki.js | 28 +-
imports/codemirror/mode/tiki/index.html | 82 ++
imports/codemirror/mode/tiki/tiki.css | 26 +
imports/codemirror/mode/tiki/tiki.js | 316 +++++++
imports/codemirror/mode/xml/xml.js | 69 +-
imports/codemirror/mode/xmlpure/index.html | 58 --
imports/codemirror/mode/xmlpure/xmlpure.js | 490 -----------
imports/codemirror/theme/ambiance.css | 81 ++
imports/codemirror/theme/blackboard.css | 25 +
imports/codemirror/theme/erlang-dark.css | 21 +
imports/codemirror/theme/lesser-dark.css | 7 +-
imports/codemirror/theme/night.css | 2 +-
imports/codemirror/theme/vibrant-ink.css | 27 +
imports/codemirror/version.txt | 2 +-
58 files changed, 3858 insertions(+), 1242 deletions(-)
create mode 100644 imports/codemirror/lib/util/loadmode.js
create mode 100644 imports/codemirror/lib/util/multiplex.js
create mode 100644 imports/codemirror/lib/util/pig-hint.js
create mode 100644 imports/codemirror/mode/clike/scala.html
delete mode 100644 imports/codemirror/mode/diff/diff.css
create mode 100644 imports/codemirror/mode/erlang/erlang.js
create mode 100644 imports/codemirror/mode/erlang/index.html
create mode 100644 imports/codemirror/mode/pig/index.html
create mode 100644 imports/codemirror/mode/pig/pig.js
create mode 100644 imports/codemirror/mode/shell/index.html
create mode 100644 imports/codemirror/mode/shell/shell.js
create mode 100644 imports/codemirror/mode/tiki/index.html
create mode 100644 imports/codemirror/mode/tiki/tiki.css
create mode 100644 imports/codemirror/mode/tiki/tiki.js
delete mode 100644 imports/codemirror/mode/xmlpure/index.html
delete mode 100644 imports/codemirror/mode/xmlpure/xmlpure.js
create mode 100644 imports/codemirror/theme/ambiance.css
create mode 100644 imports/codemirror/theme/blackboard.css
create mode 100644 imports/codemirror/theme/erlang-dark.css
create mode 100644 imports/codemirror/theme/vibrant-ink.css
(limited to 'imports/codemirror')
diff --git a/imports/codemirror/LICENSE b/imports/codemirror/LICENSE
index f62410e6..3916e96b 100644
--- a/imports/codemirror/LICENSE
+++ b/imports/codemirror/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2011 by Marijn Haverbeke
+Copyright (C) 2012 by Marijn Haverbeke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/imports/codemirror/keymap/emacs.js b/imports/codemirror/keymap/emacs.js
index 8fd3564e..2a57e2ff 100644
--- a/imports/codemirror/keymap/emacs.js
+++ b/imports/codemirror/keymap/emacs.js
@@ -18,12 +18,12 @@
"Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
"Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
- "Ctrl-Z": "undo", "Cmd-Z": "undo",
+ "Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete",
fallthrough: ["basic", "emacsy"]
};
CodeMirror.keyMap["emacs-Ctrl-X"] = {
"Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
- auto: "emacs", catchall: function(cm) {/*ignore*/}
+ auto: "emacs", nofallthrough: true
};
})();
diff --git a/imports/codemirror/keymap/vim.js b/imports/codemirror/keymap/vim.js
index f8fa5e07..2aa6e0f7 100644
--- a/imports/codemirror/keymap/vim.js
+++ b/imports/codemirror/keymap/vim.js
@@ -1,21 +1,96 @@
+// Supported keybindings:
+//
+// Cursor movement:
+// h, j, k, l
+// e, E, w, W, b, B
+// Ctrl-f, Ctrl-b
+// Ctrl-n, Ctrl-p
+// $, ^, 0
+// G
+// ge, gE
+// gg
+// f, F, t, T
+// Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
+// /, ?, n, N TODO (does not work)
+// #, * TODO
+//
+// Entering insert mode:
+// i, I, a, A, o, O
+// s
+// ce, cb (without support for number of actions like c3e - TODO)
+// cc
+// S, C TODO
+// cf, cF, ct, cT
+//
+// Deleting text:
+// x, X
+// J
+// dd, D
+// de, db (without support for number of actions like d3e - TODO)
+// df, dF, dt, dT
+//
+// Yanking and pasting:
+// yy, Y
+// p, P
+// p' TODO - test
+// y' TODO - test
+// m TODO - test
+//
+// Changing text in place:
+// ~
+// r
+//
+// Visual mode:
+// v, V TODO
+//
+// Misc:
+// . TODO
+//
+
(function() {
var count = "";
var sdir = "f";
var buf = "";
var yank = 0;
var mark = [];
+ var reptTimes = 0;
function emptyBuffer() { buf = ""; }
- function pushInBuffer(str) { buf += str; };
- function pushCountDigit(digit) { return function(cm) {count += digit;} }
- function popCount() { var i = parseInt(count); count = ""; return i || 1; }
+ function pushInBuffer(str) { buf += str; }
+ function pushCountDigit(digit) { return function(cm) {count += digit;}; }
+ function popCount() { var i = parseInt(count, 10); count = ""; return i || 1; }
+ function iterTimes(func) {
+ for (var i = 0, c = popCount(); i < c; ++i) func(i, i == c - 1);
+ }
function countTimes(func) {
if (typeof func == "string") func = CodeMirror.commands[func];
- return function(cm) { for (var i = 0, c = popCount(); i < c; ++i) func(cm); }
+ return function(cm) { iterTimes(function () { func(cm); }); };
}
function iterObj(o, f) {
for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
}
+ function iterList(l, f) {
+ for (var i in l) f(l[i]);
+ }
+ function toLetter(ch) {
+ // T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
+ if (ch.slice(0, 6) == "Shift-") {
+ return ch.slice(0, 1);
+ } else {
+ if (ch == "Space") return " ";
+ if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
+ return ch.toLowerCase();
+ }
+ }
+ var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
+ function toCombo(ch) {
+ // t -> T, T -> Shift-T, * -> '*', " " -> "Space"
+ if (ch == " ") return "Space";
+ var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
+ if (specialIdx != -1) return "'" + ch + "'";
+ if (ch.toLowerCase() == ch) return ch.toUpperCase();
+ return "Shift-" + ch.toUpperCase();
+ }
var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
function findWord(line, pos, dir, regexps) {
@@ -37,62 +112,172 @@
}
return {from: Math.min(start, end), to: Math.max(start, end)};
}
- function moveToWord(cm, regexps, dir, where) {
- var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line), word;
- while (true) {
- word = findWord(line, ch, dir, regexps);
- ch = word[where == "end" ? "to" : "from"];
- if (ch == cur.ch && word.from != word.to) ch = word[dir < 0 ? "from" : "to"];
- else break;
+ function moveToWord(cm, regexps, dir, times, where) {
+ var cur = cm.getCursor();
+
+ for (var i = 0; i < times; i++) {
+ var line = cm.getLine(cur.line), startCh = cur.ch, word;
+ while (true) {
+ // If we're at start/end of line, start on prev/next respectivly
+ if (cur.ch == line.length && dir > 0) {
+ cur.line++;
+ cur.ch = 0;
+ line = cm.getLine(cur.line);
+ } else if (cur.ch == 0 && dir < 0) {
+ cur.line--;
+ cur.ch = line.length;
+ line = cm.getLine(cur.line);
+ }
+ if (!line) break;
+
+ // On to the actual searching
+ word = findWord(line, cur.ch, dir, regexps);
+ cur.ch = word[where == "end" ? "to" : "from"];
+ if (startCh == cur.ch && word.from != word.to) cur.ch = word[dir < 0 ? "from" : "to"];
+ else break;
+ }
}
- cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true);
+ return cur;
}
function joinLineNext(cm) {
var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
- CodeMirror.commands.goLineEnd(cm);
+ CodeMirror.commands.goLineEnd(cm);
if (cur.line != cm.lineCount()) {
CodeMirror.commands.goLineEnd(cm);
cm.replaceSelection(" ", "end");
CodeMirror.commands.delCharRight(cm);
- }
- }
- function editCursor(mode) {
- if (mode == "vim-insert") {
- // put in your cursor css changing code
- } else if (mode == "vim") {
- // put in your cursor css changing code
}
}
- function delTillMark(cm, cHar) {
- var i = mark[cHar], l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
+ function delTillMark(cm, cHar) {
+ var i = mark[cHar];
+ if (i === undefined) {
+ // console.log("Mark not set"); // TODO - show in status bar
+ return;
+ }
+ var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
cm.setCursor(start);
for (var c = start; c <= end; c++) {
- pushInBuffer("\n"+cm.getLine(start));
+ pushInBuffer("\n"+cm.getLine(start));
cm.removeLine(start);
}
}
- function yankTillMark(cm, cHar) {
- var i = mark[cHar], l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
+ function yankTillMark(cm, cHar) {
+ var i = mark[cHar];
+ if (i === undefined) {
+ // console.log("Mark not set"); // TODO - show in status bar
+ return;
+ }
+ var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
for (var c = start; c <= end; c++) {
pushInBuffer("\n"+cm.getLine(c));
}
cm.setCursor(start);
}
+ function goLineStartText(cm) {
+ // Go to the start of the line where the text begins, or the end for whitespace-only lines
+ var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
+ cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
+ }
+ function charIdxInLine(cm, cHar, motion_options) {
+ // Search for cHar in line.
+ // motion_options: {forward, inclusive}
+ // If inclusive = true, include it too.
+ // If forward = true, search forward, else search backwards.
+ // If char is not found on this line, do nothing
+ var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
+ var ch = toLetter(cHar), mo = motion_options;
+ if (mo.forward) {
+ idx = line.indexOf(ch, cur.ch + 1);
+ if (idx != -1 && mo.inclusive) idx += 1;
+ } else {
+ idx = line.lastIndexOf(ch, cur.ch);
+ if (idx != -1 && !mo.inclusive) idx += 1;
+ }
+ return idx;
+ }
+
+ function moveTillChar(cm, cHar, motion_options) {
+ // Move to cHar in line, as found by charIdxInLine.
+ var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
+ if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
+ }
+
+ function delTillChar(cm, cHar, motion_options) {
+ // delete text in this line, untill cHar is met,
+ // as found by charIdxInLine.
+ // If char is not found on this line, do nothing
+ var idx = charIdxInLine(cm, cHar, motion_options);
+ var cur = cm.getCursor();
+ if (idx !== -1) {
+ if (motion_options.forward) {
+ cm.replaceRange("", {line: cur.line, ch: cur.ch}, {line: cur.line, ch: idx});
+ } else {
+ cm.replaceRange("", {line: cur.line, ch: idx}, {line: cur.line, ch: cur.ch});
+ }
+ }
+ }
+
+ function enterInsertMode(cm) {
+ // enter insert mode: switch mode and cursor
+ popCount();
+ cm.setOption("keyMap", "vim-insert");
+ }
+
+ // main keymap
var map = CodeMirror.keyMap.vim = {
- "0": function(cm) {count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);},
- "A": function(cm) {popCount(); cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "Shift-A": function(cm) {popCount(); CodeMirror.commands.goLineEnd(cm); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "I": function(cm) {popCount(); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "Shift-I": function(cm) {popCount(); CodeMirror.commands.goLineStartSmart(cm); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "O": function(cm) {popCount(); CodeMirror.commands.goLineEnd(cm); cm.replaceSelection("\n", "end"); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "Shift-O": function(cm) {popCount(); CodeMirror.commands.goLineStart(cm); cm.replaceSelection("\n", "start"); cm.setOption("keyMap", "vim-insert"); editCursor("vim-insert");},
- "G": function(cm) {cm.setOption("keyMap", "vim-prefix-g");},
- "D": function(cm) {cm.setOption("keyMap", "vim-prefix-d"); emptyBuffer();},
+ // Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
+ "'|'": function(cm) {
+ cm.setCursor(cm.getCursor().line, popCount() - 1, true);
+ },
+ "A": function(cm) {
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
+ enterInsertMode(cm);
+ },
+ "Shift-A": function(cm) { CodeMirror.commands.goLineEnd(cm); enterInsertMode(cm);},
+ "I": function(cm) { enterInsertMode(cm);},
+ "Shift-I": function(cm) { goLineStartText(cm); enterInsertMode(cm);},
+ "O": function(cm) {
+ CodeMirror.commands.goLineEnd(cm);
+ CodeMirror.commands.newlineAndIndent(cm);
+ enterInsertMode(cm);
+ },
+ "Shift-O": function(cm) {
+ CodeMirror.commands.goLineStart(cm);
+ cm.replaceSelection("\n", "start");
+ cm.indentLine(cm.getCursor().line);
+ enterInsertMode(cm);
+ },
+ "G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
+ "Shift-D": function(cm) {
+ // commented out verions works, but I left original, cause maybe
+ // I don't know vim enouth to see what it does
+ /* var cur = cm.getCursor();
+ var f = {line: cur.line, ch: cur.ch}, t = {line: cur.line};
+ pushInBuffer(cm.getRange(f, t));
+ */
+ emptyBuffer();
+ mark["Shift-D"] = cm.getCursor(false).line;
+ cm.setCursor(cm.getCursor(true).line);
+ delTillMark(cm,"Shift-D"); mark = [];
+ },
+
+ "S": function (cm) {
+ countTimes(function (_cm) {
+ CodeMirror.commands.delCharRight(_cm);
+ })(cm);
+ enterInsertMode(cm);
+ },
"M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = [];},
"Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer(); yank = 0;},
- "/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f"},
- "Shift-/": function(cm) {
+ "Shift-Y": function(cm) {
+ emptyBuffer();
+ mark["Shift-D"] = cm.getCursor(false).line;
+ cm.setCursor(cm.getCursor(true).line);
+ yankTillMark(cm,"Shift-D"); mark = [];
+ },
+ "/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
+ "'?'": function(cm) {
var f = CodeMirror.commands.find;
if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; }
},
@@ -104,244 +289,478 @@
var fn = CodeMirror.commands.findNext;
if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
},
- "Shift-G": function(cm) {count == "" ? cm.setCursor(cm.lineCount()) : cm.setCursor(parseInt(count)-1); popCount(); CodeMirror.commands.goLineStart(cm);},
- catchall: function(cm) {/*ignore*/}
+ "Shift-G": function(cm) {
+ count == "" ? cm.setCursor(cm.lineCount()) : cm.setCursor(parseInt(count, 10)-1);
+ popCount();
+ CodeMirror.commands.goLineStart(cm);
+ },
+ nofallthrough: true, style: "fat-cursor"
};
- // Add bindings for number keys
- for (var i = 1; i < 10; ++i) map[i] = pushCountDigit(i);
+
+ // standard mode switching
+ iterList(["d", "t", "T", "f", "F", "c", "r"],
+ function (ch) {
+ CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
+ cm.setOption("keyMap", "vim-prefix-" + ch);
+ emptyBuffer();
+ };
+ });
+
+ function addCountBindings(keyMap) {
+ // Add bindings for number keys
+ keyMap["0"] = function(cm) {
+ count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);
+ };
+ for (var i = 1; i < 10; ++i) keyMap[i] = pushCountDigit(i);
+ }
+ addCountBindings(CodeMirror.keyMap.vim);
+
+ // main num keymap
// Add bindings that are influenced by number keys
- iterObj({"H": "goColumnLeft", "L": "goColumnRight", "J": "goLineDown", "K": "goLineUp",
- "Left": "goColumnLeft", "Right": "goColumnRight", "Down": "goLineDown", "Up": "goLineUp",
- "Backspace": "goCharLeft", "Space": "goCharRight",
- "B": function(cm) {moveToWord(cm, word, -1, "end");},
- "E": function(cm) {moveToWord(cm, word, 1, "end");},
- "W": function(cm) {moveToWord(cm, word, 1, "start");},
- "Shift-B": function(cm) {moveToWord(cm, bigWord, -1, "end");},
- "Shift-E": function(cm) {moveToWord(cm, bigWord, 1, "end");},
- "Shift-W": function(cm) {moveToWord(cm, bigWord, 1, "start");},
- "X": function(cm) {CodeMirror.commands.delCharRight(cm)},
- "P": function(cm) {
- var cur = cm.getCursor().line;
- if (buf!= "") {
- CodeMirror.commands.goLineEnd(cm);
- cm.replaceSelection(buf, "end");
- }
- cm.setCursor(cur+1);
- },
- "Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm)},
- "Shift-J": function(cm) {joinLineNext(cm)},
- "Shift-`": function(cm) {
- var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
- cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
- cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
- cm.setCursor(cur.line, cur.ch+1);
- },
- "Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm)},
- "Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm)},
- "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
- "U": "undo", "Ctrl-R": "redo", "Shift-4": "goLineEnd"},
- function(key, cmd) { map[key] = countTimes(cmd); });
+ iterObj({
+ "Left": "goColumnLeft", "Right": "goColumnRight",
+ "Down": "goLineDown", "Up": "goLineUp", "Backspace": "goCharLeft",
+ "Space": "goCharRight",
+ "X": function(cm) {CodeMirror.commands.delCharRight(cm);},
+ "P": function(cm) {
+ var cur = cm.getCursor().line;
+ if (buf!= "") {
+ if (buf[0] == "\n") CodeMirror.commands.goLineEnd(cm);
+ cm.replaceRange(buf, cm.getCursor());
+ }
+ },
+ "Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm);},
+ "Shift-J": function(cm) {joinLineNext(cm);},
+ "Shift-P": function(cm) {
+ var cur = cm.getCursor().line;
+ if (buf!= "") {
+ CodeMirror.commands.goLineUp(cm);
+ CodeMirror.commands.goLineEnd(cm);
+ cm.replaceSelection(buf, "end");
+ }
+ cm.setCursor(cur+1);
+ },
+ "'~'": function(cm) {
+ var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
+ cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
+ cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
+ cm.setCursor(cur.line, cur.ch+1);
+ },
+ "Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm);},
+ "Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm);},
+ "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
+ "U": "undo", "Ctrl-R": "redo"
+ }, function(key, cmd) { map[key] = countTimes(cmd); });
+
+ // empty key maps
+ iterList([
+ "vim-prefix-d'",
+ "vim-prefix-y'",
+ "vim-prefix-df",
+ "vim-prefix-dF",
+ "vim-prefix-dt",
+ "vim-prefix-dT",
+ "vim-prefix-c",
+ "vim-prefix-cf",
+ "vim-prefix-cF",
+ "vim-prefix-ct",
+ "vim-prefix-cT",
+ "vim-prefix-",
+ "vim-prefix-f",
+ "vim-prefix-F",
+ "vim-prefix-t",
+ "vim-prefix-T",
+ "vim-prefix-r",
+ "vim-prefix-m"
+ ],
+ function (prefix) {
+ CodeMirror.keyMap[prefix] = {
+ auto: "vim",
+ nofallthrough: true,
+ style: "fat-cursor"
+ };
+ });
CodeMirror.keyMap["vim-prefix-g"] = {
- "E": countTimes(function(cm) { moveToWord(cm, word, -1, "start");}),
- "Shift-E": countTimes(function(cm) { moveToWord(cm, bigWord, -1, "start");}),
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
+ "E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "start"));}),
+ "Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "start"));}),
+ "G": function (cm) { cm.setCursor({line: 0, ch: cm.getCursor().ch});},
+ auto: "vim", nofallthrough: true, style: "fat-cursor"
};
- CodeMirror.keyMap["vim-prefix-m"] = {
- "A": function(cm) {mark["A"] = cm.getCursor().line;},
- "Shift-A": function(cm) {mark["Shift-A"] = cm.getCursor().line;},
- "B": function(cm) {mark["B"] = cm.getCursor().line;},
- "Shift-B": function(cm) {mark["Shift-B"] = cm.getCursor().line;},
- "C": function(cm) {mark["C"] = cm.getCursor().line;},
- "Shift-C": function(cm) {mark["Shift-C"] = cm.getCursor().line;},
- "D": function(cm) {mark["D"] = cm.getCursor().line;},
- "Shift-D": function(cm) {mark["Shift-D"] = cm.getCursor().line;},
- "E": function(cm) {mark["E"] = cm.getCursor().line;},
- "Shift-E": function(cm) {mark["Shift-E"] = cm.getCursor().line;},
- "F": function(cm) {mark["F"] = cm.getCursor().line;},
- "Shift-F": function(cm) {mark["Shift-F"] = cm.getCursor().line;},
- "G": function(cm) {mark["G"] = cm.getCursor().line;},
- "Shift-G": function(cm) {mark["Shift-G"] = cm.getCursor().line;},
- "H": function(cm) {mark["H"] = cm.getCursor().line;},
- "Shift-H": function(cm) {mark["Shift-H"] = cm.getCursor().line;},
- "I": function(cm) {mark["I"] = cm.getCursor().line;},
- "Shift-I": function(cm) {mark["Shift-I"] = cm.getCursor().line;},
- "J": function(cm) {mark["J"] = cm.getCursor().line;},
- "Shift-J": function(cm) {mark["Shift-J"] = cm.getCursor().line;},
- "K": function(cm) {mark["K"] = cm.getCursor().line;},
- "Shift-K": function(cm) {mark["Shift-K"] = cm.getCursor().line;},
- "L": function(cm) {mark["L"] = cm.getCursor().line;},
- "Shift-L": function(cm) {mark["Shift-L"] = cm.getCursor().line;},
- "M": function(cm) {mark["M"] = cm.getCursor().line;},
- "Shift-M": function(cm) {mark["Shift-M"] = cm.getCursor().line;},
- "N": function(cm) {mark["N"] = cm.getCursor().line;},
- "Shift-N": function(cm) {mark["Shift-N"] = cm.getCursor().line;},
- "O": function(cm) {mark["O"] = cm.getCursor().line;},
- "Shift-O": function(cm) {mark["Shift-O"] = cm.getCursor().line;},
- "P": function(cm) {mark["P"] = cm.getCursor().line;},
- "Shift-P": function(cm) {mark["Shift-P"] = cm.getCursor().line;},
- "Q": function(cm) {mark["Q"] = cm.getCursor().line;},
- "Shift-Q": function(cm) {mark["Shift-Q"] = cm.getCursor().line;},
- "R": function(cm) {mark["R"] = cm.getCursor().line;},
- "Shift-R": function(cm) {mark["Shift-R"] = cm.getCursor().line;},
- "S": function(cm) {mark["S"] = cm.getCursor().line;},
- "Shift-S": function(cm) {mark["Shift-S"] = cm.getCursor().line;},
- "T": function(cm) {mark["T"] = cm.getCursor().line;},
- "Shift-T": function(cm) {mark["Shift-T"] = cm.getCursor().line;},
- "U": function(cm) {mark["U"] = cm.getCursor().line;},
- "Shift-U": function(cm) {mark["Shift-U"] = cm.getCursor().line;},
- "V": function(cm) {mark["V"] = cm.getCursor().line;},
- "Shift-V": function(cm) {mark["Shift-V"] = cm.getCursor().line;},
- "W": function(cm) {mark["W"] = cm.getCursor().line;},
- "Shift-W": function(cm) {mark["Shift-W"] = cm.getCursor().line;},
- "X": function(cm) {mark["X"] = cm.getCursor().line;},
- "Shift-X": function(cm) {mark["Shift-X"] = cm.getCursor().line;},
- "Y": function(cm) {mark["Y"] = cm.getCursor().line;},
- "Shift-Y": function(cm) {mark["Shift-Y"] = cm.getCursor().line;},
- "Z": function(cm) {mark["Z"] = cm.getCursor().line;},
- "Shift-Z": function(cm) {mark["Shift-Z"] = cm.getCursor().line;},
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
- }
-
CodeMirror.keyMap["vim-prefix-d"] = {
- "D": countTimes(function(cm) { pushInBuffer("\n"+cm.getLine(cm.getCursor().line)); cm.removeLine(cm.getCursor().line); }),
- "'": function(cm) {cm.setOption("keyMap", "vim-prefix-d'"); emptyBuffer();},
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
+ "D": countTimes(function(cm) {
+ pushInBuffer("\n"+cm.getLine(cm.getCursor().line));
+ cm.removeLine(cm.getCursor().line);
+ cm.setOption("keyMap", "vim");
+ }),
+ "'": function(cm) {
+ cm.setOption("keyMap", "vim-prefix-d'");
+ emptyBuffer();
+ },
+ "B": function(cm) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+ var index = line.lastIndexOf(" ", cur.ch);
+
+ pushInBuffer(line.substring(index, cur.ch));
+ cm.replaceRange("", {line: cur.line, ch: index}, cur);
+ cm.setOption("keyMap", "vim");
+ },
+ nofallthrough: true, style: "fat-cursor"
};
+ // FIXME - does not work for bindings like "d3e"
+ addCountBindings(CodeMirror.keyMap["vim-prefix-d"]);
- CodeMirror.keyMap["vim-prefix-d'"] = {
- "A": function(cm) {delTillMark(cm,"A");},
- "Shift-A": function(cm) {delTillMark(cm,"Shift-A");},
- "B": function(cm) {delTillMark(cm,"B");},
- "Shift-B": function(cm) {delTillMark(cm,"Shift-B");},
- "C": function(cm) {delTillMark(cm,"C");},
- "Shift-C": function(cm) {delTillMark(cm,"Shift-C");},
- "D": function(cm) {delTillMark(cm,"D");},
- "Shift-D": function(cm) {delTillMark(cm,"Shift-D");},
- "E": function(cm) {delTillMark(cm,"E");},
- "Shift-E": function(cm) {delTillMark(cm,"Shift-E");},
- "F": function(cm) {delTillMark(cm,"F");},
- "Shift-F": function(cm) {delTillMark(cm,"Shift-F");},
- "G": function(cm) {delTillMark(cm,"G");},
- "Shift-G": function(cm) {delTillMark(cm,"Shift-G");},
- "H": function(cm) {delTillMark(cm,"H");},
- "Shift-H": function(cm) {delTillMark(cm,"Shift-H");},
- "I": function(cm) {delTillMark(cm,"I");},
- "Shift-I": function(cm) {delTillMark(cm,"Shift-I");},
- "J": function(cm) {delTillMark(cm,"J");},
- "Shift-J": function(cm) {delTillMark(cm,"Shift-J");},
- "K": function(cm) {delTillMark(cm,"K");},
- "Shift-K": function(cm) {delTillMark(cm,"Shift-K");},
- "L": function(cm) {delTillMark(cm,"L");},
- "Shift-L": function(cm) {delTillMark(cm,"Shift-L");},
- "M": function(cm) {delTillMark(cm,"M");},
- "Shift-M": function(cm) {delTillMark(cm,"Shift-M");},
- "N": function(cm) {delTillMark(cm,"N");},
- "Shift-N": function(cm) {delTillMark(cm,"Shift-N");},
- "O": function(cm) {delTillMark(cm,"O");},
- "Shift-O": function(cm) {delTillMark(cm,"Shift-O");},
- "P": function(cm) {delTillMark(cm,"P");},
- "Shift-P": function(cm) {delTillMark(cm,"Shift-P");},
- "Q": function(cm) {delTillMark(cm,"Q");},
- "Shift-Q": function(cm) {delTillMark(cm,"Shift-Q");},
- "R": function(cm) {delTillMark(cm,"R");},
- "Shift-R": function(cm) {delTillMark(cm,"Shift-R");},
- "S": function(cm) {delTillMark(cm,"S");},
- "Shift-S": function(cm) {delTillMark(cm,"Shift-S");},
- "T": function(cm) {delTillMark(cm,"T");},
- "Shift-T": function(cm) {delTillMark(cm,"Shift-T");},
- "U": function(cm) {delTillMark(cm,"U");},
- "Shift-U": function(cm) {delTillMark(cm,"Shift-U");},
- "V": function(cm) {delTillMark(cm,"V");},
- "Shift-V": function(cm) {delTillMark(cm,"Shift-V");},
- "W": function(cm) {delTillMark(cm,"W");},
- "Shift-W": function(cm) {delTillMark(cm,"Shift-W");},
- "X": function(cm) {delTillMark(cm,"X");},
- "Shift-X": function(cm) {delTillMark(cm,"Shift-X");},
- "Y": function(cm) {delTillMark(cm,"Y");},
- "Shift-Y": function(cm) {delTillMark(cm,"Shift-Y");},
- "Z": function(cm) {delTillMark(cm,"Z");},
- "Shift-Z": function(cm) {delTillMark(cm,"Shift-Z");},
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
+ CodeMirror.keyMap["vim-prefix-c"] = {
+ "B": function (cm) {
+ countTimes("delWordLeft")(cm);
+ enterInsertMode(cm);
+ },
+ "C": function (cm) {
+ iterTimes(function (i, last) {
+ CodeMirror.commands.deleteLine(cm);
+ if (i) {
+ CodeMirror.commands.delCharRight(cm);
+ if (last) CodeMirror.commands.deleteLine(cm);
+ }
+ });
+ enterInsertMode(cm);
+ },
+ nofallthrough: true, style: "fat-cursor"
};
- CodeMirror.keyMap["vim-prefix-y'"] = {
- "A": function(cm) {yankTillMark(cm,"A");},
- "Shift-A": function(cm) {yankTillMark(cm,"Shift-A");},
- "B": function(cm) {yankTillMark(cm,"B");},
- "Shift-B": function(cm) {yankTillMark(cm,"Shift-B");},
- "C": function(cm) {yankTillMark(cm,"C");},
- "Shift-C": function(cm) {yankTillMark(cm,"Shift-C");},
- "D": function(cm) {yankTillMark(cm,"D");},
- "Shift-D": function(cm) {yankTillMark(cm,"Shift-D");},
- "E": function(cm) {yankTillMark(cm,"E");},
- "Shift-E": function(cm) {yankTillMark(cm,"Shift-E");},
- "F": function(cm) {yankTillMark(cm,"F");},
- "Shift-F": function(cm) {yankTillMark(cm,"Shift-F");},
- "G": function(cm) {yankTillMark(cm,"G");},
- "Shift-G": function(cm) {yankTillMark(cm,"Shift-G");},
- "H": function(cm) {yankTillMark(cm,"H");},
- "Shift-H": function(cm) {yankTillMark(cm,"Shift-H");},
- "I": function(cm) {yankTillMark(cm,"I");},
- "Shift-I": function(cm) {yankTillMark(cm,"Shift-I");},
- "J": function(cm) {yankTillMark(cm,"J");},
- "Shift-J": function(cm) {yankTillMark(cm,"Shift-J");},
- "K": function(cm) {yankTillMark(cm,"K");},
- "Shift-K": function(cm) {yankTillMark(cm,"Shift-K");},
- "L": function(cm) {yankTillMark(cm,"L");},
- "Shift-L": function(cm) {yankTillMark(cm,"Shift-L");},
- "M": function(cm) {yankTillMark(cm,"M");},
- "Shift-M": function(cm) {yankTillMark(cm,"Shift-M");},
- "N": function(cm) {yankTillMark(cm,"N");},
- "Shift-N": function(cm) {yankTillMark(cm,"Shift-N");},
- "O": function(cm) {yankTillMark(cm,"O");},
- "Shift-O": function(cm) {yankTillMark(cm,"Shift-O");},
- "P": function(cm) {yankTillMark(cm,"P");},
- "Shift-P": function(cm) {yankTillMark(cm,"Shift-P");},
- "Q": function(cm) {yankTillMark(cm,"Q");},
- "Shift-Q": function(cm) {yankTillMark(cm,"Shift-Q");},
- "R": function(cm) {yankTillMark(cm,"R");},
- "Shift-R": function(cm) {yankTillMark(cm,"Shift-R");},
- "S": function(cm) {yankTillMark(cm,"S");},
- "Shift-S": function(cm) {yankTillMark(cm,"Shift-S");},
- "T": function(cm) {yankTillMark(cm,"T");},
- "Shift-T": function(cm) {yankTillMark(cm,"Shift-T");},
- "U": function(cm) {yankTillMark(cm,"U");},
- "Shift-U": function(cm) {yankTillMark(cm,"Shift-U");},
- "V": function(cm) {yankTillMark(cm,"V");},
- "Shift-V": function(cm) {yankTillMark(cm,"Shift-V");},
- "W": function(cm) {yankTillMark(cm,"W");},
- "Shift-W": function(cm) {yankTillMark(cm,"Shift-W");},
- "X": function(cm) {yankTillMark(cm,"X");},
- "Shift-X": function(cm) {yankTillMark(cm,"Shift-X");},
- "Y": function(cm) {yankTillMark(cm,"Y");},
- "Shift-Y": function(cm) {yankTillMark(cm,"Shift-Y");},
- "Z": function(cm) {yankTillMark(cm,"Z");},
- "Shift-Z": function(cm) {yankTillMark(cm,"Shift-Z");},
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
+ iterList(["vim-prefix-d", "vim-prefix-c", "vim-prefix-"], function (prefix) {
+ iterList(["f", "F", "T", "t"],
+ function (ch) {
+ CodeMirror.keyMap[prefix][toCombo(ch)] = function (cm) {
+ cm.setOption("keyMap", prefix + ch);
+ emptyBuffer();
+ };
+ });
+ });
+
+ var MOTION_OPTIONS = {
+ "t": {inclusive: false, forward: true},
+ "f": {inclusive: true, forward: true},
+ "T": {inclusive: false, forward: false},
+ "F": {inclusive: true, forward: false}
};
+ function setupPrefixBindingForKey(m) {
+ CodeMirror.keyMap["vim-prefix-m"][m] = function(cm) {
+ mark[m] = cm.getCursor().line;
+ };
+ CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
+ delTillMark(cm,m);
+ };
+ CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
+ yankTillMark(cm,m);
+ };
+ CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
+ var cur = cm.getCursor();
+ cm.replaceRange(toLetter(m),
+ {line: cur.line, ch: cur.ch},
+ {line: cur.line, ch: cur.ch + 1});
+ CodeMirror.commands.goColumnLeft(cm);
+ };
+ // all commands, related to motions till char in line
+ iterObj(MOTION_OPTIONS, function (ch, options) {
+ CodeMirror.keyMap["vim-prefix-" + ch][m] = function(cm) {
+ moveTillChar(cm, m, options);
+ };
+ CodeMirror.keyMap["vim-prefix-d" + ch][m] = function(cm) {
+ delTillChar(cm, m, options);
+ };
+ CodeMirror.keyMap["vim-prefix-c" + ch][m] = function(cm) {
+ delTillChar(cm, m, options);
+ enterInsertMode(cm);
+ };
+ });
+ }
+ for (var i = 65; i < 65 + 26; i++) { // uppercase alphabet char codes
+ var ch = String.fromCharCode(i);
+ setupPrefixBindingForKey(toCombo(ch));
+ setupPrefixBindingForKey(toCombo(ch.toLowerCase()));
+ }
+ iterList(SPECIAL_SYMBOLS, function (ch) {
+ setupPrefixBindingForKey(toCombo(ch));
+ });
+ setupPrefixBindingForKey("Space");
+
CodeMirror.keyMap["vim-prefix-y"] = {
"Y": countTimes(function(cm) { pushInBuffer("\n"+cm.getLine(cm.getCursor().line+yank)); yank++; }),
"'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
- auto: "vim",
- catchall: function(cm) {/*ignore*/}
+ nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap["vim-insert"] = {
+ // TODO: override navigation keys so that Esc will cancel automatic indentation from o, O, i_
"Esc": function(cm) {
- cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
- cm.setOption("keyMap", "vim");
- editCursor("vim");
- },
- "Ctrl-N": function(cm) {/* Code to bring up autocomplete hint */},
- "Ctrl-P": function(cm) {/* Code to bring up autocomplete hint */},
+ cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
+ cm.setOption("keyMap", "vim");
+ },
+ "Ctrl-N": "autocomplete",
+ "Ctrl-P": "autocomplete",
fallthrough: ["default"]
};
+
+ function findMatchedSymbol(cm, cur, symb) {
+ var line = cur.line;
+ var symb = symb ? symb : cm.getLine(line)[cur.ch];
+
+ // Are we at the opening or closing char
+ var forwards = ['(', '[', '{'].indexOf(symb) != -1;
+
+ var reverseSymb = (function(sym) {
+ switch (sym) {
+ case '(' : return ')';
+ case '[' : return ']';
+ case '{' : return '}';
+ case ')' : return '(';
+ case ']' : return '[';
+ case '}' : return '{';
+ default : return null;
+ }
+ })(symb);
+
+ // Couldn't find a matching symbol, abort
+ if (reverseSymb == null) return cur;
+
+ // Tracking our imbalance in open/closing symbols. An opening symbol wii be
+ // the first thing we pick up if moving forward, this isn't true moving backwards
+ var disBal = forwards ? 0 : 1;
+
+ while (true) {
+ if (line == cur.line) {
+ // First pass, do some special stuff
+ var currLine = forwards ? cm.getLine(line).substr(cur.ch).split('') : cm.getLine(line).substr(0,cur.ch).split('').reverse();
+ } else {
+ var currLine = forwards ? cm.getLine(line).split('') : cm.getLine(line).split('').reverse();
+ }
+
+ for (var index = 0; index < currLine.length; index++) {
+ if (currLine[index] == symb) disBal++;
+ else if (currLine[index] == reverseSymb) disBal--;
+
+ if (disBal == 0) {
+ if (forwards && cur.line == line) return {line: line, ch: index + cur.ch};
+ else if (forwards) return {line: line, ch: index};
+ else return {line: line, ch: currLine.length - index - 1 };
+ }
+ }
+
+ if (forwards) line++;
+ else line--;
+ }
+ }
+
+ function selectCompanionObject(cm, revSymb, inclusive) {
+ var cur = cm.getCursor();
+
+ var end = findMatchedSymbol(cm, cur, revSymb);
+ var start = findMatchedSymbol(cm, end);
+ start.ch += inclusive ? 1 : 0;
+ end.ch += inclusive ? 0 : 1;
+
+ return {start: start, end: end};
+ }
+
+ // These are our motion commands to be used for navigation and selection with
+ // certian other commands. All should return a cursor object.
+ var motionList = ['B', 'E', 'J', 'K', 'H', 'L', 'W', 'Shift-W', "'^'", "'$'", "'%'", 'Esc'];
+
+ motions = {
+ 'B': function(cm, times) { return moveToWord(cm, word, -1, times); },
+ 'Shift-B': function(cm, times) { return moveToWord(cm, bigWord, -1, times); },
+ 'E': function(cm, times) { return moveToWord(cm, word, 1, times, 'end'); },
+ 'Shift-E': function(cm, times) { return moveToWord(cm, bigWord, 1, times, 'end'); },
+ 'J': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line+times, ch : cur.ch};
+ },
+
+ 'K': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line-times, ch: cur.ch};
+ },
+
+ 'H': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line, ch: cur.ch-times};
+ },
+
+ 'L': function(cm, times) {
+ var cur = cm.getCursor();
+ return {line: cur.line, ch: cur.ch+times};
+ },
+ 'W': function(cm, times) { return moveToWord(cm, word, 1, times); },
+ 'Shift-W': function(cm, times) { return moveToWord(cm, bigWord, 1, times); },
+ "'^'": function(cm, times) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line).split('');
+
+ // Empty line :o
+ if (line.length == 0) return cur;
+
+ for (var index = 0; index < line.length; index++) {
+ if (line[index].match(/[^\s]/)) return {line: cur.line, ch: index};
+ }
+ },
+ "'$'": function(cm) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+ return {line: cur.line, ch: line.length};
+ },
+ "'%'": function(cm) { return findMatchedSymbol(cm, cm.getCursor()); },
+ "Esc" : function(cm) {
+ cm.setOption('vim');
+ reptTimes = 0;
+
+ return cm.getCursor();
+ }
+ };
+
+ // Map our movement actions each operator and non-operational movement
+ motionList.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
+ // Get our selected range
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ // Set swap var if range is of negative length
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+
+ // Take action, switching start and end if swap var is set
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ cm.replaceRange("", swap ? end : start, swap ? start : end);
+
+ // And clean up
+ reptTimes = 0;
+ cm.setOption("keyMap", "vim");
+ };
+
+ CodeMirror.keyMap['vim-prefix-c'][key] = function(cm) {
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ cm.replaceRange("", swap ? end : start, swap ? start : end);
+
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-insert');
+ };
+
+ CodeMirror.keyMap['vim-prefix-y'][key] = function(cm) {
+ var start = cm.getCursor();
+ var end = motions[key](cm, reptTimes ? reptTimes : 1);
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+
+ reptTimes = 0;
+ cm.setOption("keyMap", "vim");
+ };
+
+ CodeMirror.keyMap['vim'][key] = function(cm) {
+ var cur = motions[key](cm, reptTimes ? reptTimes : 1);
+ cm.setCursor(cur.line, cur.ch);
+
+ reptTimes = 0;
+ };
+ });
+
+ var nums = [1,2,3,4,5,6,7,8,9];
+ nums.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-d'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-y'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ CodeMirror.keyMap['vim-prefix-c'][key] = function (cm) {
+ reptTimes = (reptTimes * 10) + key;
+ };
+ });
+
+ // Create our keymaps for each operator and make xa and xi where x is an operator
+ // change to the corrosponding keymap
+ var operators = ['d', 'y', 'c'];
+ operators.forEach(function(key, index, array) {
+ CodeMirror.keyMap['vim-prefix-'+key+'a'] = {
+ auto: 'vim', nofallthrough: true, style: "fat-cursor"
+ };
+ CodeMirror.keyMap['vim-prefix-'+key+'i'] = {
+ auto: 'vim', nofallthrough: true, style: "fat-cursor"
+ };
+
+ CodeMirror.keyMap['vim-prefix-'+key]['A'] = function(cm) {
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-prefix-' + key + 'a');
+ };
+
+ CodeMirror.keyMap['vim-prefix-'+key]['I'] = function(cm) {
+ reptTimes = 0;
+ cm.setOption('keyMap', 'vim-prefix-' + key + 'i');
+ };
+ });
+
+ function regexLastIndexOf(string, pattern, startIndex) {
+ for (var i = startIndex == null ? string.length : startIndex; i >= 0; --i)
+ if (pattern.test(string.charAt(i))) return i;
+ return -1;
+ }
+
+ // Create our text object functions. They work similar to motions but they
+ // return a start cursor as well
+ var textObjectList = ['W', 'Shift-[', 'Shift-9', '['];
+ var textObjects = {
+ 'W': function(cm, inclusive) {
+ var cur = cm.getCursor();
+ var line = cm.getLine(cur.line);
+
+ var line_to_char = new String(line.substring(0, cur.ch));
+ var start = regexLastIndexOf(line_to_char, /[^a-zA-Z0-9]/) + 1;
+ var end = motions["E"](cm, 1) ;
+
+ end.ch += inclusive ? 1 : 0 ;
+ return {start: {line: cur.line, ch: start}, end: end };
+ },
+ 'Shift-[': function(cm, inclusive) { return selectCompanionObject(cm, '}', inclusive); },
+ 'Shift-9': function(cm, inclusive) { return selectCompanionObject(cm, ')', inclusive); },
+ '[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); }
+ };
+
+ // One function to handle all operation upon text objects. Kinda funky but it works
+ // better than rewriting this code six times
+ function textObjectManipulation(cm, object, remove, insert, inclusive) {
+ // Object is the text object, delete object if remove is true, enter insert
+ // mode if insert is true, inclusive is the difference between a and i
+ var tmp = textObjects[object](cm, inclusive);
+ var start = tmp.start;
+ var end = tmp.end;
+
+ if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true ;
+
+ pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
+ if (remove) cm.replaceRange("", swap ? end : start, swap ? start : end);
+ if (insert) cm.setOption('keyMap', 'vim-insert');
+ }
+
+ // And finally build the keymaps up from the text objects
+ for (var i = 0; i < textObjectList.length; ++i) {
+ var object = textObjectList[i];
+ (function(object) {
+ CodeMirror.keyMap['vim-prefix-di'][object] = function(cm) { textObjectManipulation(cm, object, true, false, false); };
+ CodeMirror.keyMap['vim-prefix-da'][object] = function(cm) { textObjectManipulation(cm, object, true, false, true); };
+ CodeMirror.keyMap['vim-prefix-yi'][object] = function(cm) { textObjectManipulation(cm, object, false, false, false); };
+ CodeMirror.keyMap['vim-prefix-ya'][object] = function(cm) { textObjectManipulation(cm, object, false, false, true); };
+ CodeMirror.keyMap['vim-prefix-ci'][object] = function(cm) { textObjectManipulation(cm, object, true, true, false); };
+ CodeMirror.keyMap['vim-prefix-ca'][object] = function(cm) { textObjectManipulation(cm, object, true, true, true); };
+ })(object)
+ }
})();
diff --git a/imports/codemirror/lib/codemirror.css b/imports/codemirror/lib/codemirror.css
index 2d79f4aa..191ac25a 100644
--- a/imports/codemirror/lib/codemirror.css
+++ b/imports/codemirror/lib/codemirror.css
@@ -1,10 +1,16 @@
.CodeMirror {
line-height: 1em;
font-family: monospace;
+
+ /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
+ position: relative;
+ /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
+ overflow: hidden;
}
.CodeMirror-scroll {
- overflow: auto;
+ overflow-x: auto;
+ overflow-y: hidden;
height: 300px;
/* This is needed to prevent an IE[67] bug where the scrolled content
is visible outside of the scrolling box. */
@@ -12,6 +18,37 @@
outline: none;
}
+/* Vertical scrollbar */
+.CodeMirror-scrollbar {
+ float: right;
+ overflow-x: hidden;
+ overflow-y: scroll;
+
+ /* This corrects for the 1px gap introduced to the left of the scrollbar
+ by the rule for .CodeMirror-scrollbar-inner. */
+ margin-left: -1px;
+}
+.CodeMirror-scrollbar-inner {
+ /* This needs to have a nonzero width in order for the scrollbar to appear
+ in Firefox and IE9. */
+ width: 1px;
+}
+.CodeMirror-scrollbar.cm-sb-overlap {
+ /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
+ rather than sitting to the right of it. */
+ position: absolute;
+ z-index: 1;
+ float: none;
+ right: 0;
+ min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-nonoverlap {
+ min-width: 12px;
+}
+.CodeMirror-scrollbar.cm-sb-ie7 {
+ min-width: 18px;
+}
+
.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
z-index: 10;
@@ -29,6 +66,11 @@
.CodeMirror-lines {
padding: .4em;
white-space: pre;
+ cursor: text;
+}
+.CodeMirror-lines * {
+ /* Necessary for throw-scrolling to decelerate properly on Safari. */
+ pointer-events: none;
}
.CodeMirror pre {
@@ -42,11 +84,14 @@
padding: 0; margin: 0;
white-space: pre;
word-wrap: normal;
+ line-height: inherit;
+ color: inherit;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
+ word-break: normal;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
@@ -61,8 +106,19 @@
position: absolute;
visibility: hidden;
border-left: 1px solid black;
- border-right:none;
- width:0;
+ border-right: none;
+ width: 0;
+}
+.cm-keymap-fat-cursor pre.CodeMirror-cursor {
+ width: auto;
+ border: 0;
+ background: transparent;
+ background: rgba(0, 200, 0, .4);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
+}
+/* Kludge to turn off filter in ie9+, which also accepts rgba */
+.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
}
.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
.CodeMirror-focused pre.CodeMirror-cursor {
@@ -98,7 +154,7 @@ div.CodeMirror-selected { background: #d9d9d9; }
.cm-s-default span.cm-bracket {color: #cc7;}
.cm-s-default span.cm-tag {color: #170;}
.cm-s-default span.cm-attribute {color: #00c;}
-.cm-s-default span.cm-header {color: #a0a;}
+.cm-s-default span.cm-header {color: blue;}
.cm-s-default span.cm-quote {color: #090;}
.cm-s-default span.cm-hr {color: #999;}
.cm-s-default span.cm-link {color: #00c;}
diff --git a/imports/codemirror/lib/codemirror.js b/imports/codemirror/lib/codemirror.js
index 5434a8dd..250d5b18 100644
--- a/imports/codemirror/lib/codemirror.js
+++ b/imports/codemirror/lib/codemirror.js
@@ -1,4 +1,4 @@
-// CodeMirror version 2.23
+// CodeMirror version 2.3
//
// All functions that need access to the editor's state live inside
// the CodeMirror function. Below that, at the bottom of the file,
@@ -23,14 +23,19 @@ var CodeMirror = (function() {
'' + // Wraps and hides input textarea
'
' +
+ '' + // This must be before the scroll area because it's float-right.
'';
if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
@@ -39,12 +44,13 @@ var CodeMirror = (function() {
scroller = wrapper.lastChild, code = scroller.firstChild,
mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
- cursor = measure.nextSibling, selectionDiv = cursor.nextSibling,
- lineDiv = selectionDiv.nextSibling;
- themeChanged();
+ cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
+ selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
+ scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
+ themeChanged(); keyMapChanged();
// Needed to hide big blue blinking cursor on Mobile Safari
if (ios) input.style.width = "0px";
- if (!webkit) lineSpace.draggable = true;
+ if (!webkit) scroller.draggable = true;
lineSpace.style.outline = "none";
if (options.tabindex != null) input.tabIndex = options.tabindex;
if (options.autofocus) focusInput();
@@ -52,6 +58,17 @@ var CodeMirror = (function() {
// Needed to handle Tab key in KHTML
if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
+ // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
+ // make it overlap the content. (But we only do this if the scrollbar doesn't already
+ // have a natural width. If the mouse is plugged in or the user sets the system pref
+ // to always show scrollbars, the scrollbar shouldn't overlap.)
+ if (mac_geLion) {
+ scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
+ } else if (ie_lt8) {
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+ scrollbar.className += " cm-sb-ie7";
+ }
+
// Check for problem with IE innerHTML not working when we have a
// P (or similar) parent node.
try { stringWidth("x"); }
@@ -75,7 +92,7 @@ var CodeMirror = (function() {
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
// Selection-related flags. shiftSelecting obviously tracks
// whether the user is holding shift.
- var shiftSelecting, lastClick, lastDoubleClick, lastScrollPos = 0, draggingText,
+ var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
overwrite = false, suppressEdits = false;
// Variables used by startOperation/endOperation to track what
// happened during the operation.
@@ -88,7 +105,7 @@ var CodeMirror = (function() {
var bracketHighlighted;
// Tracks the maximum line length so that the horizontal scrollbar
// can be kept static when scrolling.
- var maxLine = "", maxWidth;
+ var maxLine = "", updateMaxLine = false, maxLineChanged = true;
var tabCache = {};
// Initialize the content.
@@ -98,18 +115,16 @@ var CodeMirror = (function() {
// Register our event handlers.
connect(scroller, "mousedown", operation(onMouseDown));
connect(scroller, "dblclick", operation(onDoubleClick));
- connect(lineSpace, "dragstart", onDragStart);
connect(lineSpace, "selectstart", e_preventDefault);
// Gecko browsers fire contextmenu *after* opening the menu, at
// which point we can't mess with it anymore. Context menu is
// handled in onMouseDown for Gecko.
if (!gecko) connect(scroller, "contextmenu", onContextMenu);
- connect(scroller, "scroll", function() {
- lastScrollPos = scroller.scrollTop;
- updateDisplay([]);
- if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
- if (options.onScroll) options.onScroll(instance);
- });
+ connect(scroller, "scroll", onScroll);
+ connect(scrollbar, "scroll", onScroll);
+ connect(scrollbar, "mousedown", function() {setTimeout(focusInput, 0);});
+ connect(scroller, "mousewheel", onMouseWheel);
+ connect(scroller, "DOMMouseScroll", onMouseWheel);
connect(window, "resize", function() {updateDisplay(true);});
connect(input, "keyup", operation(onKeyUp));
connect(input, "input", fastPoll);
@@ -118,9 +133,16 @@ var CodeMirror = (function() {
connect(input, "focus", onFocus);
connect(input, "blur", onBlur);
- connect(scroller, "dragenter", e_stop);
- connect(scroller, "dragover", e_stop);
- connect(scroller, "drop", operation(onDrop));
+ if (options.dragDrop) {
+ connect(scroller, "dragstart", onDragStart);
+ function drag_(e) {
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
+ e_stop(e);
+ }
+ connect(scroller, "dragenter", drag_);
+ connect(scroller, "dragover", drag_);
+ connect(scroller, "drop", operation(onDrop));
+ }
connect(scroller, "paste", function(){focusInput(); fastPoll();});
connect(input, "paste", fastPoll);
connect(input, "cut", operation(function(){
@@ -160,6 +182,7 @@ var CodeMirror = (function() {
else if (option == "theme") themeChanged();
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
else if (option == "tabSize") updateDisplay(true);
+ else if (option == "keyMap") keyMapChanged();
if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
gutterChanged();
updateDisplay(true);
@@ -307,15 +330,20 @@ var CodeMirror = (function() {
},
scrollTo: function(x, y) {
if (x != null) scroller.scrollLeft = x;
- if (y != null) scroller.scrollTop = y;
+ if (y != null) scrollbar.scrollTop = y;
updateDisplay([]);
},
+ getScrollInfo: function() {
+ return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
+ height: scrollbar.scrollHeight, width: scroller.scrollWidth};
+ },
operation: function(f){return operation(f)();},
+ compoundChange: function(f){return compoundChange(f);},
refresh: function(){
updateDisplay(true);
- if (scroller.scrollHeight > lastScrollPos)
- scroller.scrollTop = lastScrollPos;
+ if (scrollbar.scrollHeight > lastScrollTop)
+ scrollbar.scrollTop = lastScrollTop;
},
getInputField: function(){return input;},
getWrapperElement: function(){return wrapper;},
@@ -336,12 +364,22 @@ var CodeMirror = (function() {
splitLines(code), top, top);
updateInput = true;
}
- function getValue(code) {
+ function getValue() {
var text = [];
doc.iter(0, doc.size, function(line) { text.push(line.text); });
return text.join("\n");
}
+ function onScroll(e) {
+ if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
+ lastScrollTop = scrollbar.scrollTop;
+ lastScrollLeft = scroller.scrollLeft;
+ updateDisplay([]);
+ if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
+ if (options.onScroll) options.onScroll(instance);
+ }
+ }
+
function onMouseDown(e) {
setShift(e_prop(e, "shiftKey"));
// Check whether this is a click in a widget
@@ -364,6 +402,8 @@ var CodeMirror = (function() {
return;
case 2:
if (start) setCursor(start.line, start.ch, true);
+ setTimeout(focusInput, 20);
+ e_preventDefault(e);
return;
}
// For button 1, if it was clicked inside the editor
@@ -385,23 +425,25 @@ var CodeMirror = (function() {
} else { lastClick = {time: now, pos: start}; }
var last = start, going;
- if (dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
+ if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
!posLess(start, sel.from) && !posLess(sel.to, start)) {
// Let the drag handler handle this.
- if (webkit) lineSpace.draggable = true;
- var up = connect(document, "mouseup", operation(function(e2) {
- if (webkit) lineSpace.draggable = false;
+ if (webkit) scroller.draggable = true;
+ function dragEnd(e2) {
+ if (webkit) scroller.draggable = false;
draggingText = false;
- up();
+ up(); drop();
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
e_preventDefault(e2);
setCursor(start.line, start.ch, true);
focusInput();
}
- }), true);
+ }
+ var up = connect(document, "mouseup", operation(dragEnd), true);
+ var drop = connect(scroller, "drop", operation(dragEnd), true);
draggingText = true;
// IE's approach to draggable
- if (lineSpace.dragDrop) lineSpace.dragDrop();
+ if (scroller.dragDrop) scroller.dragDrop();
return;
}
e_preventDefault(e);
@@ -447,6 +489,7 @@ var CodeMirror = (function() {
selectWordAt(start);
}
function onDrop(e) {
+ if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
e.preventDefault();
var pos = posFromMouse(e, true), files = e.dataTransfer.files;
if (!pos || options.readOnly) return;
@@ -456,28 +499,31 @@ var CodeMirror = (function() {
reader.onload = function() {
text[i] = reader.result;
if (++read == n) {
- pos = clipPos(pos);
- operation(function() {
+ pos = clipPos(pos);
+ operation(function() {
var end = replaceRange(text.join(""), pos, pos);
setSelectionUser(pos, end);
})();
- }
+ }
};
reader.readAsText(file);
}
var n = files.length, text = Array(n), read = 0;
for (var i = 0; i < n; ++i) loadFile(files[i], i);
- }
- else {
+ } else {
+ // Don't do a replace if the drop happened inside of the selected text.
+ if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
try {
var text = e.dataTransfer.getData("Text");
if (text) {
- var curFrom = sel.from, curTo = sel.to;
- setSelectionUser(pos, pos);
- if (draggingText) replaceRange("", curFrom, curTo);
- replaceSelection(text);
- focusInput();
- }
+ compoundChange(function() {
+ var curFrom = sel.from, curTo = sel.to;
+ setSelectionUser(pos, pos);
+ if (draggingText) replaceRange("", curFrom, curTo);
+ replaceSelection(text);
+ focusInput();
+ });
+ }
}
catch(e){}
}
@@ -487,7 +533,7 @@ var CodeMirror = (fun