From c2805e03c84b6e598556fd06d1ede7aaeea7ce9c Mon Sep 17 00:00:00 2001 From: Valerio Virgillito Date: Tue, 6 Mar 2012 16:17:54 -0800 Subject: Squashed commit FileIO-Build-Candidate into Master Fixing issues with HTML and CSS URLs. Adjusted RegEx logic. Also code a mirror update and undo/redo changes were merged into this request. Signed-off-by: Valerio Virgillito --- imports/codemirror/LICENSE | 4 + imports/codemirror/keymap/emacs.js | 0 imports/codemirror/keymap/vim.js | 277 +++++++++- imports/codemirror/lib/codemirror.css | 12 +- imports/codemirror/lib/codemirror.js | 554 +++++++++++-------- imports/codemirror/lib/util/dialog.css | 0 imports/codemirror/lib/util/dialog.js | 0 imports/codemirror/lib/util/foldcode.js | 120 +++++ imports/codemirror/lib/util/formatting.js | 9 +- imports/codemirror/lib/util/javascript-hint.js | 67 ++- imports/codemirror/lib/util/match-highlighter.js | 44 ++ imports/codemirror/lib/util/overlay.js | 0 imports/codemirror/lib/util/runmode.js | 38 +- imports/codemirror/lib/util/search.js | 0 imports/codemirror/lib/util/searchcursor.js | 0 imports/codemirror/lib/util/simple-hint.css | 0 imports/codemirror/lib/util/simple-hint.js | 0 imports/codemirror/mode/clike/clike.js | 19 +- imports/codemirror/mode/clike/index.html | 2 +- imports/codemirror/mode/clojure/clojure.js | 2 +- imports/codemirror/mode/clojure/index.html | 0 imports/codemirror/mode/coffeescript/LICENSE | 0 .../codemirror/mode/coffeescript/coffeescript.js | 90 ++-- imports/codemirror/mode/coffeescript/index.html | 0 imports/codemirror/mode/css/css.js | 0 imports/codemirror/mode/css/index.html | 0 imports/codemirror/mode/diff/diff.css | 0 imports/codemirror/mode/diff/diff.js | 0 imports/codemirror/mode/diff/index.html | 0 imports/codemirror/mode/ecl/ecl.js | 203 +++++++ imports/codemirror/mode/ecl/index.html | 42 ++ imports/codemirror/mode/gfm/gfm.js | 2 +- imports/codemirror/mode/gfm/index.html | 0 imports/codemirror/mode/go/go.js | 170 ++++++ imports/codemirror/mode/go/index.html | 72 +++ imports/codemirror/mode/groovy/groovy.js | 0 imports/codemirror/mode/groovy/index.html | 0 imports/codemirror/mode/haskell/haskell.js | 0 imports/codemirror/mode/haskell/index.html | 0 .../codemirror/mode/htmlembedded/htmlembedded.js | 0 imports/codemirror/mode/htmlembedded/index.html | 0 imports/codemirror/mode/htmlmixed/htmlmixed.js | 0 imports/codemirror/mode/htmlmixed/index.html | 0 imports/codemirror/mode/javascript/index.html | 0 imports/codemirror/mode/javascript/javascript.js | 4 +- imports/codemirror/mode/jinja2/index.html | 0 imports/codemirror/mode/jinja2/jinja2.js | 0 imports/codemirror/mode/less/index.html | 588 +++++++++++++++++++++ imports/codemirror/mode/less/less.js | 189 +++++++ imports/codemirror/mode/lua/index.html | 0 imports/codemirror/mode/lua/lua.js | 0 imports/codemirror/mode/markdown/index.html | 0 imports/codemirror/mode/markdown/markdown.js | 82 ++- imports/codemirror/mode/mysql/index.html | 41 ++ imports/codemirror/mode/mysql/mysql.js | 188 +++++++ imports/codemirror/mode/ntriples/index.html | 0 imports/codemirror/mode/ntriples/ntriples.js | 0 imports/codemirror/mode/pascal/LICENSE | 0 imports/codemirror/mode/pascal/index.html | 0 imports/codemirror/mode/pascal/pascal.js | 48 +- imports/codemirror/mode/perl/LICENSE | 0 imports/codemirror/mode/perl/index.html | 0 imports/codemirror/mode/perl/perl.js | 2 +- imports/codemirror/mode/php/index.html | 0 imports/codemirror/mode/php/php.js | 78 ++- imports/codemirror/mode/plsql/index.html | 0 imports/codemirror/mode/plsql/plsql.js | 0 imports/codemirror/mode/properties/index.html | 40 ++ imports/codemirror/mode/properties/properties.css | 3 + imports/codemirror/mode/properties/properties.js | 57 ++ imports/codemirror/mode/python/LICENSE.txt | 0 imports/codemirror/mode/python/index.html | 0 imports/codemirror/mode/python/python.js | 41 +- imports/codemirror/mode/r/LICENSE | 0 imports/codemirror/mode/r/index.html | 0 imports/codemirror/mode/r/r.js | 0 imports/codemirror/mode/rpm/changes/changes.js | 0 imports/codemirror/mode/rpm/changes/index.html | 0 imports/codemirror/mode/rpm/spec/index.html | 0 imports/codemirror/mode/rpm/spec/spec.css | 0 imports/codemirror/mode/rpm/spec/spec.js | 2 +- imports/codemirror/mode/rst/index.html | 0 imports/codemirror/mode/rst/rst.js | 0 imports/codemirror/mode/ruby/LICENSE | 0 imports/codemirror/mode/ruby/index.html | 0 imports/codemirror/mode/ruby/ruby.js | 17 +- imports/codemirror/mode/rust/index.html | 6 +- imports/codemirror/mode/rust/rust.js | 51 +- imports/codemirror/mode/scheme/index.html | 0 imports/codemirror/mode/smalltalk/index.html | 0 imports/codemirror/mode/smalltalk/smalltalk.js | 32 +- imports/codemirror/mode/sparql/index.html | 0 imports/codemirror/mode/sparql/sparql.js | 0 imports/codemirror/mode/stex/index.html | 2 +- imports/codemirror/mode/stex/stex.js | 0 imports/codemirror/mode/tiddlywiki/index.html | 0 imports/codemirror/mode/tiddlywiki/tiddlywiki.css | 0 imports/codemirror/mode/tiddlywiki/tiddlywiki.js | 0 imports/codemirror/mode/velocity/index.html | 0 imports/codemirror/mode/velocity/velocity.js | 0 imports/codemirror/mode/verilog/index.html | 210 ++++++++ imports/codemirror/mode/verilog/verilog.js | 194 +++++++ imports/codemirror/mode/xml/index.html | 0 imports/codemirror/mode/xml/xml.js | 35 +- imports/codemirror/mode/xmlpure/index.html | 0 imports/codemirror/mode/xmlpure/xmlpure.js | 5 + imports/codemirror/mode/yaml/index.html | 0 imports/codemirror/mode/yaml/yaml.js | 0 imports/codemirror/theme/cobalt.css | 2 +- imports/codemirror/theme/eclipse.css | 0 imports/codemirror/theme/elegant.css | 0 imports/codemirror/theme/monokai.css | 2 +- imports/codemirror/theme/neat.css | 0 imports/codemirror/theme/night.css | 2 +- imports/codemirror/theme/rubyblue.css | 2 +- imports/codemirror/version.txt | 2 +- js/controllers/document-controller.js | 9 +- js/controllers/selection-controller.js | 12 +- js/controllers/undo-controller.js | 17 +- js/document/html-document.js | 181 +++++-- .../picker-navigator.reel/picker-navigator.js | 6 +- js/mediators/io-mediator.js | 163 ++++-- 122 files changed, 3493 insertions(+), 547 deletions(-) mode change 100755 => 100644 imports/codemirror/LICENSE mode change 100755 => 100644 imports/codemirror/keymap/emacs.js mode change 100755 => 100644 imports/codemirror/keymap/vim.js mode change 100755 => 100644 imports/codemirror/lib/codemirror.css mode change 100755 => 100644 imports/codemirror/lib/codemirror.js mode change 100755 => 100644 imports/codemirror/lib/util/dialog.css mode change 100755 => 100644 imports/codemirror/lib/util/dialog.js mode change 100755 => 100644 imports/codemirror/lib/util/foldcode.js mode change 100755 => 100644 imports/codemirror/lib/util/formatting.js mode change 100755 => 100644 imports/codemirror/lib/util/javascript-hint.js create mode 100644 imports/codemirror/lib/util/match-highlighter.js mode change 100755 => 100644 imports/codemirror/lib/util/overlay.js mode change 100755 => 100644 imports/codemirror/lib/util/runmode.js mode change 100755 => 100644 imports/codemirror/lib/util/search.js mode change 100755 => 100644 imports/codemirror/lib/util/searchcursor.js mode change 100755 => 100644 imports/codemirror/lib/util/simple-hint.css mode change 100755 => 100644 imports/codemirror/lib/util/simple-hint.js mode change 100755 => 100644 imports/codemirror/mode/clike/clike.js mode change 100755 => 100644 imports/codemirror/mode/clike/index.html mode change 100755 => 100644 imports/codemirror/mode/clojure/clojure.js mode change 100755 => 100644 imports/codemirror/mode/clojure/index.html mode change 100755 => 100644 imports/codemirror/mode/coffeescript/LICENSE mode change 100755 => 100644 imports/codemirror/mode/coffeescript/coffeescript.js mode change 100755 => 100644 imports/codemirror/mode/coffeescript/index.html mode change 100755 => 100644 imports/codemirror/mode/css/css.js mode change 100755 => 100644 imports/codemirror/mode/css/index.html mode change 100755 => 100644 imports/codemirror/mode/diff/diff.css mode change 100755 => 100644 imports/codemirror/mode/diff/diff.js mode change 100755 => 100644 imports/codemirror/mode/diff/index.html create mode 100644 imports/codemirror/mode/ecl/ecl.js create mode 100644 imports/codemirror/mode/ecl/index.html mode change 100755 => 100644 imports/codemirror/mode/gfm/gfm.js mode change 100755 => 100644 imports/codemirror/mode/gfm/index.html create mode 100644 imports/codemirror/mode/go/go.js create mode 100644 imports/codemirror/mode/go/index.html mode change 100755 => 100644 imports/codemirror/mode/groovy/groovy.js mode change 100755 => 100644 imports/codemirror/mode/groovy/index.html mode change 100755 => 100644 imports/codemirror/mode/haskell/haskell.js mode change 100755 => 100644 imports/codemirror/mode/haskell/index.html mode change 100755 => 100644 imports/codemirror/mode/htmlembedded/htmlembedded.js mode change 100755 => 100644 imports/codemirror/mode/htmlembedded/index.html mode change 100755 => 100644 imports/codemirror/mode/htmlmixed/htmlmixed.js mode change 100755 => 100644 imports/codemirror/mode/htmlmixed/index.html mode change 100755 => 100644 imports/codemirror/mode/javascript/index.html mode change 100755 => 100644 imports/codemirror/mode/javascript/javascript.js mode change 100755 => 100644 imports/codemirror/mode/jinja2/index.html mode change 100755 => 100644 imports/codemirror/mode/jinja2/jinja2.js create mode 100644 imports/codemirror/mode/less/index.html create mode 100644 imports/codemirror/mode/less/less.js mode change 100755 => 100644 imports/codemirror/mode/lua/index.html mode change 100755 => 100644 imports/codemirror/mode/lua/lua.js mode change 100755 => 100644 imports/codemirror/mode/markdown/index.html mode change 100755 => 100644 imports/codemirror/mode/markdown/markdown.js create mode 100644 imports/codemirror/mode/mysql/index.html create mode 100644 imports/codemirror/mode/mysql/mysql.js mode change 100755 => 100644 imports/codemirror/mode/ntriples/index.html mode change 100755 => 100644 imports/codemirror/mode/ntriples/ntriples.js mode change 100755 => 100644 imports/codemirror/mode/pascal/LICENSE mode change 100755 => 100644 imports/codemirror/mode/pascal/index.html mode change 100755 => 100644 imports/codemirror/mode/pascal/pascal.js mode change 100755 => 100644 imports/codemirror/mode/perl/LICENSE mode change 100755 => 100644 imports/codemirror/mode/perl/index.html mode change 100755 => 100644 imports/codemirror/mode/perl/perl.js mode change 100755 => 100644 imports/codemirror/mode/php/index.html mode change 100755 => 100644 imports/codemirror/mode/php/php.js mode change 100755 => 100644 imports/codemirror/mode/plsql/index.html mode change 100755 => 100644 imports/codemirror/mode/plsql/plsql.js create mode 100755 imports/codemirror/mode/properties/index.html create mode 100755 imports/codemirror/mode/properties/properties.css create mode 100755 imports/codemirror/mode/properties/properties.js mode change 100755 => 100644 imports/codemirror/mode/python/LICENSE.txt mode change 100755 => 100644 imports/codemirror/mode/python/index.html mode change 100755 => 100644 imports/codemirror/mode/python/python.js mode change 100755 => 100644 imports/codemirror/mode/r/LICENSE mode change 100755 => 100644 imports/codemirror/mode/r/index.html mode change 100755 => 100644 imports/codemirror/mode/r/r.js mode change 100755 => 100644 imports/codemirror/mode/rpm/changes/changes.js mode change 100755 => 100644 imports/codemirror/mode/rpm/changes/index.html mode change 100755 => 100644 imports/codemirror/mode/rpm/spec/index.html mode change 100755 => 100644 imports/codemirror/mode/rpm/spec/spec.css mode change 100755 => 100644 imports/codemirror/mode/rpm/spec/spec.js mode change 100755 => 100644 imports/codemirror/mode/rst/index.html mode change 100755 => 100644 imports/codemirror/mode/rst/rst.js mode change 100755 => 100644 imports/codemirror/mode/ruby/LICENSE mode change 100755 => 100644 imports/codemirror/mode/ruby/index.html mode change 100755 => 100644 imports/codemirror/mode/ruby/ruby.js mode change 100755 => 100644 imports/codemirror/mode/rust/index.html mode change 100755 => 100644 imports/codemirror/mode/rust/rust.js mode change 100755 => 100644 imports/codemirror/mode/scheme/index.html mode change 100755 => 100644 imports/codemirror/mode/smalltalk/index.html mode change 100755 => 100644 imports/codemirror/mode/smalltalk/smalltalk.js mode change 100755 => 100644 imports/codemirror/mode/sparql/index.html mode change 100755 => 100644 imports/codemirror/mode/sparql/sparql.js mode change 100755 => 100644 imports/codemirror/mode/stex/index.html mode change 100755 => 100644 imports/codemirror/mode/stex/stex.js mode change 100755 => 100644 imports/codemirror/mode/tiddlywiki/index.html mode change 100755 => 100644 imports/codemirror/mode/tiddlywiki/tiddlywiki.css mode change 100755 => 100644 imports/codemirror/mode/tiddlywiki/tiddlywiki.js mode change 100755 => 100644 imports/codemirror/mode/velocity/index.html mode change 100755 => 100644 imports/codemirror/mode/velocity/velocity.js create mode 100644 imports/codemirror/mode/verilog/index.html create mode 100644 imports/codemirror/mode/verilog/verilog.js mode change 100755 => 100644 imports/codemirror/mode/xml/index.html mode change 100755 => 100644 imports/codemirror/mode/xml/xml.js mode change 100755 => 100644 imports/codemirror/mode/xmlpure/index.html mode change 100755 => 100644 imports/codemirror/mode/xmlpure/xmlpure.js mode change 100755 => 100644 imports/codemirror/mode/yaml/index.html mode change 100755 => 100644 imports/codemirror/mode/yaml/yaml.js mode change 100755 => 100644 imports/codemirror/theme/cobalt.css mode change 100755 => 100644 imports/codemirror/theme/eclipse.css mode change 100755 => 100644 imports/codemirror/theme/elegant.css mode change 100755 => 100644 imports/codemirror/theme/monokai.css mode change 100755 => 100644 imports/codemirror/theme/neat.css mode change 100755 => 100644 imports/codemirror/theme/night.css mode change 100755 => 100644 imports/codemirror/theme/rubyblue.css diff --git a/imports/codemirror/LICENSE b/imports/codemirror/LICENSE old mode 100755 new mode 100644 index 3f7c0bb1..f62410e6 --- a/imports/codemirror/LICENSE +++ b/imports/codemirror/LICENSE @@ -17,3 +17,7 @@ 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/imports/codemirror/keymap/emacs.js b/imports/codemirror/keymap/emacs.js old mode 100755 new mode 100644 diff --git a/imports/codemirror/keymap/vim.js b/imports/codemirror/keymap/vim.js old mode 100755 new mode 100644 index e03e0128..f8fa5e07 --- a/imports/codemirror/keymap/vim.js +++ b/imports/codemirror/keymap/vim.js @@ -1,5 +1,11 @@ (function() { var count = ""; + var sdir = "f"; + var buf = ""; + var yank = 0; + var mark = []; + 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 countTimes(func) { @@ -41,11 +47,64 @@ } cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true); } + function joinLineNext(cm) { + var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line); + 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; + cm.setCursor(start); + for (var c = start; c <= end; c++) { + 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; + for (var c = start; c <= end; c++) { + pushInBuffer("\n"+cm.getLine(c)); + } + cm.setCursor(start); + } var map = CodeMirror.keyMap.vim = { "0": function(cm) {count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);}, - "I": function(cm) {popCount(); cm.setOption("keyMap", "vim-insert");}, + "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();}, + "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) { + var f = CodeMirror.commands.find; + if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; } + }, + "N": function(cm) { + var fn = CodeMirror.commands.findNext; + if (fn) sdir != "r" ? fn(cm) : CodeMirror.commands.findPrev(cm); + }, + "Shift-N": function(cm) { + 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*/} }; // Add bindings for number keys @@ -60,17 +119,229 @@ "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); }); 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*/} + auto: "vim", + catchall: function(cm) {/*ignore*/} + }; + + 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*/} + }; + + 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-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*/} + }; + + 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*/} }; CodeMirror.keyMap["vim-insert"] = { - "Esc": function(cm) {cm.setOption("keyMap", "vim");}, + "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 */}, fallthrough: ["default"] }; })(); diff --git a/imports/codemirror/lib/codemirror.css b/imports/codemirror/lib/codemirror.css old mode 100755 new mode 100644 index 11614251..5eadb247 --- a/imports/codemirror/lib/codemirror.css +++ b/imports/codemirror/lib/codemirror.css @@ -59,15 +59,21 @@ position: absolute; visibility: hidden; border-left: 1px solid black; + border-right:none; + width:0; } +.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} .CodeMirror-focused pre.CodeMirror-cursor { visibility: visible; } -span.CodeMirror-selected { background: #d9d9d9; } -.CodeMirror-focused span.CodeMirror-selected { background: #d2dcf8; } +div.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; } -.CodeMirror-searching {background: #ffa;} +.CodeMirror-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} /* Default theme */ diff --git a/imports/codemirror/lib/codemirror.js b/imports/codemirror/lib/codemirror.js old mode 100755 new mode 100644 index 79eb457d..9c6e65e4 --- a/imports/codemirror/lib/codemirror.js +++ b/imports/codemirror/lib/codemirror.js @@ -1,4 +1,4 @@ -// CodeMirror version 2.2 +// CodeMirror version 2.22 // // All functions that need access to the editor's state live inside // the CodeMirror function. Below that, at the bottom of the file, @@ -6,7 +6,7 @@ // CodeMirror is the only global var we claim var CodeMirror = (function() { - // This is the function that produces an editor instance. It's + // This is the function that produces an editor instance. Its // closure is used to store the editor state. function CodeMirror(place, givenOptions) { // Determine effective options based on given values and defaults. @@ -22,17 +22,17 @@ var CodeMirror = (function() { // This mess creates the base DOM structure for the editor. wrapper.innerHTML = '
' + // Wraps and hides input textarea - '
' + '
' + '
' + // Set to the height of the text, causes scrolling '
' + // Moved around its parent to cover visible view '
' + // Provides positioning relative to (visible) text origin - '
' + - '
' + + '
' + + '
' + '
 
' + // Absolutely positioned blinky cursor - '
' + // This DIV contains the actual code + '
' + // DIVs containing the selection and the actual code '
'; if (place.appendChild) place.appendChild(wrapper); else place(wrapper); // I've never seen more elegant code in my life. @@ -40,11 +40,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, lineDiv = cursor.nextSibling; + cursor = measure.nextSibling, selectionDiv = cursor.nextSibling, + lineDiv = selectionDiv.nextSibling; themeChanged(); // Needed to hide big blue blinking cursor on Mobile Safari - if (/AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)) input.style.width = "0px"; + if (ios) input.style.width = "0px"; if (!webkit) lineSpace.draggable = true; + lineSpace.style.outline = "none"; if (options.tabindex != null) input.tabIndex = options.tabindex; if (!options.gutter && !options.lineNumbers) gutter.style.display = "none"; @@ -71,7 +73,8 @@ 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, draggingText, overwrite = false; + var shiftSelecting, lastClick, lastDoubleClick, lastScrollPos = 0, draggingText, + overwrite = false, suppressEdits = false; // Variables used by startOperation/endOperation to track what // happened during the operation. var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone, @@ -83,7 +86,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, tabText = computeTabText(); + var maxLine = "", maxWidth; // Initialize the content. operation(function(){setValue(options.value || ""); updateInput = false;})(); @@ -99,6 +102,7 @@ var CodeMirror = (function() { // 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); @@ -116,7 +120,9 @@ var CodeMirror = (function() { connect(scroller, "drop", operation(onDrop)); connect(scroller, "paste", function(){focusInput(); fastPoll();}); connect(input, "paste", fastPoll); - connect(input, "cut", operation(function(){replaceSelection("");})); + connect(input, "cut", operation(function(){ + if (!options.readOnly) replaceSelection(""); + })); // IE throws unspecified error in certain cases, when // trying to access activeElement before onload @@ -135,23 +141,30 @@ var CodeMirror = (function() { setValue: operation(setValue), getSelection: getSelection, replaceSelection: operation(replaceSelection), - focus: function(){focusInput(); onFocus(); fastPoll();}, + focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();}, setOption: function(option, value) { var oldVal = options[option]; options[option] = value; if (option == "mode" || option == "indentUnit") loadMode(); - else if (option == "readOnly" && value) {onBlur(); input.blur();} + else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();} + else if (option == "readOnly" && !value) {resetInput(true);} else if (option == "theme") themeChanged(); else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)(); - else if (option == "tabSize") operation(tabsChanged)(); - if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") - operation(gutterChanged)(); + else if (option == "tabSize") updateDisplay(true); + if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") { + gutterChanged(); + updateDisplay(true); + } }, getOption: function(option) {return options[option];}, undo: operation(undo), redo: operation(redo), indentLine: operation(function(n, dir) { - if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract"); + if (typeof dir != "string") { + if (dir == null) dir = options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(n)) indentLine(n, dir); }), indentSelection: operation(indentSelected), historySize: function() {return {undo: history.done.length, redo: history.undone.length};}, @@ -248,7 +261,15 @@ var CodeMirror = (function() { moveH: operation(moveH), deleteH: operation(deleteH), moveV: operation(moveV), - toggleOverwrite: function() {overwrite = !overwrite;}, + toggleOverwrite: function() { + if(overwrite){ + overwrite = false; + cursor.className = cursor.className.replace(" CodeMirror-overwrite", ""); + } else { + overwrite = true; + cursor.className += " CodeMirror-overwrite"; + } + }, posFromIndex: function(off) { var lineNo = 0, ch; @@ -268,9 +289,18 @@ var CodeMirror = (function() { }); return index; }, + scrollTo: function(x, y) { + if (x != null) scroller.scrollLeft = x; + if (y != null) scroller.scrollTop = y; + updateDisplay([]); + }, operation: function(f){return operation(f)();}, - refresh: function(){updateDisplay(true);}, + refresh: function(){ + updateDisplay(true); + if (scroller.scrollHeight > lastScrollPos) + scroller.scrollTop = lastScrollPos; + }, getInputField: function(){return input;}, getWrapperElement: function(){return wrapper;}, getScrollerElement: function(){return scroller;}, @@ -297,7 +327,7 @@ var CodeMirror = (function() { } function onMouseDown(e) { - setShift(e.shiftKey); + setShift(e_prop(e, "shiftKey")); // Check whether this is a click in a widget for (var n = e_target(e); n != wrapper; n = n.parentNode) if (n.parentNode == code && n != mover) return; @@ -339,7 +369,7 @@ var CodeMirror = (function() { } else { lastClick = {time: now, pos: start}; } var last = start, going; - if (dragAndDrop && !posEq(sel.from, sel.to) && + if (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; @@ -422,10 +452,10 @@ var CodeMirror = (function() { try { var text = e.dataTransfer.getData("Text"); if (text) { - var end = replaceRange(text, pos, pos); - var curFrom = sel.from, curTo = sel.to; - setSelectionUser(pos, end); + var curFrom = sel.from, curTo = sel.to; + setSelectionUser(pos, pos); if (draggingText) replaceRange("", curFrom, curTo); + replaceSelection(text); focusInput(); } } @@ -434,75 +464,103 @@ var CodeMirror = (function() { } function onDragStart(e) { var txt = getSelection(); - // This will reset escapeElement - htmlEscape(txt); - e.dataTransfer.setDragImage(escapeElement, 0, 0); + // Disabled until further notice. Doesn't work on most browsers, + // and crashes Safari (issue #332). + //htmlEscape(txt); + //e.dataTransfer.setDragImage(escapeElement, 0, 0); e.dataTransfer.setData("Text", txt); } - function handleKeyBinding(e) { - var name = keyNames[e.keyCode], next = keyMap[options.keyMap].auto, bound, dropShift; - if (name == null || e.altGraphKey) { - if (next) options.keyMap = next; - return null; - } - if (e.altKey) name = "Alt-" + name; - if (e.ctrlKey) name = "Ctrl-" + name; - if (e.metaKey) name = "Cmd-" + name; - if (e.shiftKey && (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) { - dropShift = true; - } else { - bound = lookupKey(name, options.extraKeys, options.keyMap); - } + + function doHandleBinding(bound, dropShift) { if (typeof bound == "string") { - if (commands.propertyIsEnumerable(bound)) bound = commands[bound]; - else bound = null; - } - if (next && (bound || !isModifierKey(e))) options.keyMap = next; - if (!bound) return false; - if (dropShift) { - var prevShift = shiftSelecting; - shiftSelecting = null; + bound = commands[bound]; + if (!bound) return false; + } + var prevShift = shiftSelecting; + try { + if (options.readOnly) suppressEdits = true; + if (dropShift) shiftSelecting = null; bound(instance); + } catch(e) { + if (e != Pass) throw e; + return false; + } finally { shiftSelecting = prevShift; - } else bound(instance); - e_preventDefault(e); + suppressEdits = false; + } return true; } - var lastStoppedKey = null; + function handleKeyBinding(e) { + // Handle auto keymap transitions + var startMap = getKeyMap(options.keyMap), next = startMap.auto; + clearTimeout(maybeTransition); + if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() { + if (getKeyMap(options.keyMap) == startMap) { + options.keyMap = (next.call ? next.call(null, instance) : next); + } + }, 50); + + var name = keyNames[e_prop(e, "keyCode")], handled = false; + if (name == null || e.altGraphKey) return false; + if (e_prop(e, "altKey")) name = "Alt-" + name; + if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name; + if (e_prop(e, "metaKey")) name = "Cmd-" + name; + + if (e_prop(e, "shiftKey")) + handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap, + function(b) {return doHandleBinding(b, true);}); + if (!handled) + handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding); + + if (handled) e_preventDefault(e); + return handled; + } + function handleCharBinding(e, ch) { + var handled = lookupKey("'" + ch + "'", options.extraKeys, + options.keyMap, doHandleBinding); + if (handled) e_preventDefault(e); + return handled; + } + + var lastStoppedKey = null, maybeTransition; function onKeyDown(e) { if (!focused) onFocus(); - var code = e.keyCode; + if (ie && e.keyCode == 27) { e.returnValue = false; } + if (pollingFast) { if (readInput()) pollingFast = false; } + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + var code = e_prop(e, "keyCode"); // IE does strange things with escape. - if (ie && code == 27) { e.returnValue = false; } - setShift(code == 16 || e.shiftKey); + setShift(code == 16 || e_prop(e, "shiftKey")); // First give onKeyEvent option a chance to handle this. - if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; var handled = handleKeyBinding(e); if (window.opera) { - lastStoppedKey = handled ? e.keyCode : null; + lastStoppedKey = handled ? code : null; // Opera has no cut event... we try to at least catch the key combo - if (!handled && (mac ? e.metaKey : e.ctrlKey) && e.keyCode == 88) + if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey")) replaceSelection(""); } } function onKeyPress(e) { - if (window.opera && e.keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if (pollingFast) readInput(); if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode"); + if (window.opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if (window.opera && !e.which && handleKeyBinding(e)) return; - if (options.electricChars && mode.electricChars) { - var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode); + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) { if (mode.electricChars.indexOf(ch) > -1) setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75); } + if (handleCharBinding(e, ch)) return; fastPoll(); } function onKeyUp(e) { if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; - if (e.keyCode == 16) shiftSelecting = null; + if (e_prop(e, "keyCode") == 16) shiftSelecting = null; } function onFocus() { - if (options.readOnly) return; + if (options.readOnly == "nocursor") return; if (!focused) { if (options.onFocus) options.onFocus(instance); focused = true; @@ -517,6 +575,10 @@ var CodeMirror = (function() { if (focused) { if (options.onBlur) options.onBlur(instance); focused = false; + if (bracketHighlighted) + operation(function(){ + if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; } + })(); wrapper.className = wrapper.className.replace(" CodeMirror-focused", ""); } clearInterval(blinker); @@ -526,6 +588,7 @@ var CodeMirror = (function() { // Replace the range from from to to by the strings in newText. // Afterwards, set the selection to selFrom, selTo. function updateLines(from, to, newText, selFrom, selTo) { + if (suppressEdits) return; if (history) { var old = []; doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); }); @@ -535,21 +598,25 @@ var CodeMirror = (function() { updateLinesNoUndo(from, to, newText, selFrom, selTo); } function unredoHelper(from, to) { - var change = from.pop(); - if (change) { + if (!from.length) return; + var set = from.pop(), out = []; + for (var i = set.length - 1; i >= 0; i -= 1) { + var change = set[i]; var replaced = [], end = change.start + change.added; doc.iter(change.start, end, function(line) { replaced.push(line.text); }); - to.push({start: change.start, added: change.old.length, old: replaced}); + out.push({start: change.start, added: change.old.length, old: replaced}); var pos = clipPos({line: change.start + change.old.length - 1, ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])}); updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos); - updateInput = true; } + updateInput = true; + to.push(out); } function undo() {unredoHelper(history.done, history.undone);} function redo() {unredoHelper(history.undone, history.done);} function updateLinesNoUndo(from, to, newText, selFrom, selTo) { + if (suppressEdits) return; var recomputeMaxLength = false, maxLineLength = maxLine.length; if (!options.lineWrapping) doc.iter(from.line, to.line, function(line) { @@ -651,7 +718,8 @@ var CodeMirror = (function() { setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line)); // Make sure the scroll-size div has the correct height. - code.style.height = (doc.height * textHeight() + 2 * paddingTop()) + "px"; + if (scroller.clientHeight) + code.style.height = (doc.height * textHeight() + 2 * paddingTop()) + "px"; } function replaceRange(code, from, to) { @@ -729,7 +797,7 @@ var CodeMirror = (function() { // supported or compatible enough yet to rely on.) var prevInput = ""; function readInput() { - if (leaveInputAlone || !focused || hasSelection(input)) return false; + if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false; var text = input.value; if (text == prevInput) return false; shiftSelecting = null; @@ -747,12 +815,12 @@ var CodeMirror = (function() { if (!posEq(sel.from, sel.to)) { prevInput = ""; input.value = getSelection(); - input.select(); + selectInput(input); } else if (user) prevInput = input.value = ""; } function focusInput() { - if (!options.readOnly) input.focus(); + if (options.readOnly != "nocursor") input.focus(); } function scrollEditorIntoView() { @@ -809,7 +877,7 @@ var CodeMirror = (function() { // Compute the new visible window var visible = visibleLines(); // Bail out if the visible area is already rendered and nothing changed. - if (changes !== true && changes.length == 0 && visible.from >= showingFrom && visible.to <= showingTo) return; + if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) return; var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100); if (showingFrom < from && from - showingFrom < 20) from = showingFrom; if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo); @@ -831,9 +899,9 @@ var CodeMirror = (function() { intact.sort(function(a, b) {return a.domStart - b.domStart;}); var th = textHeight(), gutterDisplay = gutter.style.display; - lineDiv.style.display = gutter.style.display = "none"; + lineDiv.style.display = "none"; patchDisplay(from, to, intact); - lineDiv.style.display = ""; + lineDiv.style.display = gutter.style.display = ""; // Position the mover div to align with the lines it's supposed // to be showing (which will cover the visible display) @@ -844,7 +912,8 @@ var CodeMirror = (function() { showingFrom = from; showingTo = to; displayOffset = heightAtLine(doc, from); mover.style.top = (displayOffset * th) + "px"; - code.style.height = (doc.height * th + 2 * paddingTop()) + "px"; + if (scroller.clientHeight) + code.style.height = (doc.height * th + 2 * paddingTop()) + "px"; // Since this is all rather error prone, it is honoured with the // only assertion in the whole file. @@ -854,14 +923,19 @@ var CodeMirror = (function() { if (options.lineWrapping) { maxWidth = scroller.clientWidth; - var curNode = lineDiv.firstChild; + var curNode = lineDiv.firstChild, heightChanged = false; doc.iter(showingFrom, showingTo, function(line) { if (!line.hidden) { var height = Math.round(curNode.offsetHeight / th) || 1; - if (line.height != height) {updateLineHeight(line, height); gutterDirty = true;} + if (line.height != height) { + updateLineHeight(line, height); + gutterDirty = heightChanged = true; + } } curNode = curNode.nextSibling; }); + if (heightChanged) + code.style.height = (doc.height * th + 2 * paddingTop()) + "px"; } else { if (maxWidth == null) maxWidth = stringWidth(maxLine); if (maxWidth > scroller.clientWidth) { @@ -875,7 +949,7 @@ var CodeMirror = (function() { } gutter.style.display = gutterDisplay; if (different || gutterDirty) updateGutter(); - updateCursor(); + updateSelection(); if (!suppressCallback && options.onUpdate) options.onUpdate(instance); return true; } @@ -922,21 +996,19 @@ var CodeMirror = (function() { } // This pass fills in the lines that actually changed. var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from; - var sfrom = sel.from.line, sto = sel.to.line, inSel = sfrom < from && sto >= from; var scratch = targetDocument.createElement("div"), newElt; doc.iter(from, to, function(line) { - var ch1 = null, ch2 = null; - if (inSel) { - ch1 = 0; - if (sto == j) {inSel = false; ch2 = sel.to.ch;} - } else if (sfrom == j) { - if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;} - else {inSel = true; ch1 = sel.from.ch;} - } if (nextIntact && nextIntact.to == j) nextIntact = intact.shift(); if (!nextIntact || nextIntact.from > j) { - if (line.hidden) scratch.innerHTML = "
";
-          else scratch.innerHTML = line.getHTML(ch1, ch2, true, tabText);
+          if (line.hidden) var html = scratch.innerHTML = "
";
+          else {
+            var html = '
' + line.getHTML(makeTab) + '
'; + // Kludge to make sure the styled element lies behind the selection (by z-index) + if (line.className) + html = '
 
' + html + "
"; + } + scratch.innerHTML = html; lineDiv.insertBefore(scratch.firstChild, curNode); } else { curNode = curNode.nextSibling; @@ -975,18 +1047,39 @@ var CodeMirror = (function() { lineSpace.style.marginLeft = gutter.offsetWidth + "px"; gutterDirty = false; } - function updateCursor() { - var head = sel.inverted ? sel.from : sel.to, lh = textHeight(); - var pos = localCoords(head, true); + function updateSelection() { + var collapsed = posEq(sel.from, sel.to); + var fromPos = localCoords(sel.from, true); + var toPos = collapsed ? fromPos : localCoords(sel.to, true); + var headPos = sel.inverted ? fromPos : toPos, th = textHeight(); var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv); - inputDiv.style.top = (pos.y + lineOff.top - wrapOff.top) + "px"; - inputDiv.style.left = (pos.x + lineOff.left - wrapOff.left) + "px"; - if (posEq(sel.from, sel.to)) { - cursor.style.top = pos.y + "px"; - cursor.style.left = (options.lineWrapping ? Math.min(pos.x, lineSpace.offsetWidth) : pos.x) + "px"; + inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px"; + inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px"; + if (collapsed) { + cursor.style.top = headPos.y + "px"; + cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px"; cursor.style.display = ""; + selectionDiv.style.display = "none"; + } else { + var sameLine = fromPos.y == toPos.y, html = ""; + function add(left, top, right, height) { + html += '
'; + } + if (sel.from.ch && fromPos.y >= 0) { + var right = sameLine ? lineSpace.clientWidth - toPos.x : 0; + add(fromPos.x, fromPos.y, right, th); + } + var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0)); + var middleHeight = Math.min(toPos.y, lineSpace.clientHeight) - middleStart; + if (middleHeight > 0.2 * th) + add(0, middleStart, 0, middleHeight); + if ((!sameLine || !sel.from.ch) && toPos.y < lineSpace.clientHeight - .5 * th) + add(0, toPos.y, lineSpace.clientWidth - toPos.x, th); + selectionDiv.innerHTML = html; + cursor.style.display = "none"; + selectionDiv.style.display = ""; } - else cursor.style.display = "none"; } function setShift(val) { @@ -1019,30 +1112,20 @@ var CodeMirror = (function() { else if (posEq(from, sel.to)) sel.inverted = false; else if (posEq(to, sel.from)) sel.inverted = true; - // Some ugly logic used to only mark the lines that actually did - // see a change in selection as changed, rather than the whole - // selected range. - if (posEq(from, to)) { - if (!posEq(sel.from, sel.to)) - changes.push({from: oldFrom, to: oldTo + 1}); - } - else if (posEq(sel.from, sel.to)) { - changes.push({from: from.line, to: to.line + 1}); - } - else { - if (!posEq(from, sel.from)) { - if (from.line < oldFrom) - changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1}); - else - changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1}); - } - if (!posEq(to, sel.to)) { - if (to.line < oldTo) - changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1}); - else - changes.push({from: Math.max(from.line, oldTo), to: to.line + 1}); + if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) { + var head = sel.inverted ? from : to; + if (head.line != sel.from.line) { + var oldLine = getLine(sel.from.line); + if (/^\s+$/.test(oldLine.text)) + setTimeout(operation(function() { + if (oldLine.parent && /^\s+$/.test(oldLine.text)) { + var no = lineNo(oldLine); + replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length}); + } + }, 10)); } } + sel.from = from; sel.to = to; selectionChanged = true; } @@ -1123,7 +1206,7 @@ var CodeMirror = (function() { function moveV(dir, unit) { var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true); if (goalColumn != null) pos.x = goalColumn; - if (unit == "page") dist = scroller.clientHeight; + if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight); else if (unit == "line") dist = textHeight(); var target = coordsChar(pos.x, pos.y + dist * dir + 2); setCursor(target.line, target.ch, true); @@ -1138,7 +1221,7 @@ var CodeMirror = (function() { setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end}); } function selectLine(line) { - setSelectionUser({line: line, ch: 0}, {line: line, ch: getLine(line).text.length}); + setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0})); } function indentSelected(mode) { if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode); @@ -1211,13 +1294,10 @@ var CodeMirror = (function() { } changes.push({from: 0, to: doc.size}); } - function computeTabText() { - for (var str = '', i = 0; i < options.tabSize; ++i) str += " "; - return str + ""; - } - function tabsChanged() { - tabText = computeTabText(); - updateDisplay(true); + function makeTab(col) { + var w = options.tabSize - col % options.tabSize; + for (var str = '', i = 0; i < w; ++i) str += " "; + return {html: str + "", width: w}; } function themeChanged() { scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") + @@ -1316,9 +1396,12 @@ var CodeMirror = (function() { if (line.hidden != hidden) { line.hidden = hidden; updateLineHeight(line, hidden ? 0 : 1); - if (hidden && (sel.from.line == no || sel.to.line == no)) - setSelection(skipHidden(sel.from, sel.from.line, sel.from.ch), - skipHidden(sel.to, sel.to.line, sel.to.ch)); + var fline = sel.from.line, tline = sel.to.line; + if (hidden && (fline == no || tline == no)) { + var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from; + var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to; + setSelection(from, to); + } return (gutterDirty = true); } }); @@ -1351,7 +1434,7 @@ var CodeMirror = (function() { if (x <= 0) return 0; var lineObj = getLine(line), text = lineObj.text; function getX(len) { - measure.innerHTML = "
" + lineObj.getHTML(null, null, false, tabText, len) + "
"; +