diff --git a/gulliver/js/codemirror/.gitattributes b/gulliver/js/codemirror/.gitattributes
new file mode 100644
index 000000000..f8bdd60f4
--- /dev/null
+++ b/gulliver/js/codemirror/.gitattributes
@@ -0,0 +1,8 @@
+*.txt text
+*.js text
+*.html text
+*.md text
+*.json text
+*.yml text
+*.css text
+*.svg text
diff --git a/gulliver/js/codemirror/.gitignore b/gulliver/js/codemirror/.gitignore
new file mode 100644
index 000000000..b471fe6e6
--- /dev/null
+++ b/gulliver/js/codemirror/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/npm-debug.log
+test.html
+.tern-*
+*~
+*.swp
diff --git a/gulliver/js/codemirror/.travis.yml b/gulliver/js/codemirror/.travis.yml
new file mode 100644
index 000000000..baa0031d5
--- /dev/null
+++ b/gulliver/js/codemirror/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - 0.8
diff --git a/gulliver/js/codemirror/AUTHORS b/gulliver/js/codemirror/AUTHORS
new file mode 100644
index 000000000..737acedab
--- /dev/null
+++ b/gulliver/js/codemirror/AUTHORS
@@ -0,0 +1,300 @@
+List of CodeMirror contributors. Updated before every release.
+
+4r2r
+Aaron Brooks
+Abe Fettig
+Adam King
+adanlobato
+Adán Lobato
+aeroson
+Ahmad Amireh
+Ahmad M. Zawawi
+ahoward
+Akeksandr Motsjonov
+Alberto Pose
+Albert Xing
+Alexander Pavlov
+Alexander Schepanovski
+Alexander Solovyov
+alexey-k
+Alex Piggott
+Amy
+Ananya Sen
+AndersMad
+Anderson Mesquita
+Andre von Houck
+Andrey Lushnikov
+Andy Joslin
+Andy Kimball
+Andy Li
+angelozerr
+angelo.zerr@gmail.com
+Ankit Ahuja
+Ansel Santosa
+Anthony Grimes
+Anton Kovalyov
+areos
+AtomicPages LLC
+Atul Bhouraskar
+Aurelian Oancea
+Bastian Müller
+benbro
+Beni Cherniavsky-Paskin
+Benjamin DeCoste
+Ben Keen
+boomyjee
+borawjm
+Brandon Frohs
+Brandon Wamboldt
+Brett Zamir
+Brian Sletten
+Bruce Mitchener
+Chandra Sekhar Pydi
+Charles Skelton
+Chris Coyier
+Chris Granger
+Chris Morgan
+Christopher Brown
+ciaranj
+CodeAnimal
+ComFreek
+dagsta
+Dan Heberden
+Daniel, Dao Quang Minh
+Daniel Faust
+Daniel Huigens
+Daniel KJ
+Daniel Neel
+Daniel Parnell
+Danny Yoo
+Darius Roberts
+David Mignot
+David Pathakjee
+deebugger
+Deep Thought
+Dominator008
+Domizio Demichelis
+Drew Bratcher
+Drew Hintz
+Drew Khoury
+Dror BG
+duralog
+eborden
+edsharp
+ekhaled
+Enam Mijbah Noor
+Eric Allam
+eustas
+Fabio Zendhi Nagao
+Fauntleroy
+fbuchinger
+feizhang365
+Felipe Lalanne
+Felix Raab
+Filip Noetzel
+flack
+ForbesLindesay
+Forbes Lindesay
+Ford_Lawnmower
+Gabriel Nahmias
+galambalazs
+Gautam Mehta
+Glenn Jorde
+Glenn Ruehle
+Golevka
+Gordon Smith
+greengiant
+Guillaume Massé
+Guillaume Massé
+Hans Engel
+Hardest
+Hasan Karahan
+hitsthings
+Hocdoc
+Ian Beck
+Ian Dickinson
+Ian Wehrman
+Ian Wetherbee
+Ice White
+ICHIKAWA, Yuji
+ilvalle
+Ingo Richter
+Irakli Gozalishvili
+Ivan Kurnosov
+Jacob Lee
+Jakub Vrana
+James Campos
+James Thorne
+Jamie Hill
+Jan Jongboom
+jankeromnes
+Jan Keromnes
+Jan Odvarko
+Jan T. Sott
+Jason
+Jason Grout
+Jason Johnston
+Jason San Jose
+Jason Siefken
+Jean Boussier
+jeffkenton
+Jeff Pickhardt
+jem (graphite)
+Jochen Berger
+Johan Ask
+John Connor
+John Lees-Miller
+John Snelson
+John Van Der Loo
+jongalloway
+Jon Malmaud
+Joost-Wim Boekesteijn
+Joseph Pecoraro
+Joshua Newman
+jots
+jsoojeon
+Juan Benavides Romero
+Jucovschi Constantin
+Juho Vuori
+jwallers@gmail.com
+kaniga
+Ken Newman
+Ken Rockot
+Kevin Sawicki
+Klaus Silveira
+Koh Zi Han, Cliff
+komakino
+Konstantin Lopuhin
+koops
+ks-ifware
+kubelsmieci
+Lanny
+Laszlo Vidacs
+leaf corcoran
+Leonya Khachaturov
+Liam Newman
+LM
+Lorenzo Stoakes
+Luciano Longo
+lynschinzer
+Maksim Lin
+Maksym Taran
+Marat Dreizin
+Marco Aurélio
+Marijn Haverbeke
+Mario Pietsch
+Mark Lentczner
+Marko Bonaci
+Martin Balek
+Martín Gaitán
+Martin Hasoň
+Mason Malone
+Mateusz Paprocki
+mats cronqvist
+Matthew Beale
+Matthias BUSSONNIER
+Matt McDonald
+Matt Pass
+Matt Sacks
+Maximilian Hils
+Maxim Kraev
+Max Kirsch
+mbarkhau
+Metatheos
+Micah Dubinko
+Michael Lehenbauer
+Michael Zhou
+Mighty Guava
+Miguel Castillo
+Mike
+Mike Brevoort
+Mike Diaz
+Mike Ivanov
+Mike Kadin
+MinRK
+Miraculix87
+misfo
+mloginov
+mps
+Narciso Jaramillo
+Nathan Williams
+nerbert
+nguillaumin
+Niels van Groningen
+Nikita Beloglazov
+Nikita Vasilyev
+Nikolay Kostov
+nlwillia
+pablo
+Page
+Patrick Strawderman
+Paul Garvin
+Paul Ivanov
+Pavel Feldman
+Pavel Strashkin
+Paweł Bartkiewicz
+peteguhl
+peterkroon
+Peter Kroon
+prasanthj
+Prasanth J
+Rahul
+Randy Edmunds
+Richard Z.H. Wang
+robertop23
+Robert Plummer
+Ruslan Osmanov
+sabaca
+Samuel Ainsworth
+sandeepshetty
+santec
+Sascha Peilicke
+satchmorun
+sathyamoorthi
+SCLINIC\jdecker
+Sebastian Zaha
+shaund
+shaun gilchrist
+Shawn A
+Shiv Deepak
+Shmuel Englard
+soliton4
+sonson
+spastorelli
+Stanislav Oaserele
+Stas Kobzar
+Stefan Borsje
+Steffen Beyer
+Steve O'Hara
+stoskov
+Taha Jahangir
+Tarmil
+tfjgeorge
+Thaddee Tyl
+think
+Thomas Dvornik
+Thomas Schmid
+Tim Baumann
+Timothy Farrell
+Timothy Hatcher
+TobiasBg
+Tomas-A
+Tomas Varaneckas
+Tom Erik Støwer
+Tom MacWright
+Tony Jian
+Travis Heppe
+Vestimir Markov
+vf
+Volker Mische
+wenli
+Wesley Wiser
+William Jamieson
+Wojtek Ptak
+Xavier Mendez
+YNH Webdev
+Yunchi Luo
+Yuvi Panda
+Zachary Dremann
+zziuni
+魏鹏刚
diff --git a/gulliver/js/codemirror/CONTRIBUTING.md b/gulliver/js/codemirror/CONTRIBUTING.md
index afc18373c..8938f6204 100644
--- a/gulliver/js/codemirror/CONTRIBUTING.md
+++ b/gulliver/js/codemirror/CONTRIBUTING.md
@@ -4,12 +4,12 @@
- [Submitting bug reports](#submitting-bug-reports-)
- [Contributing code](#contributing-code-)
-## Getting help [^](#how-to-contribute)
+## Getting help
Community discussion, questions, and informal bug reporting is done on the
[CodeMirror Google group](http://groups.google.com/group/codemirror).
-## Submitting bug reports [^](#how-to-contribute)
+## Submitting bug reports
The preferred way to report bugs is to use the
[GitHub issue tracker](http://github.com/marijnh/CodeMirror/issues). Before
@@ -45,7 +45,7 @@ should be asked on the
[jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and
include the resulting link in your bug report.
-## Contributing code [^](#how-to-contribute)
+## Contributing code
- Make sure you have a [GitHub Account](https://github.com/signup/free)
- Fork [CodeMirror](https://github.com/marijnh/CodeMirror/)
@@ -56,6 +56,8 @@ should be asked on the
test suite under `mode/XXX/test.js`. Feel free to add new test
suites to modes that don't have one yet (be sure to link the new
tests into `test/index.html`).
+- Follow the general code style of the rest of the project (see
+ below). Run `bin/lint` to verify that the linter is happy.
- Make sure all tests pass. Visit `test/index.html` in your browser to
run them.
- Submit a pull request
@@ -65,6 +67,6 @@ should be asked on the
- 2 spaces per indentation level, no tabs.
- Include semicolons after statements.
-- Note that the linter (`test/lint/lint.js`) which is run after each
- commit complains about unused variables and functions. Prefix their
- names with an underscore to muffle it.
+- Note that the linter (`bin/lint`) which is run after each commit
+ complains about unused variables and functions. Prefix their names
+ with an underscore to muffle it.
diff --git a/gulliver/js/codemirror/LICENSE b/gulliver/js/codemirror/LICENSE
index 482d55eb7..442d11cdc 100644
--- a/gulliver/js/codemirror/LICENSE
+++ b/gulliver/js/codemirror/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2013 by Marijn Haverbeke
+Copyright (C) 2013 by Marijn Haverbeke and others
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -17,7 +17,3 @@ 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/gulliver/js/codemirror/README.md b/gulliver/js/codemirror/README.md
index 976584e3b..61f6b6452 100644
--- a/gulliver/js/codemirror/README.md
+++ b/gulliver/js/codemirror/README.md
@@ -1,4 +1,6 @@
-# CodeMirror [](http://travis-ci.org/marijnh/CodeMirror)
+# CodeMirror
+[](http://travis-ci.org/marijnh/CodeMirror)
+[](http://badge.fury.io/js/codemirror)
CodeMirror is a JavaScript component that provides a code editor in
the browser. When a mode is available for the language you are coding
diff --git a/gulliver/js/codemirror/addon/comment/comment.js b/gulliver/js/codemirror/addon/comment/comment.js
new file mode 100644
index 000000000..5975b0bf6
--- /dev/null
+++ b/gulliver/js/codemirror/addon/comment/comment.js
@@ -0,0 +1,149 @@
+(function() {
+ "use strict";
+
+ var noOptions = {};
+ var nonWS = /[^\s\u00a0]/;
+ var Pos = CodeMirror.Pos;
+
+ function firstNonWS(str) {
+ var found = str.search(nonWS);
+ return found == -1 ? 0 : found;
+ }
+
+ CodeMirror.commands.toggleComment = function(cm) {
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
+ cm.uncomment(from, to) || cm.lineComment(from, to);
+ };
+
+ CodeMirror.defineExtension("lineComment", function(from, to, options) {
+ if (!options) options = noOptions;
+ var self = this, mode = self.getModeAt(from);
+ var commentString = options.lineComment || mode.lineComment;
+ if (!commentString) {
+ if (options.blockCommentStart || mode.blockCommentStart) {
+ options.fullLines = true;
+ self.blockComment(from, to, options);
+ }
+ return;
+ }
+ var firstLine = self.getLine(from.line);
+ if (firstLine == null) return;
+ var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
+ var pad = options.padding == null ? " " : options.padding;
+ var blankLines = options.commentBlankLines || from.line == to.line;
+
+ self.operation(function() {
+ if (options.indent) {
+ var baseString = firstLine.slice(0, firstNonWS(firstLine));
+ for (var i = from.line; i < end; ++i) {
+ var line = self.getLine(i), cut = baseString.length;
+ if (!blankLines && !nonWS.test(line)) continue;
+ if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
+ self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
+ }
+ } else {
+ for (var i = from.line; i < end; ++i) {
+ if (blankLines || nonWS.test(self.getLine(i)))
+ self.replaceRange(commentString + pad, Pos(i, 0));
+ }
+ }
+ });
+ });
+
+ CodeMirror.defineExtension("blockComment", function(from, to, options) {
+ if (!options) options = noOptions;
+ var self = this, mode = self.getModeAt(from);
+ var startString = options.blockCommentStart || mode.blockCommentStart;
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
+ if (!startString || !endString) {
+ if ((options.lineComment || mode.lineComment) && options.fullLines != false)
+ self.lineComment(from, to, options);
+ return;
+ }
+
+ var end = Math.min(to.line, self.lastLine());
+ if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
+
+ var pad = options.padding == null ? " " : options.padding;
+ if (from.line > end) return;
+
+ self.operation(function() {
+ if (options.fullLines != false) {
+ var lastLineHasText = nonWS.test(self.getLine(end));
+ self.replaceRange(pad + endString, Pos(end));
+ self.replaceRange(startString + pad, Pos(from.line, 0));
+ var lead = options.blockCommentLead || mode.blockCommentLead;
+ if (lead != null) for (var i = from.line + 1; i <= end; ++i)
+ if (i != end || lastLineHasText)
+ self.replaceRange(lead + pad, Pos(i, 0));
+ } else {
+ self.replaceRange(endString, to);
+ self.replaceRange(startString, from);
+ }
+ });
+ });
+
+ CodeMirror.defineExtension("uncomment", function(from, to, options) {
+ if (!options) options = noOptions;
+ var self = this, mode = self.getModeAt(from);
+ var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);
+
+ // Try finding line comments
+ var lineString = options.lineComment || mode.lineComment, lines = [];
+ var pad = options.padding == null ? " " : options.padding, didSomething;
+ lineComment: {
+ if (!lineString) break lineComment;
+ for (var i = start; i <= end; ++i) {
+ var line = self.getLine(i);
+ var found = line.indexOf(lineString);
+ if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
+ if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment;
+ if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
+ lines.push(line);
+ }
+ self.operation(function() {
+ for (var i = start; i <= end; ++i) {
+ var line = lines[i - start];
+ var pos = line.indexOf(lineString), endPos = pos + lineString.length;
+ if (pos < 0) continue;
+ if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
+ didSomething = true;
+ self.replaceRange("", Pos(i, pos), Pos(i, endPos));
+ }
+ });
+ if (didSomething) return true;
+ }
+
+ // Try block comments
+ var startString = options.blockCommentStart || mode.blockCommentStart;
+ var endString = options.blockCommentEnd || mode.blockCommentEnd;
+ if (!startString || !endString) return false;
+ var lead = options.blockCommentLead || mode.blockCommentLead;
+ var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end);
+ var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString);
+ if (close == -1 && start != end) {
+ endLine = self.getLine(--end);
+ close = endLine.lastIndexOf(endString);
+ }
+ if (open == -1 || close == -1 ||
+ !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
+ !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
+ return false;
+
+ self.operation(function() {
+ self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
+ Pos(end, close + endString.length));
+ var openEnd = open + startString.length;
+ if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
+ self.replaceRange("", Pos(start, open), Pos(start, openEnd));
+ if (lead) for (var i = start + 1; i <= end; ++i) {
+ var line = self.getLine(i), found = line.indexOf(lead);
+ if (found == -1 || nonWS.test(line.slice(0, found))) continue;
+ var foundEnd = found + lead.length;
+ if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
+ self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
+ }
+ });
+ return true;
+ });
+})();
diff --git a/gulliver/js/codemirror/addon/comment/continuecomment.js b/gulliver/js/codemirror/addon/comment/continuecomment.js
new file mode 100644
index 000000000..a3370a607
--- /dev/null
+++ b/gulliver/js/codemirror/addon/comment/continuecomment.js
@@ -0,0 +1,54 @@
+(function() {
+ var modes = ["clike", "css", "javascript"];
+ for (var i = 0; i < modes.length; ++i)
+ CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
+
+ function continueComment(cm) {
+ var pos = cm.getCursor(), token = cm.getTokenAt(pos);
+ if (token.type != "comment" || cm.getOption("disableInput")) return CodeMirror.Pass;
+ var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode;
+
+ var insert;
+ if (mode.blockCommentStart && mode.blockCommentContinue) {
+ var end = token.string.indexOf(mode.blockCommentEnd);
+ var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
+ if (end != -1 && end == token.string.length - mode.blockCommentEnd.length) {
+ // Comment ended, don't continue it
+ } else if (token.string.indexOf(mode.blockCommentStart) == 0) {
+ insert = full.slice(0, token.start);
+ if (!/^\s*$/.test(insert)) {
+ insert = "";
+ for (var i = 0; i < token.start; ++i) insert += " ";
+ }
+ } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
+ found + mode.blockCommentContinue.length > token.start &&
+ /^\s*$/.test(full.slice(0, found))) {
+ insert = full.slice(0, found);
+ }
+ if (insert != null) insert += mode.blockCommentContinue;
+ }
+ if (insert == null && mode.lineComment) {
+ var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
+ if (found > -1) {
+ insert = line.slice(0, found);
+ if (/\S/.test(insert)) insert = null;
+ else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
+ }
+ }
+
+ if (insert != null)
+ cm.replaceSelection("\n" + insert, "end");
+ else
+ return CodeMirror.Pass;
+ }
+
+ CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
+ if (prev && prev != CodeMirror.Init)
+ cm.removeKeyMap("continueComment");
+ if (val) {
+ var map = {name: "continueComment"};
+ map[typeof val == "string" ? val : "Enter"] = continueComment;
+ cm.addKeyMap(map);
+ }
+ });
+})();
diff --git a/gulliver/js/codemirror/addon/dialog/dialog.js b/gulliver/js/codemirror/addon/dialog/dialog.js
index 71e228744..41d7bf866 100644
--- a/gulliver/js/codemirror/addon/dialog/dialog.js
+++ b/gulliver/js/codemirror/addon/dialog/dialog.js
@@ -10,11 +10,22 @@
} else {
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
}
- dialog.innerHTML = template;
+ if (typeof template == "string") {
+ dialog.innerHTML = template;
+ } else { // Assuming it's a detached DOM element.
+ dialog.appendChild(template);
+ }
return dialog;
}
+ function closeNotification(cm, newVal) {
+ if (cm.state.currentNotificationClose)
+ cm.state.currentNotificationClose();
+ cm.state.currentNotificationClose = newVal;
+ }
+
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
+ closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var closed = false, me = this;
function close() {
@@ -24,6 +35,7 @@
}
var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) {
+ if (options && options.value) inp.value = options.value;
CodeMirror.on(inp, "keydown", function(e) {
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
if (e.keyCode == 13 || e.keyCode == 27) {
@@ -51,6 +63,7 @@
});
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
+ closeNotification(this, null);
var dialog = dialogDiv(this, template, options && options.bottom);
var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1;
@@ -77,4 +90,33 @@
CodeMirror.on(b, "focus", function() { ++blurring; });
}
});
+
+ /*
+ * openNotification
+ * Opens a notification, that can be closed with an optional timer
+ * (default 5000ms timer) and always closes on click.
+ *
+ * If a notification is opened while another is opened, it will close the
+ * currently opened one and open the new one immediately.
+ */
+ CodeMirror.defineExtension("openNotification", function(template, options) {
+ closeNotification(this, close);
+ var dialog = dialogDiv(this, template, options && options.bottom);
+ var duration = options && (options.duration === undefined ? 5000 : options.duration);
+ var closed = false, doneTimer;
+
+ function close() {
+ if (closed) return;
+ closed = true;
+ clearTimeout(doneTimer);
+ dialog.parentNode.removeChild(dialog);
+ }
+
+ CodeMirror.on(dialog, 'click', function(e) {
+ CodeMirror.e_preventDefault(e);
+ close();
+ });
+ if (duration)
+ doneTimer = setTimeout(close, options.duration);
+ });
})();
diff --git a/gulliver/js/codemirror/addon/display/fullscreen.css b/gulliver/js/codemirror/addon/display/fullscreen.css
new file mode 100644
index 000000000..437acd89b
--- /dev/null
+++ b/gulliver/js/codemirror/addon/display/fullscreen.css
@@ -0,0 +1,6 @@
+.CodeMirror-fullscreen {
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ height: auto;
+ z-index: 9;
+}
diff --git a/gulliver/js/codemirror/addon/display/fullscreen.js b/gulliver/js/codemirror/addon/display/fullscreen.js
new file mode 100644
index 000000000..a442f6a43
--- /dev/null
+++ b/gulliver/js/codemirror/addon/display/fullscreen.js
@@ -0,0 +1,31 @@
+(function() {
+ "use strict";
+
+ CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
+ if (old == CodeMirror.Init) old = false;
+ if (!old == !val) return;
+ if (val) setFullscreen(cm);
+ else setNormal(cm);
+ });
+
+ function setFullscreen(cm) {
+ var wrap = cm.getWrapperElement();
+ cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
+ width: wrap.style.width, height: wrap.style.height};
+ wrap.style.width = "";
+ wrap.style.height = "auto";
+ wrap.className += " CodeMirror-fullscreen";
+ document.documentElement.style.overflow = "hidden";
+ cm.refresh();
+ }
+
+ function setNormal(cm) {
+ var wrap = cm.getWrapperElement();
+ wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
+ document.documentElement.style.overflow = "";
+ var info = cm.state.fullScreenRestore;
+ wrap.style.width = info.width; wrap.style.height = info.height;
+ window.scrollTo(info.scrollLeft, info.scrollTop);
+ cm.refresh();
+ }
+})();
diff --git a/gulliver/js/codemirror/addon/display/placeholder.js b/gulliver/js/codemirror/addon/display/placeholder.js
index f85f2df12..748afe727 100644
--- a/gulliver/js/codemirror/addon/display/placeholder.js
+++ b/gulliver/js/codemirror/addon/display/placeholder.js
@@ -2,12 +2,10 @@
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
- cm.on("focus", onFocus);
cm.on("blur", onBlur);
cm.on("change", onChange);
onChange(cm);
} else if (!val && prev) {
- cm.off("focus", onFocus);
cm.off("blur", onBlur);
cm.off("change", onChange);
clearPlaceholder(cm);
@@ -19,23 +17,20 @@
});
function clearPlaceholder(cm) {
- if (cm._placeholder) {
- cm._placeholder.parentNode.removeChild(cm._placeholder);
- cm._placeholder = null;
+ if (cm.state.placeholder) {
+ cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
+ cm.state.placeholder = null;
}
}
function setPlaceholder(cm) {
clearPlaceholder(cm);
- var elt = cm._placeholder = document.createElement("pre");
+ var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible";
elt.className = "CodeMirror-placeholder";
elt.appendChild(document.createTextNode(cm.getOption("placeholder")));
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
}
- function onFocus(cm) {
- clearPlaceholder(cm);
- }
function onBlur(cm) {
if (isEmpty(cm)) setPlaceholder(cm);
}
@@ -43,7 +38,6 @@
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
- if (cm.hasFocus()) return;
if (empty) setPlaceholder(cm);
else clearPlaceholder(cm);
}
diff --git a/gulliver/js/codemirror/addon/edit/closebrackets.js b/gulliver/js/codemirror/addon/edit/closebrackets.js
index b46caca02..0575222be 100644
--- a/gulliver/js/codemirror/addon/edit/closebrackets.js
+++ b/gulliver/js/codemirror/addon/edit/closebrackets.js
@@ -1,34 +1,47 @@
(function() {
var DEFAULT_BRACKETS = "()[]{}''\"\"";
+ var DEFAULT_EXPLODE_ON_ENTER = "[]{}";
var SPACE_CHAR_REGEX = /\s/;
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
- var wasOn = old && old != CodeMirror.Init;
- if (val && !wasOn)
- cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS));
- else if (!val && wasOn)
+ if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseBrackets");
+ if (!val) return;
+ var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
+ if (typeof val == "string") pairs = val;
+ else if (typeof val == "object") {
+ if (val.pairs != null) pairs = val.pairs;
+ if (val.explode != null) explode = val.explode;
+ }
+ var map = buildKeymap(pairs);
+ if (explode) map.Enter = buildExplodeHandler(explode);
+ cm.addKeyMap(map);
});
+ function charsAround(cm, pos) {
+ var str = cm.getRange(CodeMirror.Pos(pos.line, pos.ch - 1),
+ CodeMirror.Pos(pos.line, pos.ch + 1));
+ return str.length == 2 ? str : null;
+ }
+
function buildKeymap(pairs) {
var map = {
name : "autoCloseBrackets",
Backspace: function(cm) {
- if (cm.somethingSelected()) return CodeMirror.Pass;
- var cur = cm.getCursor(), line = cm.getLine(cur.line);
- if (cur.ch && cur.ch < line.length &&
- pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0)
+ if (cm.somethingSelected() || cm.getOption("disableInput")) return CodeMirror.Pass;
+ var cur = cm.getCursor(), around = charsAround(cm, cur);
+ if (around && pairs.indexOf(around) % 2 == 0)
cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1));
else
return CodeMirror.Pass;
}
};
- var closingBrackets = [];
+ var closingBrackets = "";
for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
- if (left != right) closingBrackets.push(right);
+ if (left != right) closingBrackets += right;
function surround(cm) {
- var selection = cm.getSelection();
- cm.replaceSelection(left + selection + right);
+ var selection = cm.getSelection();
+ cm.replaceSelection(left + selection + right);
}
function maybeOverwrite(cm) {
var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1));
@@ -36,10 +49,15 @@
else cm.execCommand("goCharRight");
}
map["'" + left + "'"] = function(cm) {
+ if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment" ||
+ cm.getOption("disableInput"))
+ return CodeMirror.Pass;
if (cm.somethingSelected()) return surround(cm);
if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1);
- var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch);
+ var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch), curChar = cur.ch > 0 ? line.charAt(cur.ch - 1) : "";
+ if (left == right && CodeMirror.isWordChar(curChar))
+ return CodeMirror.Pass;
if (line.length == cur.ch || closingBrackets.indexOf(nextChar) >= 0 || SPACE_CHAR_REGEX.test(nextChar))
cm.replaceSelection(left + right, {head: ahead, anchor: ahead});
else
@@ -49,4 +67,18 @@
})(pairs.charAt(i), pairs.charAt(i + 1));
return map;
}
+
+ function buildExplodeHandler(pairs) {
+ return function(cm) {
+ var cur = cm.getCursor(), around = charsAround(cm, cur);
+ if (!around || pairs.indexOf(around) % 2 != 0 || cm.getOption("disableInput"))
+ return CodeMirror.Pass;
+ cm.operation(function() {
+ var newPos = CodeMirror.Pos(cur.line + 1, 0);
+ cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input");
+ cm.indentLine(cur.line + 1, null, true);
+ cm.indentLine(cur.line + 2, null, true);
+ });
+ };
+ }
})();
diff --git a/gulliver/js/codemirror/addon/edit/closetag.js b/gulliver/js/codemirror/addon/edit/closetag.js
index 54fa19546..cad776a78 100644
--- a/gulliver/js/codemirror/addon/edit/closetag.js
+++ b/gulliver/js/codemirror/addon/edit/closetag.js
@@ -24,16 +24,15 @@
(function() {
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
- if (val && (old == CodeMirror.Init || !old)) {
- var map = {name: "autoCloseTags"};
- if (typeof val != "object" || val.whenClosing)
- map["'/'"] = function(cm) { return autoCloseTag(cm, '/'); };
- if (typeof val != "object" || val.whenOpening)
- map["'>'"] = function(cm) { return autoCloseTag(cm, '>'); };
- cm.addKeyMap(map);
- } else if (!val && (old != CodeMirror.Init && old)) {
+ if (old != CodeMirror.Init && old)
cm.removeKeyMap("autoCloseTags");
- }
+ if (!val) return;
+ var map = {name: "autoCloseTags"};
+ if (typeof val != "object" || val.whenClosing)
+ map["'/'"] = function(cm) { return autoCloseSlash(cm); };
+ if (typeof val != "object" || val.whenOpening)
+ map["'>'"] = function(cm) { return autoCloseGT(cm); };
+ cm.addKeyMap(map);
});
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
@@ -41,39 +40,48 @@
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
- function autoCloseTag(cm, ch) {
+ function autoCloseGT(cm) {
var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
- if (inner.mode.name != "xml") return CodeMirror.Pass;
+ if (inner.mode.name != "xml" || !state.tagName || cm.getOption("disableInput")) return CodeMirror.Pass;
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
- if (ch == ">" && state.tagName) {
- var tagName = state.tagName;
- if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
- var lowerTagName = tagName.toLowerCase();
- // Don't process the '>' at the end of an end-tag or self-closing tag
- if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 ||
- dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1)
- return CodeMirror.Pass;
+ var tagName = state.tagName;
+ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
+ var lowerTagName = tagName.toLowerCase();
+ // Don't process the '>' at the end of an end-tag or self-closing tag
+ if (!tagName ||
+ tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
+ tok.type == "tag" && state.type == "closeTag" ||
+ tok.string.indexOf("/") == (tok.string.length - 1) || // match something like
+ dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
+ CodeMirror.scanForClosingTag && CodeMirror.scanForClosingTag(cm, pos, tagName,
+ Math.min(cm.lastLine() + 1, pos.line + 50)))
+ return CodeMirror.Pass;
- var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1;
- var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1);
- cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "" + tagName + ">",
- {head: curPos, anchor: curPos});
- if (doIndent) {
- cm.indentLine(pos.line + 1);
- cm.indentLine(pos.line + 2);
- }
- return;
- } else if (ch == "/" && tok.string == "<") {
- var tagName = state.context && state.context.tagName;
- if (tagName) cm.replaceSelection("/" + tagName + ">", "end");
- return;
+ var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1;
+ var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1);
+ cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "" + tagName + ">",
+ {head: curPos, anchor: curPos});
+ if (doIndent) {
+ cm.indentLine(pos.line + 1, null, true);
+ cm.indentLine(pos.line + 2, null);
}
- return CodeMirror.Pass;
+ }
+
+ function autoCloseSlash(cm) {
+ var pos = cm.getCursor(), tok = cm.getTokenAt(pos);
+ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
+ if (tok.type == "string" || tok.string.charAt(0) != "<" ||
+ tok.start != pos.ch - 1 || inner.mode.name != "xml" ||
+ cm.getOption("disableInput"))
+ return CodeMirror.Pass;
+
+ var tagName = state.context && state.context.tagName;
+ if (tagName) cm.replaceSelection("/" + tagName + ">", "end");
}
function indexOf(collection, elt) {
diff --git a/gulliver/js/codemirror/addon/edit/continuecomment.js b/gulliver/js/codemirror/addon/edit/continuecomment.js
deleted file mode 100644
index 308026229..000000000
--- a/gulliver/js/codemirror/addon/edit/continuecomment.js
+++ /dev/null
@@ -1,44 +0,0 @@
-(function() {
- var modes = ["clike", "css", "javascript"];
- for (var i = 0; i < modes.length; ++i)
- CodeMirror.extendMode(modes[i], {blockCommentStart: "/*",
- blockCommentEnd: "*/",
- blockCommentContinue: " * "});
-
- function continueComment(cm) {
- var pos = cm.getCursor(), token = cm.getTokenAt(pos);
- var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode;
- var space;
-
- if (token.type == "comment" && mode.blockCommentStart) {
- var end = token.string.indexOf(mode.blockCommentEnd);
- var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
- if (end != -1 && end == token.string.length - mode.blockCommentEnd.length) {
- // Comment ended, don't continue it
- } else if (token.string.indexOf(mode.blockCommentStart) == 0) {
- space = full.slice(0, token.start);
- if (!/^\s*$/.test(space)) {
- space = "";
- for (var i = 0; i < token.start; ++i) space += " ";
- }
- } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
- found + mode.blockCommentContinue.length > token.start &&
- /^\s*$/.test(full.slice(0, found))) {
- space = full.slice(0, found);
- }
- }
-
- if (space != null)
- cm.replaceSelection("\n" + space + mode.blockCommentContinue, "end");
- else
- return CodeMirror.Pass;
- }
-
- CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
- if (prev && prev != CodeMirror.Init)
- cm.removeKeyMap("continueComment");
- var map = {name: "continueComment"};
- map[typeof val == "string" ? val : "Enter"] = continueComment;
- cm.addKeyMap(map);
- });
-})();
diff --git a/gulliver/js/codemirror/addon/edit/continuelist.js b/gulliver/js/codemirror/addon/edit/continuelist.js
index fb1fc38ba..190b41dcb 100644
--- a/gulliver/js/codemirror/addon/edit/continuelist.js
+++ b/gulliver/js/codemirror/addon/edit/continuelist.js
@@ -5,8 +5,10 @@
unorderedBullets = '*+-';
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
+ if (cm.getOption("disableInput")) return CodeMirror.Pass;
+
var pos = cm.getCursor(),
- inList = cm.getStateAfter(pos.line).list,
+ inList = cm.getStateAfter(pos.line).list !== false,
match;
if (!inList || !(match = cm.getLine(pos.line).match(listRE))) {
diff --git a/gulliver/js/codemirror/addon/edit/matchbrackets.js b/gulliver/js/codemirror/addon/edit/matchbrackets.js
index f4925b725..465b6ccaa 100644
--- a/gulliver/js/codemirror/addon/edit/matchbrackets.js
+++ b/gulliver/js/codemirror/addon/edit/matchbrackets.js
@@ -3,25 +3,29 @@
(document.documentMode == null || document.documentMode < 8);
var Pos = CodeMirror.Pos;
- // Disable brace matching in long lines, since it'll cause hugely slow updates
- var maxLineLen = 1000;
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
- function findMatchingBracket(cm) {
- var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
+ function findMatchingBracket(cm, where, strict) {
+ var state = cm.state.matchBrackets;
+ var maxScanLen = (state && state.maxScanLineLength) || 10000;
+ var maxScanLines = (state && state.maxScanLines) || 100;
+
+ var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
if (!match) return null;
var forward = match.charAt(1) == ">", d = forward ? 1 : -1;
- var style = cm.getTokenAt(Pos(cur.line, pos + 1)).type;
+ if (strict && forward != (pos == cur.ch)) return null;
+ var style = cm.getTokenTypeAt(Pos(cur.line, pos + 1));
var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
function scan(line, lineNo, start) {
if (!line.text) return;
var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1;
+ if (line.text.length > maxScanLen) return null;
if (start != null) pos = start + d;
for (; pos != end; pos += d) {
var ch = line.text.charAt(pos);
- if (re.test(ch) && cm.getTokenAt(Pos(lineNo, pos + 1)).type == style) {
+ if (re.test(ch) && cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style) {
var match = matching[ch];
if (match.charAt(1) == ">" == forward) stack.push(ch);
else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
@@ -29,25 +33,28 @@
}
}
}
- for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) {
+ for (var i = cur.line, found, e = forward ? Math.min(i + maxScanLines, cm.lineCount()) : Math.max(-1, i - maxScanLines); i != e; i+=d) {
if (i == cur.line) found = scan(line, i, pos);
else found = scan(cm.getLineHandle(i), i);
if (found) break;
}
- return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos), match: found && found.match};
+ return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos),
+ match: found && found.match, forward: forward};
}
function matchBrackets(cm, autoclear) {
+ // Disable brace matching in long lines, since it'll cause hugely slow updates
+ var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
var found = findMatchingBracket(cm);
- if (!found || cm.getLine(found.from.line).length > maxLineLen ||
- found.to && cm.getLine(found.to.line).length > maxLineLen)
+ if (!found || cm.getLine(found.from.line).length > maxHighlightLen ||
+ found.to && cm.getLine(found.to.line).length > maxHighlightLen)
return;
var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
var one = cm.markText(found.from, Pos(found.from.line, found.from.ch + 1), {className: style});
var two = found.to && cm.markText(found.to, Pos(found.to.line, found.to.ch + 1), {className: style});
// Kludge to work around the IE bug from issue #1193, where text
- // input stops going to the textare whever this fires.
+ // input stops going to the textarea whenever this fires.
if (ie_lt8 && cm.state.focused) cm.display.input.focus();
var clear = function() {
cm.operation(function() { one.clear(); two && two.clear(); });
@@ -64,11 +71,17 @@
});
}
- CodeMirror.defineOption("matchBrackets", false, function(cm, val) {
- if (val) cm.on("cursorActivity", doMatchBrackets);
- else cm.off("cursorActivity", doMatchBrackets);
+ CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
+ if (old && old != CodeMirror.Init)
+ cm.off("cursorActivity", doMatchBrackets);
+ if (val) {
+ cm.state.matchBrackets = typeof val == "object" ? val : {};
+ cm.on("cursorActivity", doMatchBrackets);
+ }
});
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
- CodeMirror.defineExtension("findMatchingBracket", function(){return findMatchingBracket(this);});
+ CodeMirror.defineExtension("findMatchingBracket", function(pos, strict){
+ return findMatchingBracket(this, pos, strict);
+ });
})();
diff --git a/gulliver/js/codemirror/addon/edit/matchtags.js b/gulliver/js/codemirror/addon/edit/matchtags.js
new file mode 100644
index 000000000..f189c1f8e
--- /dev/null
+++ b/gulliver/js/codemirror/addon/edit/matchtags.js
@@ -0,0 +1,56 @@
+(function() {
+ "use strict";
+
+ CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
+ if (old && old != CodeMirror.Init) {
+ cm.off("cursorActivity", doMatchTags);
+ cm.off("viewportChange", maybeUpdateMatch);
+ clear(cm);
+ }
+ if (val) {
+ cm.state.matchBothTags = typeof val == "object" && val.bothTags;
+ cm.on("cursorActivity", doMatchTags);
+ cm.on("viewportChange", maybeUpdateMatch);
+ doMatchTags(cm);
+ }
+ });
+
+ function clear(cm) {
+ if (cm.state.tagHit) cm.state.tagHit.clear();
+ if (cm.state.tagOther) cm.state.tagOther.clear();
+ cm.state.tagHit = cm.state.tagOther = null;
+ }
+
+ function doMatchTags(cm) {
+ cm.state.failedTagMatch = false;
+ cm.operation(function() {
+ clear(cm);
+ if (cm.somethingSelected()) return;
+ var cur = cm.getCursor(), range = cm.getViewport();
+ range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
+ var match = CodeMirror.findMatchingTag(cm, cur, range);
+ if (!match) return;
+ if (cm.state.matchBothTags) {
+ var hit = match.at == "open" ? match.open : match.close;
+ if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
+ }
+ var other = match.at == "close" ? match.open : match.close;
+ if (other)
+ cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
+ else
+ cm.state.failedTagMatch = true;
+ });
+ }
+
+ function maybeUpdateMatch(cm) {
+ if (cm.state.failedTagMatch) doMatchTags(cm);
+ }
+
+ CodeMirror.commands.toMatchingTag = function(cm) {
+ var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
+ if (found) {
+ var other = found.at == "close" ? found.open : found.close;
+ if (other) cm.setSelection(other.to, other.from);
+ }
+ };
+})();
diff --git a/gulliver/js/codemirror/addon/edit/trailingspace.js b/gulliver/js/codemirror/addon/edit/trailingspace.js
new file mode 100644
index 000000000..f6bb02645
--- /dev/null
+++ b/gulliver/js/codemirror/addon/edit/trailingspace.js
@@ -0,0 +1,15 @@
+CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
+ if (prev == CodeMirror.Init) prev = false;
+ if (prev && !val)
+ cm.removeOverlay("trailingspace");
+ else if (!prev && val)
+ cm.addOverlay({
+ token: function(stream) {
+ for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
+ if (i > stream.pos) { stream.pos = i; return null; }
+ stream.pos = l;
+ return "trailingspace";
+ },
+ name: "trailingspace"
+ });
+});
diff --git a/gulliver/js/codemirror/addon/fold/brace-fold.js b/gulliver/js/codemirror/addon/fold/brace-fold.js
index aad6e0141..2560b2b94 100644
--- a/gulliver/js/codemirror/addon/fold/brace-fold.js
+++ b/gulliver/js/codemirror/addon/fold/brace-fold.js
@@ -1,31 +1,93 @@
-CodeMirror.braceRangeFinder = function(cm, start) {
+CodeMirror.registerHelper("fold", "brace", function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
- var at = lineText.length, startChar, tokenType;
- for (;;) {
- var found = lineText.lastIndexOf("{", at);
- if (found < start.ch) break;
- tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type;
- if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
- at = found - 1;
+ var startCh, tokenType;
+
+ function findOpening(openCh) {
+ for (var at = start.ch, pass = 0;;) {
+ var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
+ if (found == -1) {
+ if (pass == 1) break;
+ pass = 1;
+ at = lineText.length;
+ continue;
+ }
+ if (pass == 1 && found < start.ch) break;
+ tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
+ if (!/^(comment|string)/.test(tokenType)) return found + 1;
+ at = found - 1;
+ }
}
- if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
- var count = 1, lastLine = cm.lineCount(), end, endCh;
- outer: for (var i = line + 1; i < lastLine; ++i) {
- var text = cm.getLine(i), pos = 0;
+
+ var startToken = "{", endToken = "}", startCh = findOpening("{");
+ if (startCh == null) {
+ startToken = "[", endToken = "]";
+ startCh = findOpening("[");
+ }
+
+ if (startCh == null) return;
+ var count = 1, lastLine = cm.lastLine(), end, endCh;
+ outer: for (var i = line; i <= lastLine; ++i) {
+ var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
- var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
- if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) {
+ if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
if (pos == nextOpen) ++count;
else if (!--count) { end = i; endCh = pos; break outer; }
}
++pos;
}
}
- if (end == null || end == line + 1) return;
- return {from: CodeMirror.Pos(line, startChar + 1),
+ if (end == null || line == end && endCh == startCh) return;
+ return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
-};
+});
+CodeMirror.braceRangeFinder = CodeMirror.fold.brace; // deprecated
+
+CodeMirror.registerHelper("fold", "import", function(cm, start) {
+ function hasImport(line) {
+ if (line < cm.firstLine() || line > cm.lastLine()) return null;
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+ if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+ if (start.type != "keyword" || start.string != "import") return null;
+ // Now find closing semicolon, return its position
+ for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
+ var text = cm.getLine(i), semi = text.indexOf(";");
+ if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
+ }
+ }
+
+ var start = start.line, has = hasImport(start), prev;
+ if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
+ return null;
+ for (var end = has.end;;) {
+ var next = hasImport(end.line + 1);
+ if (next == null) break;
+ end = next.end;
+ }
+ return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
+});
+CodeMirror.importRangeFinder = CodeMirror.fold["import"]; // deprecated
+
+CodeMirror.registerHelper("fold", "include", function(cm, start) {
+ function hasInclude(line) {
+ if (line < cm.firstLine() || line > cm.lastLine()) return null;
+ var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+ if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+ if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
+ }
+
+ var start = start.line, has = hasInclude(start);
+ if (has == null || hasInclude(start - 1) != null) return null;
+ for (var end = start;;) {
+ var next = hasInclude(end + 1);
+ if (next == null) break;
+ ++end;
+ }
+ return {from: CodeMirror.Pos(start, has + 1),
+ to: cm.clipPos(CodeMirror.Pos(end))};
+});
+CodeMirror.includeRangeFinder = CodeMirror.fold.include; // deprecated
diff --git a/gulliver/js/codemirror/addon/fold/comment-fold.js b/gulliver/js/codemirror/addon/fold/comment-fold.js
new file mode 100644
index 000000000..26e72f09f
--- /dev/null
+++ b/gulliver/js/codemirror/addon/fold/comment-fold.js
@@ -0,0 +1,42 @@
+CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
+ return mode.blockCommentStart && mode.blockCommentEnd;
+}, function(cm, start) {
+ var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
+ if (!startToken || !endToken) return;
+ var line = start.line, lineText = cm.getLine(line);
+
+ var startCh;
+ for (var at = start.ch, pass = 0;;) {
+ var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
+ if (found == -1) {
+ if (pass == 1) return;
+ pass = 1;
+ at = lineText.length;
+ continue;
+ }
+ if (pass == 1 && found < start.ch) return;
+ if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
+ startCh = found + startToken.length;
+ break;
+ }
+ at = found - 1;
+ }
+
+ var depth = 1, lastLine = cm.lastLine(), end, endCh;
+ outer: for (var i = line; i <= lastLine; ++i) {
+ var text = cm.getLine(i), pos = i == line ? startCh : 0;
+ for (;;) {
+ var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+ if (nextOpen < 0) nextOpen = text.length;
+ if (nextClose < 0) nextClose = text.length;
+ pos = Math.min(nextOpen, nextClose);
+ if (pos == text.length) break;
+ if (pos == nextOpen) ++depth;
+ else if (!--depth) { end = i; endCh = pos; break outer; }
+ ++pos;
+ }
+ }
+ if (end == null || line == end && endCh == startCh) return;
+ return {from: CodeMirror.Pos(line, startCh),
+ to: CodeMirror.Pos(end, endCh)};
+});
diff --git a/gulliver/js/codemirror/addon/fold/foldcode.js b/gulliver/js/codemirror/addon/fold/foldcode.js
index b8b4b0da9..5c00d7093 100644
--- a/gulliver/js/codemirror/addon/fold/foldcode.js
+++ b/gulliver/js/codemirror/addon/fold/foldcode.js
@@ -1,32 +1,86 @@
-CodeMirror.newFoldFunction = function(rangeFinder, widget) {
- if (widget == null) widget = "\u2194";
- if (typeof widget == "string") {
- var text = document.createTextNode(widget);
- widget = document.createElement("span");
- widget.appendChild(text);
- widget.className = "CodeMirror-foldmarker";
- }
+(function() {
+ "use strict";
- return function(cm, pos) {
+ function doFold(cm, pos, options, force) {
+ var finder = options && (options.call ? options : options.rangeFinder);
+ if (!finder) finder = CodeMirror.fold.auto;
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
- var range = rangeFinder(cm, pos);
- if (!range) return;
+ var minSize = options && options.minFoldSize || 0;
- var present = cm.findMarksAt(range.from), cleared = 0;
- for (var i = 0; i < present.length; ++i) {
- if (present[i].__isFold) {
- ++cleared;
- present[i].clear();
+ function getRange(allowFolded) {
+ var range = finder(cm, pos);
+ if (!range || range.to.line - range.from.line < minSize) return null;
+ var marks = cm.findMarksAt(range.from);
+ for (var i = 0; i < marks.length; ++i) {
+ if (marks[i].__isFold && force !== "fold") {
+ if (!allowFolded) return null;
+ range.cleared = true;
+ marks[i].clear();
+ }
}
+ return range;
}
- if (cleared) return;
- var myWidget = widget.cloneNode(true);
- CodeMirror.on(myWidget, "mousedown", function() {myRange.clear();});
+ var range = getRange(true);
+ if (options && options.scanUp) while (!range && pos.line > cm.firstLine()) {
+ pos = CodeMirror.Pos(pos.line - 1, 0);
+ range = getRange(false);
+ }
+ if (!range || range.cleared || force === "unfold") return;
+
+ var myWidget = makeWidget(options);
+ CodeMirror.on(myWidget, "mousedown", function() { myRange.clear(); });
var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget,
clearOnEnter: true,
__isFold: true
});
+ myRange.on("clear", function(from, to) {
+ CodeMirror.signal(cm, "unfold", cm, from, to);
+ });
+ CodeMirror.signal(cm, "fold", cm, range.from, range.to);
+ }
+
+ function makeWidget(options) {
+ var widget = (options && options.widget) || "\u2194";
+ if (typeof widget == "string") {
+ var text = document.createTextNode(widget);
+ widget = document.createElement("span");
+ widget.appendChild(text);
+ widget.className = "CodeMirror-foldmarker";
+ }
+ return widget;
+ }
+
+ // Clumsy backwards-compatible interface
+ CodeMirror.newFoldFunction = function(rangeFinder, widget) {
+ return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
};
-};
+
+ // New-style interface
+ CodeMirror.defineExtension("foldCode", function(pos, options, force) {
+ doFold(this, pos, options, force);
+ });
+
+ CodeMirror.commands.fold = function(cm) {
+ cm.foldCode(cm.getCursor());
+ };
+
+ CodeMirror.registerHelper("fold", "combine", function() {
+ var funcs = Array.prototype.slice.call(arguments, 0);
+ return function(cm, start) {
+ for (var i = 0; i < funcs.length; ++i) {
+ var found = funcs[i](cm, start);
+ if (found) return found;
+ }
+ };
+ });
+
+ CodeMirror.registerHelper("fold", "auto", function(cm, start) {
+ var helpers = cm.getHelpers(start, "fold");
+ for (var i = 0; i < helpers.length; i++) {
+ var cur = helpers[i](cm, start);
+ if (cur) return cur;
+ }
+ });
+})();
diff --git a/gulliver/js/codemirror/addon/fold/foldgutter.css b/gulliver/js/codemirror/addon/fold/foldgutter.css
new file mode 100644
index 000000000..49805393d
--- /dev/null
+++ b/gulliver/js/codemirror/addon/fold/foldgutter.css
@@ -0,0 +1,21 @@
+.CodeMirror-foldmarker {
+ color: blue;
+ text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
+ font-family: arial;
+ line-height: .3;
+ cursor: pointer;
+}
+.CodeMirror-foldgutter {
+ width: .7em;
+}
+.CodeMirror-foldgutter-open,
+.CodeMirror-foldgutter-folded {
+ color: #555;
+ cursor: pointer;
+}
+.CodeMirror-foldgutter-open:after {
+ content: "\25BE";
+}
+.CodeMirror-foldgutter-folded:after {
+ content: "\25B8";
+}
diff --git a/gulliver/js/codemirror/addon/fold/foldgutter.js b/gulliver/js/codemirror/addon/fold/foldgutter.js
new file mode 100644
index 000000000..a4f3bb318
--- /dev/null
+++ b/gulliver/js/codemirror/addon/fold/foldgutter.js
@@ -0,0 +1,124 @@
+(function() {
+ "use strict";
+
+ CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
+ if (old && old != CodeMirror.Init) {
+ cm.clearGutter(cm.state.foldGutter.options.gutter);
+ cm.state.foldGutter = null;
+ cm.off("gutterClick", onGutterClick);
+ cm.off("change", onChange);
+ cm.off("viewportChange", onViewportChange);
+ cm.off("fold", onFold);
+ cm.off("unfold", onFold);
+ cm.off("swapDoc", updateInViewport);
+ }
+ if (val) {
+ cm.state.foldGutter = new State(parseOptions(val));
+ updateInViewport(cm);
+ cm.on("gutterClick", onGutterClick);
+ cm.on("change", onChange);
+ cm.on("viewportChange", onViewportChange);
+ cm.on("fold", onFold);
+ cm.on("unfold", onFold);
+ cm.on("swapDoc", updateInViewport);
+ }
+ });
+
+ var Pos = CodeMirror.Pos;
+
+ function State(options) {
+ this.options = options;
+ this.from = this.to = 0;
+ }
+
+ function parseOptions(opts) {
+ if (opts === true) opts = {};
+ if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
+ if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
+ if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
+ return opts;
+ }
+
+ function isFolded(cm, line) {
+ var marks = cm.findMarksAt(Pos(line));
+ for (var i = 0; i < marks.length; ++i)
+ if (marks[i].__isFold && marks[i].find().from.line == line) return true;
+ }
+
+ function marker(spec) {
+ if (typeof spec == "string") {
+ var elt = document.createElement("div");
+ elt.className = spec;
+ return elt;
+ } else {
+ return spec.cloneNode(true);
+ }
+ }
+
+ function updateFoldInfo(cm, from, to) {
+ var opts = cm.state.foldGutter.options, cur = from;
+ cm.eachLine(from, to, function(line) {
+ var mark = null;
+ if (isFolded(cm, cur)) {
+ mark = marker(opts.indicatorFolded);
+ } else {
+ var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto;
+ var range = func && func(cm, pos);
+ if (range && range.from.line + 1 < range.to.line)
+ mark = marker(opts.indicatorOpen);
+ }
+ cm.setGutterMarker(line, opts.gutter, mark);
+ ++cur;
+ });
+ }
+
+ function updateInViewport(cm) {
+ var vp = cm.getViewport(), state = cm.state.foldGutter;
+ if (!state) return;
+ cm.operation(function() {
+ updateFoldInfo(cm, vp.from, vp.to);
+ });
+ state.from = vp.from; state.to = vp.to;
+ }
+
+ function onGutterClick(cm, line, gutter) {
+ var opts = cm.state.foldGutter.options;
+ if (gutter != opts.gutter) return;
+ cm.foldCode(Pos(line, 0), opts.rangeFinder);
+ }
+
+ function onChange(cm) {
+ var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
+ state.from = state.to = 0;
+ clearTimeout(state.changeUpdate);
+ state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
+ }
+
+ function onViewportChange(cm) {
+ var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
+ clearTimeout(state.changeUpdate);
+ state.changeUpdate = setTimeout(function() {
+ var vp = cm.getViewport();
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
+ updateInViewport(cm);
+ } else {
+ cm.operation(function() {
+ if (vp.from < state.from) {
+ updateFoldInfo(cm, vp.from, state.from);
+ state.from = vp.from;
+ }
+ if (vp.to > state.to) {
+ updateFoldInfo(cm, state.to, vp.to);
+ state.to = vp.to;
+ }
+ });
+ }
+ }, opts.updateViewportTimeSpan || 400);
+ }
+
+ function onFold(cm, from) {
+ var state = cm.state.foldGutter, line = from.line;
+ if (line >= state.from && line < state.to)
+ updateFoldInfo(cm, line, line + 1);
+ }
+})();
diff --git a/gulliver/js/codemirror/addon/fold/indent-fold.js b/gulliver/js/codemirror/addon/fold/indent-fold.js
index 94a0a1ffa..434c2bc5c 100644
--- a/gulliver/js/codemirror/addon/fold/indent-fold.js
+++ b/gulliver/js/codemirror/addon/fold/indent-fold.js
@@ -1,11 +1,30 @@
-CodeMirror.indentRangeFinder = function(cm, start) {
+CodeMirror.registerHelper("fold", "indent", function(cm, start) {
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
- var myIndent = CodeMirror.countColumn(firstLine, null, tabSize);
- for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) {
+ if (!/\S/.test(firstLine)) return;
+ var getIndent = function(line) {
+ return CodeMirror.countColumn(line, null, tabSize);
+ };
+ var myIndent = getIndent(firstLine);
+ var lastLineInFold = null;
+ // Go through lines until we find a line that definitely doesn't belong in
+ // the block we're folding, or to the end.
+ for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
var curLine = cm.getLine(i);
- if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent &&
- CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent)
- return {from: CodeMirror.Pos(start.line, firstLine.length),
- to: CodeMirror.Pos(i, curLine.length)};
+ var curIndent = getIndent(curLine);
+ if (curIndent > myIndent) {
+ // Lines with a greater indent are considered part of the block.
+ lastLineInFold = i;
+ } else if (!/\S/.test(curLine)) {
+ // Empty lines might be breaks within the block we're trying to fold.
+ } else {
+ // A non-empty line at an indent equal to or less than ours marks the
+ // start of another block.
+ break;
+ }
}
-};
+ if (lastLineInFold) return {
+ from: CodeMirror.Pos(start.line, firstLine.length),
+ to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
+ };
+});
+CodeMirror.indentRangeFinder = CodeMirror.fold.indent; // deprecated
diff --git a/gulliver/js/codemirror/addon/fold/xml-fold.js b/gulliver/js/codemirror/addon/fold/xml-fold.js
index 79c524d48..db5aed704 100644
--- a/gulliver/js/codemirror/addon/fold/xml-fold.js
+++ b/gulliver/js/codemirror/addon/fold/xml-fold.js
@@ -1,64 +1,173 @@
-CodeMirror.tagRangeFinder = (function() {
+(function() {
+ "use strict";
+
+ var Pos = CodeMirror.Pos;
+ function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
+
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
- return function(cm, start) {
- var line = start.line, ch = start.ch, lineText = cm.getLine(line);
+ function Iter(cm, line, ch, range) {
+ this.line = line; this.ch = ch;
+ this.cm = cm; this.text = cm.getLine(line);
+ this.min = range ? range.from : cm.firstLine();
+ this.max = range ? range.to - 1 : cm.lastLine();
+ }
- function nextLine() {
- if (line >= cm.lastLine()) return;
- ch = 0;
- lineText = cm.getLine(++line);
- return true;
- }
- function toTagEnd() {
- for (;;) {
- var gt = lineText.indexOf(">", ch);
- if (gt == -1) { if (nextLine()) continue; else return; }
- var lastSlash = lineText.lastIndexOf("/", gt);
- var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt));
- ch = gt + 1;
- return selfClose ? "selfClose" : "regular";
- }
- }
- function toNextTag() {
- for (;;) {
- xmlTagStart.lastIndex = ch;
- var found = xmlTagStart.exec(lineText);
- if (!found) { if (nextLine()) continue; else return; }
- ch = found.index + found[0].length;
- return found;
- }
- }
+ function tagAt(iter, ch) {
+ var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
+ return type && /\btag\b/.test(type);
+ }
- var stack = [], startCh;
+ function nextLine(iter) {
+ if (iter.line >= iter.max) return;
+ iter.ch = 0;
+ iter.text = iter.cm.getLine(++iter.line);
+ return true;
+ }
+ function prevLine(iter) {
+ if (iter.line <= iter.min) return;
+ iter.text = iter.cm.getLine(--iter.line);
+ iter.ch = iter.text.length;
+ return true;
+ }
+
+ function toTagEnd(iter) {
for (;;) {
- var openTag = toNextTag(), end;
- if (!openTag || line != start.line || !(end = toTagEnd())) return;
- if (!openTag[1] && end != "selfClose") {
- stack.push(openTag[2]);
- startCh = ch;
- break;
- }
+ var gt = iter.text.indexOf(">", iter.ch);
+ if (gt == -1) { if (nextLine(iter)) continue; else return; }
+ if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
+ var lastSlash = iter.text.lastIndexOf("/", gt);
+ var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+ iter.ch = gt + 1;
+ return selfClose ? "selfClose" : "regular";
}
-
+ }
+ function toTagStart(iter) {
for (;;) {
- var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0);
- if (!next || !(end = toTagEnd())) return;
+ var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
+ if (lt == -1) { if (prevLine(iter)) continue; else return; }
+ if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
+ xmlTagStart.lastIndex = lt;
+ iter.ch = lt;
+ var match = xmlTagStart.exec(iter.text);
+ if (match && match.index == lt) return match;
+ }
+ }
+
+ function toNextTag(iter) {
+ for (;;) {
+ xmlTagStart.lastIndex = iter.ch;
+ var found = xmlTagStart.exec(iter.text);
+ if (!found) { if (nextLine(iter)) continue; else return; }
+ if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
+ iter.ch = found.index + found[0].length;
+ return found;
+ }
+ }
+ function toPrevTag(iter) {
+ for (;;) {
+ var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
+ if (gt == -1) { if (prevLine(iter)) continue; else return; }
+ if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
+ var lastSlash = iter.text.lastIndexOf("/", gt);
+ var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+ iter.ch = gt + 1;
+ return selfClose ? "selfClose" : "regular";
+ }
+ }
+
+ function findMatchingClose(iter, tag) {
+ var stack = [];
+ for (;;) {
+ var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
+ if (!next || !(end = toTagEnd(iter))) return;
if (end == "selfClose") continue;
if (next[1]) { // closing tag
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
stack.length = i;
break;
}
- if (!stack.length) return {
- from: CodeMirror.Pos(start.line, startCh),
- to: CodeMirror.Pos(tagLine, tagCh)
+ if (i < 0 && (!tag || tag == next[2])) return {
+ tag: next[2],
+ from: Pos(startLine, startCh),
+ to: Pos(iter.line, iter.ch)
};
} else { // opening tag
stack.push(next[2]);
}
}
+ }
+ function findMatchingOpen(iter, tag) {
+ var stack = [];
+ for (;;) {
+ var prev = toPrevTag(iter);
+ if (!prev) return;
+ if (prev == "selfClose") { toTagStart(iter); continue; }
+ var endLine = iter.line, endCh = iter.ch;
+ var start = toTagStart(iter);
+ if (!start) return;
+ if (start[1]) { // closing tag
+ stack.push(start[2]);
+ } else { // opening tag
+ for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
+ stack.length = i;
+ break;
+ }
+ if (i < 0 && (!tag || tag == start[2])) return {
+ tag: start[2],
+ from: Pos(iter.line, iter.ch),
+ to: Pos(endLine, endCh)
+ };
+ }
+ }
+ }
+
+ CodeMirror.registerHelper("fold", "xml", function(cm, start) {
+ var iter = new Iter(cm, start.line, 0);
+ for (;;) {
+ var openTag = toNextTag(iter), end;
+ if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
+ if (!openTag[1] && end != "selfClose") {
+ var start = Pos(iter.line, iter.ch);
+ var close = findMatchingClose(iter, openTag[2]);
+ return close && {from: start, to: close.from};
+ }
+ }
+ });
+ CodeMirror.tagRangeFinder = CodeMirror.fold.xml; // deprecated
+
+ CodeMirror.findMatchingTag = function(cm, pos, range) {
+ var iter = new Iter(cm, pos.line, pos.ch, range);
+ if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
+ var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
+ var start = end && toTagStart(iter);
+ if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return;
+ var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
+
+ if (start[1]) { // closing tag
+ return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
+ } else { // opening tag
+ iter = new Iter(cm, to.line, to.ch, range);
+ return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
+ }
+ };
+
+ CodeMirror.findEnclosingTag = function(cm, pos, range) {
+ var iter = new Iter(cm, pos.line, pos.ch, range);
+ for (;;) {
+ var open = findMatchingOpen(iter);
+ if (!open) break;
+ var forward = new Iter(cm, pos.line, pos.ch, range);
+ var close = findMatchingClose(forward, open.tag);
+ if (close) return {open: open, close: close};
+ }
+ };
+
+ // Used by addon/edit/closetag.js
+ CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
+ var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
+ return !!findMatchingClose(iter, name);
};
})();
diff --git a/gulliver/js/codemirror/addon/hint/anyword-hint.js b/gulliver/js/codemirror/addon/hint/anyword-hint.js
new file mode 100644
index 000000000..a144768c8
--- /dev/null
+++ b/gulliver/js/codemirror/addon/hint/anyword-hint.js
@@ -0,0 +1,32 @@
+(function() {
+ "use strict";
+
+ var WORD = /[\w$]+/, RANGE = 500;
+
+ CodeMirror.registerHelper("hint", "anyword", function(editor, options) {
+ var word = options && options.word || WORD;
+ var range = options && options.range || RANGE;
+ var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
+ var start = cur.ch, end = start;
+ while (end < curLine.length && word.test(curLine.charAt(end))) ++end;
+ while (start && word.test(curLine.charAt(start - 1))) --start;
+ var curWord = start != end && curLine.slice(start, end);
+
+ var list = [], seen = {};
+ var re = new RegExp(word.source, "g");
+ for (var dir = -1; dir <= 1; dir += 2) {
+ var line = cur.line, end = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir;
+ for (; line != end; line += dir) {
+ var text = editor.getLine(line), m;
+ while (m = re.exec(text)) {
+ if (line == cur.line && m[0] === curWord) continue;
+ if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) {
+ seen[m[0]] = true;
+ list.push(m[0]);
+ }
+ }
+ }
+ }
+ return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
+ });
+})();
diff --git a/gulliver/js/codemirror/addon/hint/css-hint.js b/gulliver/js/codemirror/addon/hint/css-hint.js
new file mode 100644
index 000000000..6789c458b
--- /dev/null
+++ b/gulliver/js/codemirror/addon/hint/css-hint.js
@@ -0,0 +1,46 @@
+(function () {
+ "use strict";
+
+ var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
+ "first-letter": 1, "first-line": 1, "first-child": 1,
+ before: 1, after: 1, lang: 1};
+
+ CodeMirror.registerHelper("hint", "css", function(cm) {
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+ var inner = CodeMirror.innerMode(cm.getMode(), token.state);
+ if (inner.mode.name != "css") return;
+
+ var word = token.string, start = token.start, end = token.end;
+ if (/[^\w$_-]/.test(word)) {
+ word = ""; start = end = cur.ch;
+ }
+
+ var spec = CodeMirror.resolveMode("text/css");
+
+ var result = [];
+ function add(keywords) {
+ for (var name in keywords)
+ if (!word || name.lastIndexOf(word, 0) == 0)
+ result.push(name);
+ }
+
+ var st = token.state.state;
+ if (st == "pseudo" || token.type == "variable-3") {
+ add(pseudoClasses);
+ } else if (st == "block" || st == "maybeprop") {
+ add(spec.propertyKeywords);
+ } else if (st == "prop" || st == "parens" || st == "at" || st == "params") {
+ add(spec.valueKeywords);
+ add(spec.colorKeywords);
+ } else if (st == "media" || st == "media_parens") {
+ add(spec.mediaTypes);
+ add(spec.mediaFeatures);
+ }
+
+ if (result.length) return {
+ list: result,
+ from: CodeMirror.Pos(cur.line, start),
+ to: CodeMirror.Pos(cur.line, end)
+ };
+ });
+})();
diff --git a/gulliver/js/codemirror/addon/hint/html-hint.js b/gulliver/js/codemirror/addon/hint/html-hint.js
index 8b5dc6f00..cf256851e 100755
--- a/gulliver/js/codemirror/addon/hint/html-hint.js
+++ b/gulliver/js/codemirror/addon/hint/html-hint.js
@@ -1,582 +1,337 @@
(function () {
- function htmlHint(editor, htmlStructure, getToken) {
- var cur = editor.getCursor();
- var token = getToken(editor, cur);
- var keywords = [];
- var i = 0;
- var j = 0;
- var k = 0;
- var from = {line: cur.line, ch: cur.ch};
- var to = {line: cur.line, ch: cur.ch};
- var flagClean = true;
+ var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" ");
+ var targets = ["_blank", "_self", "_top", "_parent"];
+ var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"];
+ var methods = ["get", "post", "put", "delete"];
+ var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"];
+ var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech",
+ "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait",
+ "orientation:landscape", "device-height: [X]", "device-width: [X]"];
+ var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags
- var text = editor.getRange({line: 0, ch: 0}, cur);
-
- var open = text.lastIndexOf('<');
- var close = text.lastIndexOf('>');
- var tokenString = token.string.replace("<","");
-
- if(open > close) {
- var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur);
- if(last == "<") {
- for(i = 0; i < htmlStructure.length; i++) {
- keywords.push(htmlStructure[i].tag);
- }
- from.ch = token.start + 1;
- } else {
- var counter = 0;
- var found = function(token, type, position) {
- counter++;
- if(counter > 50) return;
- if(token.type == type) {
- return token;
- } else {
- position.ch = token.start;
- var newToken = editor.getTokenAt(position);
- return found(newToken, type, position);
- }
- };
-
- var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch});
- var node = nodeToken.string.substring(1);
-
- if(token.type === null && token.string.trim() === "") {
- for(i = 0; i < htmlStructure.length; i++) {
- if(htmlStructure[i].tag == node) {
- for(j = 0; j < htmlStructure[i].attr.length; j++) {
- keywords.push(htmlStructure[i].attr[j].key + "=\"\" ");
- }
-
- for(k = 0; k < globalAttributes.length; k++) {
- keywords.push(globalAttributes[k].key + "=\"\" ");
- }
- }
- }
- } else if(token.type == "string") {
- tokenString = tokenString.substring(1, tokenString.length - 1);
- var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch});
- var attribute = attributeToken.string;
-
- for(i = 0; i < htmlStructure.length; i++) {
- if(htmlStructure[i].tag == node) {
- for(j = 0; j < htmlStructure[i].attr.length; j++) {
- if(htmlStructure[i].attr[j].key == attribute) {
- for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) {
- keywords.push(htmlStructure[i].attr[j].values[k]);
- }
- }
- }
-
- for(j = 0; j < globalAttributes.length; j++) {
- if(globalAttributes[j].key == attribute) {
- for(k = 0; k < globalAttributes[j].values.length; k++) {
- keywords.push(globalAttributes[j].values[k]);
- }
- }
- }
- }
- }
- from.ch = token.start + 1;
- } else if(token.type == "attribute") {
- for(i = 0; i < htmlStructure.length; i++) {
- if(htmlStructure[i].tag == node) {
- for(j = 0; j < htmlStructure[i].attr.length; j++) {
- keywords.push(htmlStructure[i].attr[j].key + "=\"\" ");
- }
-
- for(k = 0; k < globalAttributes.length; k++) {
- keywords.push(globalAttributes[k].key + "=\"\" ");
- }
- }
- }
- from.ch = token.start;
- } else if(token.type == "tag") {
- for(i = 0; i < htmlStructure.length; i++) {
- keywords.push(htmlStructure[i].tag);
- }
-
- from.ch = token.start + 1;
- }
+ var data = {
+ a: {
+ attrs: {
+ href: null, ping: null, type: null,
+ media: media,
+ target: targets,
+ hreflang: langs
}
- } else {
- for(i = 0; i < htmlStructure.length; i++) {
- keywords.push("<" + htmlStructure[i].tag);
+ },
+ abbr: s,
+ acronym: s,
+ address: s,
+ applet: s,
+ area: {
+ attrs: {
+ alt: null, coords: null, href: null, target: null, ping: null,
+ media: media, hreflang: langs, type: null,
+ shape: ["default", "rect", "circle", "poly"]
}
+ },
+ article: s,
+ aside: s,
+ audio: {
+ attrs: {
+ src: null, mediagroup: null,
+ crossorigin: ["anonymous", "use-credentials"],
+ preload: ["none", "metadata", "auto"],
+ autoplay: ["", "autoplay"],
+ loop: ["", "loop"],
+ controls: ["", "controls"]
+ }
+ },
+ b: s,
+ base: { attrs: { href: null, target: targets } },
+ basefont: s,
+ bdi: s,
+ bdo: s,
+ big: s,
+ blockquote: { attrs: { cite: null } },
+ body: s,
+ br: s,
+ button: {
+ attrs: {
+ form: null, formaction: null, name: null, value: null,
+ autofocus: ["", "autofocus"],
+ disabled: ["", "autofocus"],
+ formenctype: encs,
+ formmethod: methods,
+ formnovalidate: ["", "novalidate"],
+ formtarget: targets,
+ type: ["submit", "reset", "button"]
+ }
+ },
+ canvas: { attrs: { width: null, height: null } },
+ caption: s,
+ center: s,
+ cite: s,
+ code: s,
+ col: { attrs: { span: null } },
+ colgroup: { attrs: { span: null } },
+ command: {
+ attrs: {
+ type: ["command", "checkbox", "radio"],
+ label: null, icon: null, radiogroup: null, command: null, title: null,
+ disabled: ["", "disabled"],
+ checked: ["", "checked"]
+ }
+ },
+ data: { attrs: { value: null } },
+ datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } },
+ datalist: { attrs: { data: null } },
+ dd: s,
+ del: { attrs: { cite: null, datetime: null } },
+ details: { attrs: { open: ["", "open"] } },
+ dfn: s,
+ dir: s,
+ div: s,
+ dl: s,
+ dt: s,
+ em: s,
+ embed: { attrs: { src: null, type: null, width: null, height: null } },
+ eventsource: { attrs: { src: null } },
+ fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } },
+ figcaption: s,
+ figure: s,
+ font: s,
+ footer: s,
+ form: {
+ attrs: {
+ action: null, name: null,
+ "accept-charset": charsets,
+ autocomplete: ["on", "off"],
+ enctype: encs,
+ method: methods,
+ novalidate: ["", "novalidate"],
+ target: targets
+ }
+ },
+ frame: s,
+ frameset: s,
+ h1: s, h2: s, h3: s, h4: s, h5: s, h6: s,
+ head: {
+ attrs: {},
+ children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"]
+ },
+ header: s,
+ hgroup: s,
+ hr: s,
+ html: {
+ attrs: { manifest: null },
+ children: ["head", "body"]
+ },
+ i: s,
+ iframe: {
+ attrs: {
+ src: null, srcdoc: null, name: null, width: null, height: null,
+ sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"],
+ seamless: ["", "seamless"]
+ }
+ },
+ img: {
+ attrs: {
+ alt: null, src: null, ismap: null, usemap: null, width: null, height: null,
+ crossorigin: ["anonymous", "use-credentials"]
+ }
+ },
+ input: {
+ attrs: {
+ alt: null, dirname: null, form: null, formaction: null,
+ height: null, list: null, max: null, maxlength: null, min: null,
+ name: null, pattern: null, placeholder: null, size: null, src: null,
+ step: null, value: null, width: null,
+ accept: ["audio/*", "video/*", "image/*"],
+ autocomplete: ["on", "off"],
+ autofocus: ["", "autofocus"],
+ checked: ["", "checked"],
+ disabled: ["", "disabled"],
+ formenctype: encs,
+ formmethod: methods,
+ formnovalidate: ["", "novalidate"],
+ formtarget: targets,
+ multiple: ["", "multiple"],
+ readonly: ["", "readonly"],
+ required: ["", "required"],
+ type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month",
+ "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
+ "file", "submit", "image", "reset", "button"]
+ }
+ },
+ ins: { attrs: { cite: null, datetime: null } },
+ kbd: s,
+ keygen: {
+ attrs: {
+ challenge: null, form: null, name: null,
+ autofocus: ["", "autofocus"],
+ disabled: ["", "disabled"],
+ keytype: ["RSA"]
+ }
+ },
+ label: { attrs: { "for": null, form: null } },
+ legend: s,
+ li: { attrs: { value: null } },
+ link: {
+ attrs: {
+ href: null, type: null,
+ hreflang: langs,
+ media: media,
+ sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"]
+ }
+ },
+ map: { attrs: { name: null } },
+ mark: s,
+ menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } },
+ meta: {
+ attrs: {
+ content: null,
+ charset: charsets,
+ name: ["viewport", "application-name", "author", "description", "generator", "keywords"],
+ "http-equiv": ["content-language", "content-type", "default-style", "refresh"]
+ }
+ },
+ meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } },
+ nav: s,
+ noframes: s,
+ noscript: s,
+ object: {
+ attrs: {
+ data: null, type: null, name: null, usemap: null, form: null, width: null, height: null,
+ typemustmatch: ["", "typemustmatch"]
+ }
+ },
+ ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } },
+ optgroup: { attrs: { disabled: ["", "disabled"], label: null } },
+ option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } },
+ output: { attrs: { "for": null, form: null, name: null } },
+ p: s,
+ param: { attrs: { name: null, value: null } },
+ pre: s,
+ progress: { attrs: { value: null, max: null } },
+ q: { attrs: { cite: null } },
+ rp: s,
+ rt: s,
+ ruby: s,
+ s: s,
+ samp: s,
+ script: {
+ attrs: {
+ type: ["text/javascript"],
+ src: null,
+ async: ["", "async"],
+ defer: ["", "defer"],
+ charset: charsets
+ }
+ },
+ section: s,
+ select: {
+ attrs: {
+ form: null, name: null, size: null,
+ autofocus: ["", "autofocus"],
+ disabled: ["", "disabled"],
+ multiple: ["", "multiple"]
+ }
+ },
+ small: s,
+ source: { attrs: { src: null, type: null, media: null } },
+ span: s,
+ strike: s,
+ strong: s,
+ style: {
+ attrs: {
+ type: ["text/css"],
+ media: media,
+ scoped: null
+ }
+ },
+ sub: s,
+ summary: s,
+ sup: s,
+ table: s,
+ tbody: s,
+ td: { attrs: { colspan: null, rowspan: null, headers: null } },
+ textarea: {
+ attrs: {
+ dirname: null, form: null, maxlength: null, name: null, placeholder: null,
+ rows: null, cols: null,
+ autofocus: ["", "autofocus"],
+ disabled: ["", "disabled"],
+ readonly: ["", "readonly"],
+ required: ["", "required"],
+ wrap: ["soft", "hard"]
+ }
+ },
+ tfoot: s,
+ th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } },
+ thead: s,
+ time: { attrs: { datetime: null } },
+ title: s,
+ tr: s,
+ track: {
+ attrs: {
+ src: null, label: null, "default": null,
+ kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"],
+ srclang: langs
+ }
+ },
+ tt: s,
+ u: s,
+ ul: s,
+ "var": s,
+ video: {
+ attrs: {
+ src: null, poster: null, width: null, height: null,
+ crossorigin: ["anonymous", "use-credentials"],
+ preload: ["auto", "metadata", "none"],
+ autoplay: ["", "autoplay"],
+ mediagroup: ["movie"],
+ muted: ["", "muted"],
+ controls: ["", "controls"]
+ }
+ },
+ wbr: s
+ };
- tokenString = ("<" + tokenString).trim();
- from.ch = token.start;
- }
-
- if(flagClean === true && tokenString.trim() === "") {
- flagClean = false;
- }
-
- if(flagClean) {
- keywords = cleanResults(tokenString, keywords);
- }
-
- return {list: keywords, from: from, to: to};
+ var globalAttrs = {
+ accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
+ "class": null,
+ contenteditable: ["true", "false"],
+ contextmenu: null,
+ dir: ["ltr", "rtl", "auto"],
+ draggable: ["true", "false", "auto"],
+ dropzone: ["copy", "move", "link", "string:", "file:"],
+ hidden: ["hidden"],
+ id: null,
+ inert: ["inert"],
+ itemid: null,
+ itemprop: null,
+ itemref: null,
+ itemscope: ["itemscope"],
+ itemtype: null,
+ lang: ["en", "es"],
+ spellcheck: ["true", "false"],
+ style: null,
+ tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
+ title: null,
+ translate: ["yes", "no"],
+ onclick: null,
+ rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"]
+ };
+ function populate(obj) {
+ for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr))
+ obj.attrs[attr] = globalAttrs[attr];
}
+ populate(s);
+ for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s)
+ populate(data[tag]);
- var cleanResults = function(text, keywords) {
- var results = [];
- var i = 0;
-
- for(i = 0; i < keywords.length; i++) {
- if(keywords[i].substring(0, text.length) == text) {
- results.push(keywords[i]);
- }
- }
-
- return results;
- };
-
- var htmlStructure = [
- {tag: '!DOCTYPE', attr: []},
- {tag: 'a', attr: [
- {key: 'href', values: ["#"]},
- {key: 'target', values: ["_blank","_self","_top","_parent"]},
- {key: 'ping', values: [""]},
- {key: 'media', values: ["#"]},
- {key: 'hreflang', values: ["en","es"]},
- {key: 'type', values: []}
- ]},
- {tag: 'abbr', attr: []},
- {tag: 'acronym', attr: []},
- {tag: 'address', attr: []},
- {tag: 'applet', attr: []},
- {tag: 'area', attr: [
- {key: 'alt', values: [""]},
- {key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]},
- {key: 'shape', values: ["default","rect","circle","poly"]},
- {key: 'href', values: ["#"]},
- {key: 'target', values: ["#"]},
- {key: 'ping', values: []},
- {key: 'media', values: []},
- {key: 'hreflang', values: []},
- {key: 'type', values: []}
-
- ]},
- {tag: 'article', attr: []},
- {tag: 'aside', attr: []},
- {tag: 'audio', attr: [
- {key: 'src', values: []},
- {key: 'crossorigin', values: ["anonymous","use-credentials"]},
- {key: 'preload', values: ["none","metadata","auto"]},
- {key: 'autoplay', values: ["","autoplay"]},
- {key: 'mediagroup', values: []},
- {key: 'loop', values: ["","loop"]},
- {key: 'controls', values: ["","controls"]}
- ]},
- {tag: 'b', attr: []},
- {tag: 'base', attr: [
- {key: 'href', values: ["#"]},
- {key: 'target', values: ["_blank","_self","_top","_parent"]}
- ]},
- {tag: 'basefont', attr: []},
- {tag: 'bdi', attr: []},
- {tag: 'bdo', attr: []},
- {tag: 'big', attr: []},
- {tag: 'blockquote', attr: [
- {key: 'cite', values: ["http://"]}
- ]},
- {tag: 'body', attr: []},
- {tag: 'br', attr: []},
- {tag: 'button', attr: [
- {key: 'autofocus', values: ["","autofocus"]},
- {key: 'disabled', values: ["","disabled"]},
- {key: 'form', values: []},
- {key: 'formaction', values: []},
- {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
- {key: 'formmethod', values: ["get","post","put","delete"]},
- {key: 'formnovalidate', values: ["","novalidate"]},
- {key: 'formtarget', values: ["_blank","_self","_top","_parent"]},
- {key: 'name', values: []},
- {key: 'type', values: ["submit","reset","button"]},
- {key: 'value', values: []}
- ]},
- {tag: 'canvas', attr: [
- {key: 'width', values: []},
- {key: 'height', values: []}
- ]},
- {tag: 'caption', attr: []},
- {tag: 'center', attr: []},
- {tag: 'cite', attr: []},
- {tag: 'code', attr: []},
- {tag: 'col', attr: [
- {key: 'span', values: []}
- ]},
- {tag: 'colgroup', attr: [
- {key: 'span', values: []}
- ]},
- {tag: 'command', attr: [
- {key: 'type', values: ["command","checkbox","radio"]},
- {key: 'label', values: []},
- {key: 'icon', values: []},
- {key: 'disabled', values: ["","disabled"]},
- {key: 'checked', values: ["","checked"]},
- {key: 'radiogroup', values: []},
- {key: 'command', values: []},
- {key: 'title', values: []}
- ]},
- {tag: 'data', attr: [
- {key: 'value', values: []}
- ]},
- {tag: 'datagrid', attr: [
- {key: 'disabled', values: ["","disabled"]},
- {key: 'multiple', values: ["","multiple"]}
- ]},
- {tag: 'datalist', attr: [
- {key: 'data', values: []}
- ]},
- {tag: 'dd', attr: []},
- {tag: 'del', attr: [
- {key: 'cite', values: []},
- {key: 'datetime', values: []}
- ]},
- {tag: 'details', attr: [
- {key: 'open', values: ["","open"]}
- ]},
- {tag: 'dfn', attr: []},
- {tag: 'dir', attr: []},
- {tag: 'div', attr: [
- {key: 'id', values: []},
- {key: 'class', values: []},
- {key: 'style', values: []}
- ]},
- {tag: 'dl', attr: []},
- {tag: 'dt', attr: []},
- {tag: 'em', attr: []},
- {tag: 'embed', attr: [
- {key: 'src', values: []},
- {key: 'type', values: []},
- {key: 'width', values: []},
- {key: 'height', values: []}
- ]},
- {tag: 'eventsource', attr: [
- {key: 'src', values: []}
- ]},
- {tag: 'fieldset', attr: [
- {key: 'disabled', values: ["","disabled"]},
- {key: 'form', values: []},
- {key: 'name', values: []}
- ]},
- {tag: 'figcaption', attr: []},
- {tag: 'figure', attr: []},
- {tag: 'font', attr: []},
- {tag: 'footer', attr: []},
- {tag: 'form', attr: [
- {key: 'accept-charset', values: ["UNKNOWN","utf-8"]},
- {key: 'action', values: []},
- {key: 'autocomplete', values: ["on","off"]},
- {key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
- {key: 'method', values: ["get","post","put","delete","dialog"]},
- {key: 'name', values: []},
- {key: 'novalidate', values: ["","novalidate"]},
- {key: 'target', values: ["_blank","_self","_top","_parent"]}
- ]},
- {tag: 'frame', attr: []},
- {tag: 'frameset', attr: []},
- {tag: 'h1', attr: []},
- {tag: 'h2', attr: []},
- {tag: 'h3', attr: []},
- {tag: 'h4', attr: []},
- {tag: 'h5', attr: []},
- {tag: 'h6', attr: []},
- {tag: 'head', attr: []},
- {tag: 'header', attr: []},
- {tag: 'hgroup', attr: []},
- {tag: 'hr', attr: []},
- {tag: 'html', attr: [
- {key: 'manifest', values: []}
- ]},
- {tag: 'i', attr: []},
- {tag: 'iframe', attr: [
- {key: 'src', values: []},
- {key: 'srcdoc', values: []},
- {key: 'name', values: []},
- {key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]},
- {key: 'seamless', values: ["","seamless"]},
- {key: 'width', values: []},
- {key: 'height', values: []}
- ]},
- {tag: 'img', attr: [
- {key: 'alt', values: []},
- {key: 'src', values: []},
- {key: 'crossorigin', values: ["anonymous","use-credentials"]},
- {key: 'ismap', values: []},
- {key: 'usemap', values: []},
- {key: 'width', values: []},
- {key: 'height', values: []}
- ]},
- {tag: 'input', attr: [
- {key: 'accept', values: ["audio/*","video/*","image/*"]},
- {key: 'alt', values: []},
- {key: 'autocomplete', values: ["on","off"]},
- {key: 'autofocus', values: ["","autofocus"]},
- {key: 'checked', values: ["","checked"]},
- {key: 'disabled', values: ["","disabled"]},
- {key: 'dirname', values: []},
- {key: 'form', values: []},
- {key: 'formaction', values: []},
- {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]},
- {key: 'formmethod', values: ["get","post","put","delete"]},
- {key: 'formnovalidate', values: ["","novalidate"]},
- {key: 'formtarget', values: ["_blank","_self","_top","_parent"]},
- {key: 'height', values: []},
- {key: 'list', values: []},
- {key: 'max', values: []},
- {key: 'maxlength', values: []},
- {key: 'min', values: []},
- {key: 'multiple', values: ["","multiple"]},
- {key: 'name', values: []},
- {key: 'pattern', values: []},
- {key: 'placeholder', values: []},
- {key: 'readonly', values: ["","readonly"]},
- {key: 'required', values: ["","required"]},
- {key: 'size', values: []},
- {key: 'src', values: []},
- {key: 'step', values: []},
- {key: 'type', values: [
- "hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local",
- "number","range","color","checkbox","radio","file","submit","image","reset","button"
- ]},
- {key: 'value', values: []},
- {key: 'width', values: []}
- ]},
- {tag: 'ins', attr: [
- {key: 'cite', values: []},
- {key: 'datetime', values: []}
- ]},
- {tag: 'kbd', attr: []},
- {tag: 'keygen', attr: [
- {key: 'autofocus', values: ["","autofocus"]},
- {key: 'challenge', values: []},
- {key: 'disabled', values: ["","disabled"]},
- {key: 'form', values: []},
- {key: 'keytype', values: ["RSA"]},
- {key: 'name', values: []}
- ]},
- {tag: 'label', attr: [
- {key: 'for', values: []},
- {key: 'form', values: []}
- ]},
- {tag: 'legend', attr: []},
- {tag: 'li', attr: [
- {key: 'value', values: []}
- ]},
- {tag: 'link', attr: [
- {key: 'href', values: []},
- {key: 'hreflang', values: ["en","es"]},
- {key: 'media', values: [
- "all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses",
- "resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3",
- "device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait",
- "orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2"
- ]},
- {key: 'type', values: []},
- {key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]}
- ]},
- {tag: 'map', attr: [
- {key: 'name', values: []}
- ]},
- {tag: 'mark', attr: []},
- {tag: 'menu', attr: [
- {key: 'type', values: ["list","context","toolbar"]},
- {key: 'label', values: []}
- ]},
- {tag: 'meta', attr: [
- {key: 'charset', attr: ["utf-8"]},
- {key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]},
- {key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]},
- {key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]}
- ]},
- {tag: 'meter', attr: [
- {key: 'value', values: []},
- {key: 'min', values: []},
- {key: 'low', values: []},
- {key: 'high', values: []},
- {key: 'max', values: []},
- {key: 'optimum', values: []}
- ]},
- {tag: 'nav', attr: []},
- {tag: 'noframes', attr: []},
- {tag: 'noscript', attr: []},
- {tag: 'object', attr: [
- {key: 'data', values: []},
- {key: 'type', values: []},
- {key: 'typemustmatch', values: ["","typemustmatch"]},
- {key: 'name', values: []},
- {key: 'usemap', values: []},
- {key: 'form', values: []},
- {key: 'width', values: []},
- {key: 'height', values: []}
- ]},
- {tag: 'ol', attr: [
- {key: 'reversed', values: ["", "reversed"]},
- {key: 'start', values: []},
- {key: 'type', values: ["1","a","A","i","I"]}
- ]},
- {tag: 'optgroup', attr: [
- {key: 'disabled', values: ["","disabled"]},
- {key: 'label', values: []}
- ]},
- {tag: 'option', attr: [
- {key: 'disabled', values: ["", "disabled"]},
- {key: 'label', values: []},
- {key: 'selected', values: ["", "selected"]},
- {key: 'value', values: []}
- ]},
- {tag: 'output', attr: [
- {key: 'for', values: []},
- {key: 'form', values: []},
- {key: 'name', values: []}
- ]},
- {tag: 'p', attr: []},
- {tag: 'param', attr: [
- {key: 'name', values: []},
- {key: 'value', values: []}
- ]},
- {tag: 'pre', attr: []},
- {tag: 'progress', attr: [
- {key: 'value', values: []},
- {key: 'max', values: []}
- ]},
- {tag: 'q', attr: [
- {key: 'cite', values: []}
- ]},
- {tag: 'rp', attr: []},
- {tag: 'rt', attr: []},
- {tag: 'ruby', attr: []},
- {tag: 's', attr: []},
- {tag: 'samp', attr: []},
- {tag: 'script', attr: [
- {key: 'type', values: ["text/javascript"]},
- {key: 'src', values: []},
- {key: 'async', values: ["","async"]},
- {key: 'defer', values: ["","defer"]},
- {key: 'charset', values: ["utf-8"]}
- ]},
- {tag: 'section', attr: []},
- {tag: 'select', attr: [
- {key: 'autofocus', values: ["", "autofocus"]},
- {key: 'disabled', values: ["", "disabled"]},
- {key: 'form', values: []},
- {key: 'multiple', values: ["", "multiple"]},
- {key: 'name', values: []},
- {key: 'size', values: []}
- ]},
- {tag: 'small', attr: []},
- {tag: 'source', attr: [
- {key: 'src', values: []},
- {key: 'type', values: []},
- {key: 'media', values: []}
- ]},
- {tag: 'span', attr: []},
- {tag: 'strike', attr: []},
- {tag: 'strong', attr: []},
- {tag: 'style', attr: [
- {key: 'type', values: ["text/css"]},
- {key: 'media', values: ["all","braille","print","projection","screen","speech"]},
- {key: 'scoped', values: []}
- ]},
- {tag: 'sub', attr: []},
- {tag: 'summary', attr: []},
- {tag: 'sup', attr: []},
- {tag: 'table', attr: [
- {key: 'border', values: []}
- ]},
- {tag: 'tbody', attr: []},
- {tag: 'td', attr: [
- {key: 'colspan', values: []},
- {key: 'rowspan', values: []},
- {key: 'headers', values: []}
- ]},
- {tag: 'textarea', attr: [
- {key: 'autofocus', values: ["","autofocus"]},
- {key: 'disabled', values: ["","disabled"]},
- {key: 'dirname', values: []},
- {key: 'form', values: []},
- {key: 'maxlength', values: []},
- {key: 'name', values: []},
- {key: 'placeholder', values: []},
- {key: 'readonly', values: ["","readonly"]},
- {key: 'required', values: ["","required"]},
- {key: 'rows', values: []},
- {key: 'cols', values: []},
- {key: 'wrap', values: ["soft","hard"]}
- ]},
- {tag: 'tfoot', attr: []},
- {tag: 'th', attr: [
- {key: 'colspan', values: []},
- {key: 'rowspan', values: []},
- {key: 'headers', values: []},
- {key: 'scope', values: ["row","col","rowgroup","colgroup"]}
- ]},
- {tag: 'thead', attr: []},
- {tag: 'time', attr: [
- {key: 'datetime', values: []}
- ]},
- {tag: 'title', attr: []},
- {tag: 'tr', attr: []},
- {tag: 'track', attr: [
- {key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]},
- {key: 'src', values: []},
- {key: 'srclang', values: ["en","es"]},
- {key: 'label', values: []},
- {key: 'default', values: []}
- ]},
- {tag: 'tt', attr: []},
- {tag: 'u', attr: []},
- {tag: 'ul', attr: []},
- {tag: 'var', attr: []},
- {tag: 'video', attr: [
- {key: "src", values: []},
- {key: "crossorigin", values: ["anonymous","use-credentials"]},
- {key: "poster", values: []},
- {key: "preload", values: ["auto","metadata","none"]},
- {key: "autoplay", values: ["","autoplay"]},
- {key: "mediagroup", values: ["movie"]},
- {key: "loop", values: ["","loop"]},
- {key: "muted", values: ["","muted"]},
- {key: "controls", values: ["","controls"]},
- {key: "width", values: []},
- {key: "height", values: []}
- ]},
- {tag: 'wbr', attr: []}
- ];
-
- var globalAttributes = [
- {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]},
- {key: "class", values: []},
- {key: "contenteditable", values: ["true", "false"]},
- {key: "contextmenu", values: []},
- {key: "dir", values: ["ltr","rtl","auto"]},
- {key: "draggable", values: ["true","false","auto"]},
- {key: "dropzone", values: ["copy","move","link","string:","file:"]},
- {key: "hidden", values: ["hidden"]},
- {key: "id", values: []},
- {key: "inert", values: ["inert"]},
- {key: "itemid", values: []},
- {key: "itemprop", values: []},
- {key: "itemref", values: []},
- {key: "itemscope", values: ["itemscope"]},
- {key: "itemtype", values: []},
- {key: "lang", values: ["en","es"]},
- {key: "spellcheck", values: ["true","false"]},
- {key: "style", values: []},
- {key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]},
- {key: "title", values: []},
- {key: "translate", values: ["yes","no"]},
- {key: "onclick", values: []},
- {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]}
- ];
-
- CodeMirror.htmlHint = function(editor) {
- if(String.prototype.trim == undefined) {
- String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');};
- }
- return htmlHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); });
- };
+ CodeMirror.htmlSchema = data;
+ function htmlHint(cm, options) {
+ var local = {schemaInfo: data};
+ if (options) for (var opt in options) local[opt] = options[opt];
+ return CodeMirror.hint.xml(cm, local);
+ }
+ CodeMirror.htmlHint = htmlHint; // deprecated
+ CodeMirror.registerHelper("hint", "html", htmlHint);
})();
diff --git a/gulliver/js/codemirror/addon/hint/javascript-hint.js b/gulliver/js/codemirror/addon/hint/javascript-hint.js
index fe2240af1..c347c206e 100644
--- a/gulliver/js/codemirror/addon/hint/javascript-hint.js
+++ b/gulliver/js/codemirror/addon/hint/javascript-hint.js
@@ -4,7 +4,7 @@
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}
-
+
function arrayContains(arr, item) {
if (!Array.prototype.indexOf) {
var i = arr.length;
@@ -21,8 +21,11 @@
function scriptHint(editor, keywords, getToken, options) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
+ if (/\b(?:string|comment)\b/.test(token.type)) return;
+ token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
+
// If it's not a 'word-style' token, ignore the token.
- if (!/^[\w$_]*$/.test(token.string)) {
+ if (!/^[\w$_]*$/.test(token.string)) {
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
type: token.string == "." ? "property" : null};
}
@@ -31,21 +34,6 @@
tprop = getToken(editor, Pos(cur.line, tprop.start));
if (tprop.string != ".") return;
tprop = getToken(editor, Pos(cur.line, tprop.start));
- if (tprop.string == ')') {
- var level = 1;
- do {
- tprop = getToken(editor, Pos(cur.line, tprop.start));
- switch (tprop.string) {
- case ')': level++; break;
- case '(': level--; break;
- default: break;
- }
- } while (level > 0);
- tprop = getToken(editor, Pos(cur.line, tprop.start));
- if (tprop.type.indexOf("variable") === 0)
- tprop.type = "function";
- else return; // no clue
- }
if (!context) var context = [];
context.push(tprop);
}
@@ -54,11 +42,13 @@
to: Pos(cur.line, token.end)};
}
- CodeMirror.javascriptHint = function(editor, options) {
+ function javascriptHint(editor, options) {
return scriptHint(editor, javascriptKeywords,
function (e, cur) {return e.getTokenAt(cur);},
options);
};
+ CodeMirror.javascriptHint = javascriptHint; // deprecated
+ CodeMirror.registerHelper("hint", "javascript", javascriptHint);
function getCoffeeScriptToken(editor, cur) {
// This getToken, it is for coffeescript, imitates the behavior of
@@ -78,9 +68,11 @@
return token;
}
- CodeMirror.coffeescriptHint = function(editor, options) {
+ function coffeescriptHint(editor, options) {
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
- };
+ }
+ CodeMirror.coffeescriptHint = coffeescriptHint; // deprecated
+ CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
"toUpperCase toLowerCase split concat match replace search").split(" ");
@@ -95,7 +87,7 @@
function getCompletions(token, context, keywords, options) {
var found = [], start = token.string;
function maybeAdd(str) {
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
}
function gatherCompletions(obj) {
if (typeof obj == "string") forEach(stringProps, maybeAdd);
@@ -104,11 +96,11 @@
for (var name in obj) maybeAdd(name);
}
- if (context) {
+ if (context && context.length) {
// If this is a property, see if it belongs to some object we can
// find in the current environment.
var obj = context.pop(), base;
- if (obj.type.indexOf("variable") === 0) {
+ if (obj.type && obj.type.indexOf("variable") === 0) {
if (options && options.additionalContext)
base = options.additionalContext[obj.string];
base = base || window[obj.string];
@@ -126,8 +118,7 @@
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
- }
- else {
+ } else {
// If not, just look in the window object and any local scope
// (reading into JS mode internals to get at the local and global variables)
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
diff --git a/gulliver/js/codemirror/addon/hint/php-hint.js b/gulliver/js/codemirror/addon/hint/php-hint.js
deleted file mode 100644
index 9723cb250..000000000
--- a/gulliver/js/codemirror/addon/hint/php-hint.js
+++ /dev/null
@@ -1,267 +0,0 @@
-(function () {
- var Pos = CodeMirror.Pos;
-
- function forEach(arr, f) {
- for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
- }
-
- function arrayContains(arr, item) {
- if (!Array.prototype.indexOf) {
- var i = arr.length;
- while (i--) {
- if (arr[i] === item) {
- return true;
- }
- }
- return false;
- }
- return arr.indexOf(item) != -1;
- }
-
- function scriptHint(editor, keywords, getToken, options) {
- // Find the token at the cursor
- var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
- var sToken = token.string.trim();
-
- if ( sToken == "(") {
- token = tprop = getToken(editor, Pos(cur.line, tprop.start));
- return {list: getCompletions(token.string, keywords, options),
- from: Pos(cur.line, token.start),
- to: Pos(cur.line, token.end + 1)};
- }
- if ( sToken == "=") {
- return {list: getCompletions(token.string, keywords, options),
- from: Pos(cur.line, token.start + 1),
- to: Pos(cur.line, token.end)};
- }
- return {list: getCompletions(token.string, keywords, options),
- from: Pos(cur.line, token.start),
- to: Pos(cur.line, token.end)};
- }
-
- CodeMirror.phpHint = function(editor, options) {
- return scriptHint(editor, phpPMFunctions, function (e, cur) {return e.getTokenAt(cur);}, options);
- };
-
- var SPACE = " ";
- var arrayFunctions = [];
-
- var formatDate = "formatDate";
- var formatDateFunction = [formatDate+"($date,$format,$language);",formatDate+"($date,$format);"];
- arrayFunctions[formatDate] = formatDateFunction;
-
- var getCurrentDate = "getCurrentDate";
- var getCurrentDateFunction = [getCurrentDate+"()"];
- arrayFunctions[getCurrentDate] = getCurrentDateFunction;
-
- var getCurrentTime = "getCurrentTime";
- var getCurrentTimeFunction = [getCurrentTime+"()"];
- arrayFunctions[getCurrentTime] = getCurrentTimeFunction;
-
- var literalDate = "literalDate";
- var literalDateFunction = [literalDate+"($date,$Language)",literalDate+"($date)"];
- arrayFunctions[literalDate] = literalDateFunction;
-
- var capitalize = "capitalize";
- var capitalizeFunction = [capitalize+"($textToConvert)"];
- arrayFunctions[capitalize] = capitalizeFunction;
-
- var lowerCase = "lowerCase";
- var lowerCaseFunction = [lowerCase+"($textToConvert)"];
- arrayFunctions[lowerCase] = lowerCaseFunction;
-
- var upperCase = "upperCase";
- var upperCaseFunction = [upperCase+"($textToConvert)"];
- arrayFunctions[upperCase] = upperCaseFunction;
-
- var userInfo = "userInfo";
- var userInfoFunction = [userInfo+"($USER_ID)"];
- arrayFunctions[userInfo] = userInfoFunction;
-
- var executeQuery = "executeQuery";
- var executeQueryFunction = [executeQuery+"($sqlStatement,$DBConnectionUID)",executeQuery+"($sqlStatement)"];
- arrayFunctions[executeQuery] = executeQueryFunction;
-
- var orderGrid = "orderGrid";
- var orderGridFunction = ("orderGrid($gridName,$field,$criteria) orderGrid($gridName,$field)").split(SPACE);
- arrayFunctions[orderGrid] = orderGridFunction;
-
- var evaluateFunction = "evaluateFunction";
- var evaluateFunctionFunction = [evaluateFunction+"($gridName,$Expression)"];
- arrayFunctions[evaluateFunction] = evaluateFunctionFunction;
-
- var PMFTaskCase = "PMFTaskCase";
- var PMFTaskCaseFunction = [PMFTaskCase+"($caseId)"];
- arrayFunctions[PMFTaskCase] = PMFTaskCaseFunction;
-
- var PMFTaskList = "PMFTaskList";
- var PMFTaskListFunction = [PMFTaskList+"($userId)"];
- arrayFunctions[PMFTaskList] = PMFTaskListFunction;
-
- var PMFUserList = "PMFUserList";
- var PMFUserListFunction = [PMFUserList+"()"];
- arrayFunctions[PMFUserList] = PMFUserListFunction;
-
- var PMFGroupList = "PMFGroupList";
- var PMFGroupListFunction = [PMFGroupList+"()"];
- arrayFunctions[PMFGroupList] = PMFGroupListFunction;
-
- var PMFRoleList = "PMFRoleList";
- var PMFRoleListFunction = [PMFRoleList+"()"];
- arrayFunctions[PMFRoleList] = PMFRoleListFunction;
-
- var PMFCaseList = "PMFCaseList";
- var PMFCaseListFunction = [PMFCaseList+"($userId)",PMFCaseList+"()"];
- arrayFunctions[PMFCaseList] = PMFCaseListFunction;
-
- var PMFProcessList = "PMFProcessList";
- var PMFProcessListFunction = [PMFProcessList+"()"];
- arrayFunctions[PMFProcessList] = PMFProcessListFunction;
-
- var PMFSendVariables = "PMFSendVariables";
- var PMFSendVariablesFunction = [PMFSendVariables+"($caseId,$variables)"];
- arrayFunctions[PMFSendVariables] = PMFSendVariablesFunction;
-
- var PMFDerivateCase = "PMFDerivateCase";
- var PMFDerivateCaseFunction = [PMFDerivateCase+"($caseId,$delegation,$executeTriggersBeforeAssigment)",PMFDerivateCase+"($caseId,$delegation)"];
- arrayFunctions[PMFDerivateCase] = PMFDerivateCaseFunction;
-
- var PMFNewCaseImpersonate = "PMFNewCaseImpersonate";
- var PMFNewCaseImpersonateFunction = [PMFNewCaseImpersonate+"($processId,$userId,$variables)"];
- arrayFunctions[PMFNewCaseImpersonate] = PMFNewCaseImpersonateFunction;
-
- var PMFNewCase = "PMFNewCase";
- var PMFNewCaseFunction = [PMFNewCase+"($processId,$userId,$taskId,$variables)"];
- arrayFunctions[PMFNewCase] = PMFNewCaseFunction;
-
- var PMFPauseCase = "PMFPauseCase";
- var PMFPauseCaseFunction = [PMFPauseCase+"($caseUid,$delIndex,$userUid,$unpauseDate)",PMFPauseCase+"($caseUid,$delIndex,$userUid)"];
- arrayFunctions[PMFPauseCase] = PMFPauseCaseFunction;
-
- var PMFAssignUserToGroup = "PMFAssignUserToGroup";
- var PMFAssignUserToGroupFunction = [PMFAssignUserToGroup+"($userId,$groupId)"];
- arrayFunctions[PMFAssignUserToGroup] = PMFAssignUserToGroupFunction;
-
- var PMFCreateUser = "PMFCreateUser";
- var PMFCreateUserFunction = [PMFCreateUser+"($userId,$password,$firstname,$lastname,$email,$role)"];
- arrayFunctions[PMFCreateUser] = PMFCreateUserFunction;
-
- var PMFUpdateUser = "PMFUpdateUser";
- var PMFUpdateUserFunction = [PMFUpdateUser+"($userUid,$userName,$firstName,$lastName,$email,$dueDate,$status,$role,$password)"];
- arrayFunctions[PMFUpdateUser] = PMFUpdateUserFunction;
-
- var PMFInformationUser = "PMFInformationUser";
- var PMFInformationUserFunction = [PMFInformationUser+"($userUid)"];
- arrayFunctions[PMFInformationUser] = PMFInformationUserFunction;
-
- var generateCode = "generateCode";
- var generateCodeFunction = [generateCode+"($size,$type)"];
- arrayFunctions[generateCode] = generateCodeFunction;
-
- var setCaseTrackerCode = "setCaseTrackerCode";
- var setCaseTrackerCodeFunction = [setCaseTrackerCode+"($caseId,$code,$pin)"];
- arrayFunctions[setCaseTrackerCode] = setCaseTrackerCodeFunction;
-
- var jumping = "jumping";
- var jumpingFunction = [jumping+"($caseId,$delegation)"];
- arrayFunctions[jumping] = jumpingFunction;
-
- var PMFRedirectToStep = "PMFRedirectToStep";
- var PMFRedirectToStepFunction = [PMFRedirectToStep+"($caseId,$delegation,$stepType,$stepId)"];
- arrayFunctions[PMFRedirectToStep] = PMFRedirectToStepFunction;
-
- var pauseCase = "pauseCase";
- var pauseCaseFunction = [pauseCase+"($caseId,$delegation,$userId,$unpauseDate)",pauseCase+"($caseId,$delegation,$userId)"];
- arrayFunctions[pauseCase] = pauseCaseFunction;
-
- var PMFUnpauseCase = "PMFUnpauseCase";
- var PMFUnpauseCaseFunction = [PMFUnpauseCase+"($caseId,$delegation,$userId,$unpauseDate)",PMFUnpauseCase+"($caseId,$delegation,$userId)"];
- arrayFunctions[PMFUnpauseCase] = PMFUnpauseCaseFunction;
-
- var PMFSendMessage = "PMFSendMessage";
- var PMFSendMessageFunction = [PMFSendMessage+"($caseId,$from,$to,$cc,$bcc,$subject,$template,$fields,$attachments)",PMFSendMessage+"($caseId,$from,$to,$cc,$bcc,$subject,$template,$fields)",PMFSendMessage+"($caseId,$from,$to,$cc,$bcc,$subject,$template)"];
- arrayFunctions[PMFSendMessage] = PMFSendMessageFunction;
-
- var PMFgetLabelOption = "PMFgetLabelOption";
- var PMFgetLabelOptionFunction = [PMFgetLabelOption+"($processId,$dynaformId,$fieldName,$optionId)"];
- arrayFunctions[PMFgetLabelOption] = PMFgetLabelOptionFunction;
-
- var PMFGenerateOutputDocument = "PMFGenerateOutputDocument";
- var PMFGenerateOutputDocumentFunction = [PMFGenerateOutputDocument+"($outputID)"];
- arrayFunctions[PMFGenerateOutputDocument] = PMFGenerateOutputDocumentFunction;
-
- var PMFGetUserEmailAddress = "PMFGetUserEmailAddress";
- var PMFGetUserEmailAddressFunction = [PMFGetUserEmailAddress+"($id,$APP_UID,$prefix)",PMFGetUserEmailAddress+"($id,$APP_UID)",PMFGetUserEmailAddress+"($id)"];
- arrayFunctions[PMFGetUserEmailAddress] = PMFGetUserEmailAddressFunction;
-
- var PMFGetNextAssignedUser = "PMFGetNextAssignedUser";
- var PMFGetNextAssignedUserFunction = (PMFGetNextAssignedUser+"($application,$task)").split(SPACE);
- arrayFunctions[PMFGetNextAssignedUser] = PMFGetNextAssignedUserFunction;
-
- var PMFDeleteCase = "PMFDeleteCase";
- var PMFDeleteCaseFunction = ("PMFDeleteCase($caseId)").split(SPACE);
- arrayFunctions[PMFDeleteCase] = PMFDeleteCaseFunction;
-
- var PMFCancelCase = "PMFCancelCase";
- var PMFCancelCaseFunction = [PMFCancelCase+"($caseUid,$delIndex,$userUid)"];
- arrayFunctions[PMFCancelCase] = PMFCancelCaseFunction;
-
- var PMFAddInputDocument = "PMFAddInputDocument";
- var PMFAddInputDocumentFunction = [PMFAddInputDocument+"($inputDocumentUid,$appDocUid,$docVersion,$appDocType,$appDocComment,$inputDocumentAction,$caseUid,$delIndex,$taskUid,$userUid,$option,$file)",PMFAddInputDocument+"($inputDocumentUid,$appDocUid,$docVersion,$appDocType,$appDocComment,$inputDocumentAction,$caseUid,$delIndex,$taskUid,$userUid,$option)",PMFAddInputDocument+"($inputDocumentUid,$appDocUid,$docVersion,$appDocType,$appDocComment,$inputDocumentAction,$caseUid,$delIndex,$taskUid,$userUid)"];
- arrayFunctions[PMFAddInputDocument] = PMFAddInputDocumentFunction;
-
- var PMFAddCaseNote = "PMFAddCaseNote";
- var PMFAddCaseNoteFunction = [PMFAddCaseNote+"($caseUid,$processUid,$taskUid,$userUid,$note,$sendMail)"];
- arrayFunctions[PMFAddCaseNote] = PMFAddCaseNoteFunction;
-
- var PMFGetCaseNotes = "PMFGetCaseNotes";
- var PMFGetCaseNotesFunction = [PMFGetCaseNotes+"($applicationID,$type,$userUid);",PMFGetCaseNotes+"($applicationID,$type)",PMFGetCaseNotes+"($applicationID)"];
- arrayFunctions[PMFGetCaseNotes] = PMFGetCaseNotesFunction;
-
- var phpPMFunctions = [formatDate,getCurrentDate,getCurrentTime,literalDate,capitalize,lowerCase,upperCase,userInfo,executeQuery,orderGrid,
- evaluateFunction,PMFTaskCase,PMFTaskList,PMFUserList,PMFGroupList,PMFRoleList,PMFCaseList,PMFProcessList,PMFSendVariables,PMFDerivateCase,
- PMFNewCaseImpersonate,PMFNewCase,PMFPauseCase,PMFUnpauseCase,PMFAssignUserToGroup,PMFCreateUser,PMFUpdateUser,PMFInformationUser,
- generateCode,setCaseTrackerCode,jumping,PMFRedirectToStep,pauseCase,PMFSendMessage,PMFgetLabelOption,PMFGenerateOutputDocument,
- PMFGetUserEmailAddress,PMFGetNextAssignedUser,PMFDeleteCase,PMFCancelCase,PMFAddInputDocument,PMFAddCaseNote,PMFGetCaseNotes];
-
- var phpKeywords = ("break case catch continue default do else false for function " +
- "if new return switch throw true try var while").split(SPACE);
-
- function getCompletions(functionName, keywords, options) {
-
- var found = [];
-
- function maybeAdd(str) {// for keywords ?
- if ( str.indexOf(functionName) == 0 && !arrayContains(found, str)) {
- found.push(str);
- }
- }
-
- function yesAdd(str) {
- if ( !arrayContains(found, str)) {
- found.push(str);
- }
- }
-
- arrayFunction = arrayFunctions[functionName];
-
- if (arrayFunction != undefined) {
- forEach( arrayFunction, yesAdd);
- } else {
- if (functionName.trim() == "") {
- forEach (phpKeywords, yesAdd);
- forEach (keywords, yesAdd);
- } else if (functionName == "=") {
- forEach (phpPMFunctions, yesAdd);
- } else {
- for (index = 0; index < phpKeywords.length; index++) {
- if ( phpKeywords[index].indexOf(functionName) == 0 ) {
- found.push(phpKeywords[index]);
- }
- }
- forEach(keywords, maybeAdd);
- }
- }
- return found;
- }
-})();
diff --git a/gulliver/js/codemirror/addon/hint/pig-hint.js b/gulliver/js/codemirror/addon/hint/pig-hint.js
index 9847996be..6c0c52377 100644
--- a/gulliver/js/codemirror/addon/hint/pig-hint.js
+++ b/gulliver/js/codemirror/addon/hint/pig-hint.js
@@ -1,8 +1,10 @@
(function () {
+ "use strict";
+
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}
-
+
function arrayContains(arr, item) {
if (!Array.prototype.indexOf) {
var i = arr.length;
@@ -25,11 +27,11 @@
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
className: token.string == ":" ? "pig-type" : null};
}
-
+
if (!context) var context = [];
context.push(tprop);
-
- var completionList = getCompletions(token, context);
+
+ var completionList = getCompletions(token, context);
completionList = completionList.sort();
//prevent autocomplete for last word, instead show dropdown with one word
if(completionList.length == 1) {
@@ -40,24 +42,26 @@
from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)};
}
-
- CodeMirror.pigHint = function(editor) {
+
+ function pigHint(editor) {
return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
- };
-
+ }
+ CodeMirror.pigHint = pigHint; // deprecated
+ CodeMirror.registerHelper("hint", "pig", pigHint);
+
var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
- + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ "NEQ MATCHES TRUE FALSE";
var pigKeywordsU = pigKeywords.split(" ");
var pigKeywordsL = pigKeywords.toLowerCase().split(" ");
-
+
var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP";
var pigTypesU = pigTypes.split(" ");
var pigTypesL = pigTypes.toLowerCase().split(" ");
-
- var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+
+ var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
@@ -66,9 +70,9 @@
+ "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
- + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
- var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
- var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
+ var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
+ var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs "
+ "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax "
+ "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum "
@@ -76,13 +80,13 @@
+ "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize "
+ "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax "
+ "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" ");
-
+
function getCompletions(token, context) {
var found = [], start = token.string;
function maybeAdd(str) {
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
}
-
+
function gatherCompletions(obj) {
if(obj == ":") {
forEach(pigTypesL, maybeAdd);
@@ -103,11 +107,11 @@
// find in the current environment.
var obj = context.pop(), base;
- if (obj.type == "variable")
+ if (obj.type == "variable")
base = obj.string;
else if(obj.type == "variable-3")
base = ":" + obj.string;
-
+
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
diff --git a/gulliver/js/codemirror/addon/hint/python-hint.js b/gulliver/js/codemirror/addon/hint/python-hint.js
index 60221b89e..248284e8c 100644
--- a/gulliver/js/codemirror/addon/hint/python-hint.js
+++ b/gulliver/js/codemirror/addon/hint/python-hint.js
@@ -31,19 +31,17 @@
var completionList = getCompletions(token, context);
completionList = completionList.sort();
- //prevent autocomplete for last word, instead show dropdown with one word
- if(completionList.length == 1) {
- completionList.push(" ");
- }
return {list: completionList,
from: CodeMirror.Pos(cur.line, token.start),
to: CodeMirror.Pos(cur.line, token.end)};
}
- CodeMirror.pythonHint = function(editor) {
+ function pythonHint(editor) {
return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
- };
+ }
+ CodeMirror.pythonHint = pythonHint; // deprecated
+ CodeMirror.registerHelper("hint", "python", pythonHint);
var pythonKeywords = "and del from not while as elif global or with assert else if pass yield"
+ "break except import print class exec in raise continue finally is return def for lambda try";
@@ -64,7 +62,7 @@
function getCompletions(token, context) {
var found = [], start = token.string;
function maybeAdd(str) {
- if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
+ if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
}
function gatherCompletions(_obj) {
diff --git a/gulliver/js/codemirror/addon/hint/show-hint.css b/gulliver/js/codemirror/addon/hint/show-hint.css
index 47fb7921f..8a4ff052e 100644
--- a/gulliver/js/codemirror/addon/hint/show-hint.css
+++ b/gulliver/js/codemirror/addon/hint/show-hint.css
@@ -25,7 +25,7 @@
margin: 0;
padding: 0 4px;
border-radius: 2px;
- max-width: 150em;
+ max-width: 19em;
overflow: hidden;
white-space: pre;
color: black;
diff --git a/gulliver/js/codemirror/addon/hint/show-hint.js b/gulliver/js/codemirror/addon/hint/show-hint.js
index 42e8caac7..7e03d1139 100644
--- a/gulliver/js/codemirror/addon/hint/show-hint.js
+++ b/gulliver/js/codemirror/addon/hint/show-hint.js
@@ -1,80 +1,199 @@
-CodeMirror.showHint = function(cm, getHints, options) {
- if (!options) options = {};
- var startCh = cm.getCursor().ch, continued = false;
- var closeOn = options.closeCharacters || /[\s()\[\]{};:]/;
+(function() {
+ "use strict";
- function startHinting() {
+ var HINT_ELEMENT_CLASS = "CodeMirror-hint";
+ var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
+
+ CodeMirror.showHint = function(cm, getHints, options) {
// We want a single cursor position.
if (cm.somethingSelected()) return;
+ if (getHints == null) {
+ if (options && options.async) return;
+ else getHints = CodeMirror.hint.auto;
+ }
- if (options.async)
- getHints(cm, showHints, options);
+ if (cm.state.completionActive) cm.state.completionActive.close();
+
+ var completion = cm.state.completionActive = new Completion(cm, getHints, options || {});
+ CodeMirror.signal(cm, "startCompletion", cm);
+ if (completion.options.async)
+ getHints(cm, function(hints) { completion.showHints(hints); }, completion.options);
else
- return showHints(getHints(cm, options));
+ return completion.showHints(getHints(cm, completion.options));
+ };
+
+ function Completion(cm, getHints, options) {
+ this.cm = cm;
+ this.getHints = getHints;
+ this.options = options;
+ this.widget = this.onClose = null;
}
+ Completion.prototype = {
+ close: function() {
+ if (!this.active()) return;
+ this.cm.state.completionActive = null;
+
+ if (this.widget) this.widget.close();
+ if (this.onClose) this.onClose();
+ CodeMirror.signal(this.cm, "endCompletion", this.cm);
+ },
+
+ active: function() {
+ return this.cm.state.completionActive == this;
+ },
+
+ pick: function(data, i) {
+ var completion = data.list[i];
+ if (completion.hint) completion.hint(this.cm, data, completion);
+ else this.cm.replaceRange(getText(completion), data.from, data.to);
+ CodeMirror.signal(data, "pick", completion);
+ this.close();
+ },
+
+ showHints: function(data) {
+ if (!data || !data.list.length || !this.active()) return this.close();
+
+ if (this.options.completeSingle != false && data.list.length == 1)
+ this.pick(data, 0);
+ else
+ this.showWidget(data);
+ },
+
+ showWidget: function(data) {
+ this.widget = new Widget(this, data);
+ CodeMirror.signal(data, "shown");
+
+ var debounce = 0, completion = this, finished;
+ var closeOn = this.options.closeCharacters || /[\s()\[\]{};:>,]/;
+ var startPos = this.cm.getCursor(), startLen = this.cm.getLine(startPos.line).length;
+
+ var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
+ return setTimeout(fn, 1000/60);
+ };
+ var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
+
+ function done() {
+ if (finished) return;
+ finished = true;
+ completion.close();
+ completion.cm.off("cursorActivity", activity);
+ if (data) CodeMirror.signal(data, "close");
+ }
+
+ function update() {
+ if (finished) return;
+ CodeMirror.signal(data, "update");
+ if (completion.options.async)
+ completion.getHints(completion.cm, finishUpdate, completion.options);
+ else
+ finishUpdate(completion.getHints(completion.cm, completion.options));
+ }
+ function finishUpdate(data_) {
+ data = data_;
+ if (finished) return;
+ if (!data || !data.list.length) return done();
+ completion.widget = new Widget(completion, data);
+ }
+
+ function clearDebounce() {
+ if (debounce) {
+ cancelAnimationFrame(debounce);
+ debounce = 0;
+ }
+ }
+
+ function activity() {
+ clearDebounce();
+ var pos = completion.cm.getCursor(), line = completion.cm.getLine(pos.line);
+ if (pos.line != startPos.line || line.length - pos.ch != startLen - startPos.ch ||
+ pos.ch < startPos.ch || completion.cm.somethingSelected() ||
+ (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) {
+ completion.close();
+ } else {
+ debounce = requestAnimationFrame(update);
+ if (completion.widget) completion.widget.close();
+ }
+ }
+ this.cm.on("cursorActivity", activity);
+ this.onClose = done;
+ }
+ };
+
function getText(completion) {
if (typeof completion == "string") return completion;
else return completion.text;
}
- function pickCompletion(cm, data, completion) {
- if (completion.hint) completion.hint(cm, data, completion);
- else cm.replaceRange(getText(completion), data.from, data.to);
+ function buildKeyMap(options, handle) {
+ var baseMap = {
+ Up: function() {handle.moveFocus(-1);},
+ Down: function() {handle.moveFocus(1);},
+ PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
+ PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
+ Home: function() {handle.setFocus(0);},
+ End: function() {handle.setFocus(handle.length - 1);},
+ Enter: handle.pick,
+ Tab: handle.pick,
+ Esc: handle.close
+ };
+ var ourMap = options.customKeys ? {} : baseMap;
+ function addBinding(key, val) {
+ var bound;
+ if (typeof val != "string")
+ bound = function(cm) { return val(cm, handle); };
+ // This mechanism is deprecated
+ else if (baseMap.hasOwnProperty(val))
+ bound = baseMap[val];
+ else
+ bound = val;
+ ourMap[key] = bound;
+ }
+ if (options.customKeys)
+ for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key))
+ addBinding(key, options.customKeys[key]);
+ if (options.extraKeys)
+ for (var key in options.extraKeys) if (options.extraKeys.hasOwnProperty(key))
+ addBinding(key, options.extraKeys[key]);
+ return ourMap;
}
- function getMaxAccordingList(list) {
- var max = 0;
- for (var i = 0; i < list.length; i++) {
- if (list[i].length > max)
- max = list[i].length;
+ function getHintElement(hintsElement, el) {
+ while (el && el != hintsElement) {
+ if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
+ el = el.parentNode;
}
- return max;
}
- function showHints(data) {
- if (!data || !data.list.length) return;
- var completions = data.list;
- var maxWidth = getMaxAccordingList(data.list);
- // When there is only one completion, use it directly.
- if (!continued && options.completeSingle !== false && completions.length == 1) {
- pickCompletion(cm, data, completions[0]);
- return true;
- }
+ function Widget(completion, data) {
+ this.completion = completion;
+ this.data = data;
+ var widget = this, cm = completion.cm, options = completion.options;
- // Build the select widget
- var hints = document.createElement("ul"), selectedHint = 0;
+ var hints = this.hints = document.createElement("ul");
hints.className = "CodeMirror-hints";
- for (var i = 0; i < completions.length; ++i) {
- var elt = hints.appendChild(document.createElement("li")), completion = completions[i];
- var className = "CodeMirror-hint" + (i ? "" : " CodeMirror-hint-active");
- if (completion.className != null) className = completion.className + " " + className;
+ this.selectedHint = options.getDefaultSelection ? options.getDefaultSelection(cm,options,data) : 0;
+
+ var completions = data.list;
+ for (var i = 0; i < completions.length; ++i) {
+ var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
+ var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
+ if (cur.className != null) className = cur.className + " " + className;
elt.className = className;
- if (completion.render) {completion.render(elt, data, completion);}
- else elt.appendChild(document.createTextNode(getText(completion)));
+ if (cur.render) cur.render(elt, data, cur);
+ else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
elt.hintId = i;
}
-
+
var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null);
var left = pos.left, top = pos.bottom, below = true;
hints.style.left = left + "px";
hints.style.top = top + "px";
- hints.style.width = (maxWidth * 18) + "px";
-
- ie = /MSIE \d/.test(navigator.userAgent);
- if( ie.length > 0 ) {
- hints.style.left = (left + 2) + "px";
- hints.style.top = (top + 20) + "px";
- }
-
- hints.style.zIndex = "5000";
- document.body.appendChild(hints);
-
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
+ (options.container || document.body).appendChild(hints);
var box = hints.getBoundingClientRect();
-
var overlapX = box.right - winW, overlapY = box.bottom - winH;
if (overlapX > 0) {
if (box.right - box.left > winW) {
@@ -95,99 +214,122 @@ CodeMirror.showHint = function(cm, getHints, options) {
hints.style.top = (top = pos.bottom - overlapY) + "px";
}
- function changeActive(i) {
- i = Math.max(0, Math.min(i, completions.length - 1));
- if (selectedHint == i) return;
- var node = hints.childNodes[selectedHint];
- node.className = node.className.replace(" CodeMirror-hint-active", "");
- node = hints.childNodes[selectedHint = i];
- node.className += " CodeMirror-hint-active";
- if (node.offsetTop < hints.scrollTop)
- hints.scrollTop = node.offsetTop - 3;
- else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight)
- hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3;
+ cm.addKeyMap(this.keyMap = buildKeyMap(options, {
+ moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
+ setFocus: function(n) { widget.changeActive(n); },
+ menuSize: function() { return widget.screenAmount(); },
+ length: completions.length,
+ close: function() { completion.close(); },
+ pick: function() { widget.pick(); }
+ }));
+
+ if (options.closeOnUnfocus !== false) {
+ var closingOnBlur;
+ cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
+ cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
}
- function screenAmount() {
- return Math.floor(hints.clientHeight / hints.firstChild.offsetHeight) || 1;
- }
-
- var ourMap = {
- Up: function() {changeActive(selectedHint - 1);},
- Down: function() {changeActive(selectedHint + 1);},
- PageUp: function() {changeActive(selectedHint - screenAmount());},
- PageDown: function() {changeActive(selectedHint + screenAmount());},
- Home: function() {changeActive(0);},
- End: function() {changeActive(completions.length - 1);},
- Enter: pick,
- Tab: pick,
- Esc: close
- };
- if (options.customKeys) for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) {
- var val = options.customKeys[key];
- if (/^(Up|Down|Enter|Esc)$/.test(key)) val = ourMap[val];
- ourMap[key] = val;
- }
-
- cm.addKeyMap(ourMap);
- cm.on("cursorActivity", cursorActivity);
- var closingOnBlur;
- function onBlur(){ closingOnBlur = setTimeout(close, 100); };
- function onFocus(){ clearTimeout(closingOnBlur); };
- cm.on("blur", onBlur);
- cm.on("focus", onFocus);
var startScroll = cm.getScrollInfo();
- function onScroll() {
+ cm.on("scroll", this.onScroll = function() {
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
- var newTop = top + startScroll.top - curScroll.top, point = newTop;
+ var newTop = top + startScroll.top - curScroll.top;
+ var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
if (!below) point += hints.offsetHeight;
- if (point <= editor.top || point >= editor.bottom) return close();
+ if (point <= editor.top || point >= editor.bottom) return completion.close();
hints.style.top = newTop + "px";
hints.style.left = (left + startScroll.left - curScroll.left) + "px";
- }
- cm.on("scroll", onScroll);
+ });
+
CodeMirror.on(hints, "dblclick", function(e) {
- var t = e.target || e.srcElement;
- if (t.hintId != null) {selectedHint = t.hintId; pick();}
+ var t = getHintElement(hints, e.target || e.srcElement);
+ if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
});
+
CodeMirror.on(hints, "click", function(e) {
- var t = e.target || e.srcElement;
- if (t.hintId != null) changeActive(t.hintId);
+ var t = getHintElement(hints, e.target || e.srcElement);
+ if (t && t.hintId != null) {
+ widget.changeActive(t.hintId);
+ if (options.completeOnSingleClick) widget.pick();
+ }
});
+
CodeMirror.on(hints, "mousedown", function() {
setTimeout(function(){cm.focus();}, 20);
});
- var done = false, once;
- function close() {
- if (done) return;
- done = true;
- clearTimeout(once);
- hints.parentNode.removeChild(hints);
- cm.removeKeyMap(ourMap);
- cm.off("cursorActivity", cursorActivity);
- cm.off("blur", onBlur);
- cm.off("focus", onFocus);
- cm.off("scroll", onScroll);
- }
- function pick() {
- pickCompletion(cm, data, completions[selectedHint]);
- close();
- }
- var once, lastPos = cm.getCursor(), lastLen = cm.getLine(lastPos.line).length;
- function cursorActivity() {
- clearTimeout(once);
-
- var pos = cm.getCursor(), line = cm.getLine(pos.line);
- if (pos.line != lastPos.line || line.length - pos.ch != lastLen - lastPos.ch ||
- pos.ch < startCh || cm.somethingSelected() ||
- (pos.ch && closeOn.test(line.charAt(pos.ch - 1))))
- close();
- else
- once = setTimeout(function(){close(); continued = true; startHinting();}, 70);
- }
+ CodeMirror.signal(data, "select", completions[0], hints.firstChild);
return true;
}
- return startHinting();
-};
+ Widget.prototype = {
+ close: function() {
+ if (this.completion.widget != this) return;
+ this.completion.widget = null;
+ this.hints.parentNode.removeChild(this.hints);
+ this.completion.cm.removeKeyMap(this.keyMap);
+
+ var cm = this.completion.cm;
+ if (this.completion.options.closeOnUnfocus !== false) {
+ cm.off("blur", this.onBlur);
+ cm.off("focus", this.onFocus);
+ }
+ cm.off("scroll", this.onScroll);
+ },
+
+ pick: function() {
+ this.completion.pick(this.data, this.selectedHint);
+ },
+
+ changeActive: function(i, avoidWrap) {
+ if (i >= this.data.list.length)
+ i = avoidWrap ? this.data.list.length - 1 : 0;
+ else if (i < 0)
+ i = avoidWrap ? 0 : this.data.list.length - 1;
+ if (this.selectedHint == i) return;
+ var node = this.hints.childNodes[this.selectedHint];
+ node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
+ node = this.hints.childNodes[this.selectedHint = i];
+ node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
+ if (node.offsetTop < this.hints.scrollTop)
+ this.hints.scrollTop = node.offsetTop - 3;
+ else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
+ this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+ CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
+ },
+
+ screenAmount: function() {
+ return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
+ }
+ };
+
+ CodeMirror.registerHelper("hint", "auto", function(cm, options) {
+ var helpers = cm.getHelpers(cm.getCursor(), "hint");
+ if (helpers.length) {
+ for (var i = 0; i < helpers.length; i++) {
+ var cur = helpers[i](cm, options);
+ if (cur && cur.list.length) return cur;
+ }
+ } else {
+ var words = cm.getHelper(cm.getCursor(), "hintWords");
+ if (words) return CodeMirror.hint.fromList(cm, {words: words});
+ }
+ });
+
+ CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+ var found = [];
+ for (var i = 0; i < options.words.length; i++) {
+ var word = options.words[i];
+ if (word.slice(0, token.string.length) == token.string)
+ found.push(word);
+ }
+
+ if (found.length) return {
+ list: found,
+ from: CodeMirror.Pos(cur.line, token.start),
+ to: CodeMirror.Pos(cur.line, token.end)
+ };
+ });
+
+ CodeMirror.commands.autocomplete = CodeMirror.showHint;
+})();
diff --git a/gulliver/js/codemirror/addon/hint/sql-hint.js b/gulliver/js/codemirror/addon/hint/sql-hint.js
new file mode 100644
index 000000000..d00781cff
--- /dev/null
+++ b/gulliver/js/codemirror/addon/hint/sql-hint.js
@@ -0,0 +1,146 @@
+(function () {
+ "use strict";
+
+ var tables;
+ var keywords;
+ var CONS = {
+ QUERY_DIV: ";",
+ ALIAS_KEYWORD: "AS"
+ };
+
+ function getKeywords(editor) {
+ var mode = editor.doc.modeOption;
+ if(mode === "sql") mode = "text/x-sql";
+ return CodeMirror.resolveMode(mode).keywords;
+ }
+
+ function match(string, word) {
+ var len = string.length;
+ var sub = word.substr(0, len);
+ return string.toUpperCase() === sub.toUpperCase();
+ }
+
+ function addMatches(result, search, wordlist, formatter) {
+ for(var word in wordlist) {
+ if(!wordlist.hasOwnProperty(word)) continue;
+ if(Array.isArray(wordlist)) {
+ word = wordlist[word];
+ }
+ if(match(search, word)) {
+ result.push(formatter(word));
+ }
+ }
+ }
+
+ function columnCompletion(result, editor) {
+ var cur = editor.getCursor();
+ var token = editor.getTokenAt(cur);
+ var string = token.string.substr(1);
+ var prevCur = CodeMirror.Pos(cur.line, token.start);
+ var table = editor.getTokenAt(prevCur).string;
+ if( !tables.hasOwnProperty( table ) ){
+ table = findTableByAlias(table, editor);
+ }
+ var columns = tables[table];
+ if(!columns) {
+ return;
+ }
+ addMatches(result, string, columns,
+ function(w) {return "." + w;});
+ }
+
+ function eachWord(lineText, f) {
+ if( !lineText ){return;}
+ var excepted = /[,;]/g;
+ var words = lineText.split( " " );
+ for( var i = 0; i < words.length; i++ ){
+ f( words[i]?words[i].replace( excepted, '' ) : '' );
+ }
+ }
+
+ function convertCurToNumber( cur ){
+ // max characters of a line is 999,999.
+ return cur.line + cur.ch / Math.pow( 10, 6 );
+ }
+
+ function convertNumberToCur( num ){
+ return CodeMirror.Pos(Math.floor( num ), +num.toString().split( '.' ).pop());
+ }
+
+ function findTableByAlias(alias, editor) {
+ var doc = editor.doc;
+ var fullQuery = doc.getValue();
+ var aliasUpperCase = alias.toUpperCase();
+ var previousWord = "";
+ var table = "";
+ var separator = [];
+ var validRange = {
+ start: CodeMirror.Pos( 0, 0 ),
+ end: CodeMirror.Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).length )
+ };
+
+ //add separator
+ var indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV );
+ while( indexOfSeparator != -1 ){
+ separator.push( doc.posFromIndex(indexOfSeparator));
+ indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV, indexOfSeparator+1);
+ }
+ separator.unshift( CodeMirror.Pos( 0, 0 ) );
+ separator.push( CodeMirror.Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).text.length ) );
+
+ //find valieRange
+ var prevItem = 0;
+ var current = convertCurToNumber( editor.getCursor() );
+ for( var i=0; i< separator.length; i++){
+ var _v = convertCurToNumber( separator[i] );
+ if( current > prevItem && current <= _v ){
+ validRange = { start: convertNumberToCur( prevItem ), end: convertNumberToCur( _v ) };
+ break;
+ }
+ prevItem = _v;
+ }
+
+ var query = doc.getRange(validRange.start, validRange.end, false);
+
+ for(var i=0; i < query.length; i++){
+ var lineText = query[i];
+ eachWord( lineText, function( word ){
+ var wordUpperCase = word.toUpperCase();
+ if( wordUpperCase === aliasUpperCase && tables.hasOwnProperty( previousWord ) ){
+ table = previousWord;
+ }
+ if( wordUpperCase !== CONS.ALIAS_KEYWORD ){
+ previousWord = word;
+ }
+ });
+ if( table ){ break; }
+ }
+ return table;
+ }
+
+ function sqlHint(editor, options) {
+ tables = (options && options.tables) || {};
+ keywords = keywords || getKeywords(editor);
+ var cur = editor.getCursor();
+ var token = editor.getTokenAt(cur);
+ var result = [];
+ var search = token.string.trim();
+
+ addMatches(result, search, keywords,
+ function(w) {return w.toUpperCase();});
+
+ addMatches(result, search, tables,
+ function(w) {return w;});
+
+ if(search.lastIndexOf('.') === 0) {
+ columnCompletion(result, editor);
+ }
+
+ return {
+ list: result,
+ from: CodeMirror.Pos(cur.line, token.start),
+ to: CodeMirror.Pos(cur.line, token.end)
+ };
+ }
+ CodeMirror.registerHelper("hint", "sql", sqlHint);
+})();
diff --git a/gulliver/js/codemirror/addon/hint/xml-hint.js b/gulliver/js/codemirror/addon/hint/xml-hint.js
index 42eab6f3b..69f2b771f 100644
--- a/gulliver/js/codemirror/addon/hint/xml-hint.js
+++ b/gulliver/js/codemirror/addon/hint/xml-hint.js
@@ -1,118 +1,69 @@
(function() {
+ "use strict";
- CodeMirror.xmlHints = [];
+ var Pos = CodeMirror.Pos;
- CodeMirror.xmlHint = function(cm) {
-
- var cursor = cm.getCursor();
-
- if (cursor.ch > 0) {
-
- var text = cm.getRange(CodeMirror.Pos(0, 0), cursor);
- var typed = '';
- var simbol = '';
- for(var i = text.length - 1; i >= 0; i--) {
- if(text[i] == ' ' || text[i] == '<') {
- simbol = text[i];
- break;
- }
- else {
- typed = text[i] + typed;
- }
- }
-
- text = text.slice(0, text.length - typed.length);
-
- var path = getActiveElement(text) + simbol;
- var hints = CodeMirror.xmlHints[path];
-
- if(typeof hints === 'undefined')
- hints = [''];
- else {
- hints = hints.slice(0);
- for (var i = hints.length - 1; i >= 0; i--) {
- if(hints[i].indexOf(typed) != 0)
- hints.splice(i, 1);
- }
- }
-
- return {
- list: hints,
- from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length),
- to: cursor
- };
+ function getHints(cm, options) {
+ var tags = options && options.schemaInfo;
+ var quote = (options && options.quoteChar) || '"';
+ if (!tags) return;
+ var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+ var inner = CodeMirror.innerMode(cm.getMode(), token.state);
+ if (inner.mode.name != "xml") return;
+ var result = [], replaceToken = false, prefix;
+ var isTag = token.string.charAt(0) == "<";
+ if (!inner.state.tagName || isTag) { // Tag completion
+ if (isTag) {
+ prefix = token.string.slice(1);
+ replaceToken = true;
+ }
+ var cx = inner.state.context, curTag = cx && tags[cx.tagName];
+ var childList = cx ? curTag && curTag.children : tags["!top"];
+ if (childList) {
+ for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
+ result.push("<" + childList[i]);
+ } else {
+ for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
+ result.push("<" + name);
+ }
+ if (cx && (!prefix || ("/" + cx.tagName).lastIndexOf(prefix, 0) == 0))
+ result.push("" + cx.tagName + ">");
+ } else {
+ // Attribute completion
+ var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
+ if (!attrs) return;
+ if (token.type == "string" || token.string == "=") { // A value
+ var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),
+ Pos(cur.line, token.type == "string" ? token.start : token.end));
+ var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues;
+ if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;
+ if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget
+ if (token.type == "string") {
+ prefix = token.string;
+ if (/['"]/.test(token.string.charAt(0))) {
+ quote = token.string.charAt(0);
+ prefix = token.string.slice(1);
+ }
+ replaceToken = true;
}
- };
-
- var getActiveElement = function(text) {
-
- var element = '';
-
- if(text.length >= 0) {
-
- var regex = new RegExp('<([^!?][^\\s/>]*)[\\s\\S]*?>', 'g');
-
- var matches = [];
- var match;
- while ((match = regex.exec(text)) != null) {
- matches.push({
- tag: match[1],
- selfclose: (match[0].slice(match[0].length - 2) === '/>')
- });
- }
-
- for (var i = matches.length - 1, skip = 0; i >= 0; i--) {
-
- var item = matches[i];
-
- if (item.tag[0] == '/')
- {
- skip++;
- }
- else if (item.selfclose == false)
- {
- if (skip > 0)
- {
- skip--;
- }
- else
- {
- element = '<' + item.tag + '>' + element;
- }
- }
- }
-
- element += getOpenTag(text);
+ for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)
+ result.push(quote + atValues[i] + quote);
+ } else { // An attribute name
+ if (token.type == "attribute") {
+ prefix = token.string;
+ replaceToken = true;
}
-
- return element;
- };
-
- var getOpenTag = function(text) {
-
- var open = text.lastIndexOf('<');
- var close = text.lastIndexOf('>');
-
- if (close < open)
- {
- text = text.slice(open);
-
- if(text != '<') {
-
- var space = text.indexOf(' ');
- if(space < 0)
- space = text.indexOf('\t');
- if(space < 0)
- space = text.indexOf('\n');
-
- if (space < 0)
- space = text.length;
-
- return text.slice(0, space);
- }
- }
-
- return '';
+ for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))
+ result.push(attr);
+ }
+ }
+ return {
+ list: result,
+ from: replaceToken ? Pos(cur.line, token.start) : cur,
+ to: replaceToken ? Pos(cur.line, token.end) : cur
};
+ }
+ CodeMirror.xmlHint = getHints; // deprecated
+ CodeMirror.registerHelper("hint", "xml", getHints);
})();
diff --git a/gulliver/js/codemirror/addon/lint/coffeescript-lint.js b/gulliver/js/codemirror/addon/lint/coffeescript-lint.js
new file mode 100644
index 000000000..7f55a294d
--- /dev/null
+++ b/gulliver/js/codemirror/addon/lint/coffeescript-lint.js
@@ -0,0 +1,27 @@
+// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
+
+// declare global: coffeelint
+
+CodeMirror.registerHelper("lint", "coffeescript", function(text) {
+ var found = [];
+ var parseError = function(err) {
+ var loc = err.lineNumber;
+ found.push({from: CodeMirror.Pos(loc-1, 0),
+ to: CodeMirror.Pos(loc, 0),
+ severity: err.level,
+ message: err.message});
+ };
+ try {
+ var res = coffeelint.lint(text);
+ for(var i = 0; i < res.length; i++) {
+ parseError(res[i]);
+ }
+ } catch(e) {
+ found.push({from: CodeMirror.Pos(e.location.first_line, 0),
+ to: CodeMirror.Pos(e.location.last_line, e.location.last_column),
+ severity: 'error',
+ message: e.message});
+ }
+ return found;
+});
+CodeMirror.coffeeValidator = CodeMirror.lint.coffeescript; // deprecated
diff --git a/gulliver/js/codemirror/addon/lint/css-lint.js b/gulliver/js/codemirror/addon/lint/css-lint.js
new file mode 100644
index 000000000..1de71fbcb
--- /dev/null
+++ b/gulliver/js/codemirror/addon/lint/css-lint.js
@@ -0,0 +1,19 @@
+// Depends on csslint.js from https://github.com/stubbornella/csslint
+
+// declare global: CSSLint
+
+CodeMirror.registerHelper("lint", "css", function(text) {
+ var found = [];
+ var results = CSSLint.verify(text), messages = results.messages, message = null;
+ for ( var i = 0; i < messages.length; i++) {
+ message = messages[i];
+ var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col;
+ found.push({
+ from: CodeMirror.Pos(startLine, startCol),
+ to: CodeMirror.Pos(endLine, endCol),
+ message: message.message,
+ severity : message.type
+ });
+ }
+ return found;
+});
diff --git a/gulliver/js/codemirror/addon/lint/javascript-lint.js b/gulliver/js/codemirror/addon/lint/javascript-lint.js
index db9ff6b22..7123ab7e6 100644
--- a/gulliver/js/codemirror/addon/lint/javascript-lint.js
+++ b/gulliver/js/codemirror/addon/lint/javascript-lint.js
@@ -1,26 +1,25 @@
(function() {
+ "use strict";
+ // declare global: JSHINT
var bogus = [ "Dangerous comment" ];
var warnings = [ [ "Expected '{'",
- "Statement body should be inside '{ }' braces." ] ];
+ "Statement body should be inside '{ }' braces." ] ];
var errors = [ "Missing semicolon", "Extra comma", "Missing property name",
- "Unmatched ", " and instead saw", " is not defined",
- "Unclosed string", "Stopping, unable to continue" ];
+ "Unmatched ", " and instead saw", " is not defined",
+ "Unclosed string", "Stopping, unable to continue" ];
- function validator(options, text) {
+ function validator(text, options) {
JSHINT(text, options);
var errors = JSHINT.data().errors, result = [];
if (errors) parseErrors(errors, result);
return result;
}
- CodeMirror.javascriptValidatorWithOptions = function(options) {
- return function(text) { return validator(options, text); };
- };
-
- CodeMirror.javascriptValidator = CodeMirror.javascriptValidatorWithOptions(null);
+ CodeMirror.registerHelper("lint", "javascript", validator);
+ CodeMirror.javascriptValidator = CodeMirror.lint.javascript; // deprecated
function cleanup(error) {
// All problems are warnings by default
@@ -42,10 +41,10 @@
found = description.indexOf(find) !== -1;
if (force || found) {
- error.severity = severity;
+ error.severity = severity;
}
if (found && replace) {
- error.description = replace;
+ error.description = replace;
}
}
}
@@ -54,7 +53,7 @@
var description = error.description;
for ( var i = 0; i < bogus.length; i++) {
if (description.indexOf(bogus[i]) !== -1) {
- return true;
+ return true;
}
}
return false;
@@ -64,59 +63,59 @@
for ( var i = 0; i < errors.length; i++) {
var error = errors[i];
if (error) {
- var linetabpositions, index;
+ var linetabpositions, index;
- linetabpositions = [];
+ linetabpositions = [];
- // This next block is to fix a problem in jshint. Jshint
- // replaces
- // all tabs with spaces then performs some checks. The error
- // positions (character/space) are then reported incorrectly,
- // not taking the replacement step into account. Here we look
- // at the evidence line and try to adjust the character position
- // to the correct value.
- if (error.evidence) {
- // Tab positions are computed once per line and cached
- var tabpositions = linetabpositions[error.line];
- if (!tabpositions) {
- var evidence = error.evidence;
- tabpositions = [];
- // ugggh phantomjs does not like this
- // forEachChar(evidence, function(item, index) {
- Array.prototype.forEach.call(evidence, function(item,
- index) {
- if (item === '\t') {
- // First col is 1 (not 0) to match error
- // positions
- tabpositions.push(index + 1);
- }
- });
- linetabpositions[error.line] = tabpositions;
- }
- if (tabpositions.length > 0) {
- var pos = error.character;
- tabpositions.forEach(function(tabposition) {
- if (pos > tabposition) pos -= 1;
- });
- error.character = pos;
- }
- }
+ // This next block is to fix a problem in jshint. Jshint
+ // replaces
+ // all tabs with spaces then performs some checks. The error
+ // positions (character/space) are then reported incorrectly,
+ // not taking the replacement step into account. Here we look
+ // at the evidence line and try to adjust the character position
+ // to the correct value.
+ if (error.evidence) {
+ // Tab positions are computed once per line and cached
+ var tabpositions = linetabpositions[error.line];
+ if (!tabpositions) {
+ var evidence = error.evidence;
+ tabpositions = [];
+ // ugggh phantomjs does not like this
+ // forEachChar(evidence, function(item, index) {
+ Array.prototype.forEach.call(evidence, function(item,
+ index) {
+ if (item === '\t') {
+ // First col is 1 (not 0) to match error
+ // positions
+ tabpositions.push(index + 1);
+ }
+ });
+ linetabpositions[error.line] = tabpositions;
+ }
+ if (tabpositions.length > 0) {
+ var pos = error.character;
+ tabpositions.forEach(function(tabposition) {
+ if (pos > tabposition) pos -= 1;
+ });
+ error.character = pos;
+ }
+ }
- var start = error.character - 1, end = start + 1;
- if (error.evidence) {
- index = error.evidence.substring(start).search(/.\b/);
- if (index > -1) {
- end += index;
- }
- }
+ var start = error.character - 1, end = start + 1;
+ if (error.evidence) {
+ index = error.evidence.substring(start).search(/.\b/);
+ if (index > -1) {
+ end += index;
+ }
+ }
- // Convert to format expected by validation service
- error.description = error.reason;// + "(jshint)";
- error.start = error.character;
- error.end = end;
- error = cleanup(error);
+ // Convert to format expected by validation service
+ error.description = error.reason;// + "(jshint)";
+ error.start = error.character;
+ error.end = end;
+ error = cleanup(error);
- if (error)
+ if (error)
output.push({message: error.description,
severity: error.severity,
from: CodeMirror.Pos(error.line - 1, start),
diff --git a/gulliver/js/codemirror/addon/lint/json-lint.js b/gulliver/js/codemirror/addon/lint/json-lint.js
index 42b36abb3..e10e11bca 100644
--- a/gulliver/js/codemirror/addon/lint/json-lint.js
+++ b/gulliver/js/codemirror/addon/lint/json-lint.js
@@ -1,6 +1,8 @@
// Depends on jsonlint.js from https://github.com/zaach/jsonlint
-CodeMirror.jsonValidator = function(text) {
+// declare global: jsonlint
+
+CodeMirror.registerHelper("lint", "json", function(text) {
var found = [];
jsonlint.parseError = function(str, hash) {
var loc = hash.loc;
@@ -11,4 +13,5 @@ CodeMirror.jsonValidator = function(text) {
try { jsonlint.parse(text); }
catch(e) {}
return found;
-};
+});
+CodeMirror.jsonValidator = CodeMirror.lint.json; // deprecated
diff --git a/gulliver/js/codemirror/addon/lint/lint.css b/gulliver/js/codemirror/addon/lint/lint.css
index 4fd72e774..414a9a0e0 100644
--- a/gulliver/js/codemirror/addon/lint/lint.css
+++ b/gulliver/js/codemirror/addon/lint/lint.css
@@ -14,6 +14,7 @@
padding: 2px 5px;
position: fixed;
white-space: pre;
+ white-space: pre-wrap;
z-index: 100;
max-width: 600px;
opacity: 0;
@@ -24,18 +25,18 @@
-ms-transition: opacity .4s;
}
-.CodeMirror-lint-span-error, .CodeMirror-lint-span-warning {
+.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
background-position: left bottom;
background-repeat: repeat-x;
}
-.CodeMirror-lint-span-error {
+.CodeMirror-lint-mark-error {
background-image:
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")
;
}
-.CodeMirror-lint-span-warning {
+.CodeMirror-lint-mark-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
}
@@ -57,40 +58,16 @@
}
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
- background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs=");
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=");
}
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
- background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw==");
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=");
}
.CodeMirror-lint-marker-multiple {
- background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII=");
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");
background-repeat: no-repeat;
background-position: right bottom;
width: 100%; height: 100%;
}
-
-/* Styles for the overview ruler
-.annotationOverview {
- cursor: pointer;
- border-radius: 2px;
- left: 2px;
- width: 8px;
-}
-.annotationOverview.error {
- background-color: lightcoral;
- border: 1px solid darkred;
-}
-.annotationOverview.warning {
- background-color: Gold;
- border: 1px solid black;
-}
-
-.annotationHTML.overlay {
- background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII=");
- background-position: right bottom;
- position: relative;
- top: -16px;
-}
-*/
\ No newline at end of file
diff --git a/gulliver/js/codemirror/addon/lint/lint.js b/gulliver/js/codemirror/addon/lint/lint.js
index dd838e7ea..6121735d3 100644
--- a/gulliver/js/codemirror/addon/lint/lint.js
+++ b/gulliver/js/codemirror/addon/lint/lint.js
@@ -1,4 +1,5 @@
-CodeMirror.validate = (function() {
+(function() {
+ "use strict";
var GUTTER_ID = "CodeMirror-lint-markers";
var SEVERITIES = /^(?:error|warning)$/;
@@ -10,12 +11,12 @@ CodeMirror.validate = (function() {
function position(e) {
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
- tt.style.top = (e.clientY - tt.offsetHeight - 5) + "px";
+ tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
tt.style.left = (e.clientX + 5) + "px";
}
CodeMirror.on(document, "mousemove", position);
position(e);
- tt.style.opacity = 1;
+ if (tt.style.opacity != null) tt.style.opacity = 1;
return tt;
}
function rm(elt) {
@@ -28,6 +29,22 @@ CodeMirror.validate = (function() {
setTimeout(function() { rm(tt); }, 600);
}
+ function showTooltipFor(e, content, node) {
+ var tooltip = showTooltip(e, content);
+ function hide() {
+ CodeMirror.off(node, "mouseout", hide);
+ if (tooltip) { hideTooltip(tooltip); tooltip = null; }
+ }
+ var poll = setInterval(function() {
+ if (tooltip) for (var n = node;; n = n.parentNode) {
+ if (n == document.body) return;
+ if (!n) { hide(); break; }
+ }
+ if (!tooltip) return clearInterval(poll);
+ }, 400);
+ CodeMirror.on(node, "mouseout", hide);
+ }
+
function LintState(cm, options, hasGutter) {
this.marked = [];
this.options = options;
@@ -36,21 +53,23 @@ CodeMirror.validate = (function() {
this.onMouseOver = function(e) { onMouseOver(cm, e); };
}
- function parseOptions(options) {
+ function parseOptions(cm, options) {
if (options instanceof Function) return {getAnnotations: options};
- else if (!options || !options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
+ if (!options || options === true) options = {};
+ if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint");
+ if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)");
return options;
}
function clearMarks(cm) {
- var state = cm._lintState;
+ var state = cm.state.lint;
if (state.hasGutter) cm.clearGutter(GUTTER_ID);
for (var i = 0; i < state.marked.length; ++i)
state.marked[i].clear();
state.marked.length = 0;
}
- function makeMarker(labels, severity, multiple) {
+ function makeMarker(labels, severity, multiple, tooltips) {
var marker = document.createElement("div"), inner = marker;
marker.className = "CodeMirror-lint-marker-" + severity;
if (multiple) {
@@ -58,9 +77,9 @@ CodeMirror.validate = (function() {
inner.className = "CodeMirror-lint-marker-multiple";
}
- var tooltip;
- CodeMirror.on(inner, "mouseover", function(e) { tooltip = showTooltip(e, labels); });
- CodeMirror.on(inner, "mouseout", function() { if (tooltip) hideTooltip(tooltip); });
+ if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) {
+ showTooltipFor(e, labels, inner);
+ });
return marker;
}
@@ -89,16 +108,16 @@ CodeMirror.validate = (function() {
}
function startLinting(cm) {
- var state = cm._lintState, options = state.options;
- if (options.async)
- options.getAnnotations(cm, updateLinting, options);
- else
- updateLinting(cm, options.getAnnotations(cm.getValue()));
+ var state = cm.state.lint, options = state.options;
+ if (options.async)
+ options.getAnnotations(cm, updateLinting, options);
+ else
+ updateLinting(cm, options.getAnnotations(cm.getValue(), options.options));
}
-
+
function updateLinting(cm, annotationsNotSorted) {
clearMarks(cm);
- var state = cm._lintState, options = state.options;
+ var state = cm.state.lint, options = state.options;
var annotations = groupByLine(annotationsNotSorted);
@@ -115,35 +134,31 @@ CodeMirror.validate = (function() {
if (!SEVERITIES.test(severity)) severity = "error";
maxSeverity = getMaxSeverity(maxSeverity, severity);
- if (options.formatAnnotation) ann = options.formatAnnotation(ann);
+ if (options.formatAnnotation) ann = options.formatAnnotation(ann);
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
- className: "CodeMirror-lint-span-" + severity,
+ className: "CodeMirror-lint-mark-" + severity,
__annotation: ann
}));
}
if (state.hasGutter)
- cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1));
+ cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
+ state.options.tooltips));
}
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
}
function onChange(cm) {
- var state = cm._lintState;
+ var state = cm.state.lint;
clearTimeout(state.timeout);
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500);
}
function popupSpanTooltip(ann, e) {
- var tooltip = showTooltip(e, annotationTooltip(ann));
var target = e.target || e.srcElement;
- CodeMirror.on(target, "mouseout", hide);
- function hide() {
- CodeMirror.off(target, "mouseout", hide);
- hideTooltip(tooltip);
- }
+ showTooltipFor(e, annotationTooltip(ann), target);
}
// When the mouseover fires, the cursor might not actually be over
@@ -152,7 +167,7 @@ CodeMirror.validate = (function() {
var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0];
function onMouseOver(cm, e) {
- if (!/\bCodeMirror-lint-span-/.test((e.target || e.srcElement).className)) return;
+ if (!/\bCodeMirror-lint-mark-/.test((e.target || e.srcElement).className)) return;
for (var i = 0; i < nearby.length; i += 2) {
var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i],
top: e.clientY + nearby[i + 1]}));
@@ -163,21 +178,26 @@ CodeMirror.validate = (function() {
}
}
- CodeMirror.defineOption("lintWith", false, function(cm, val, old) {
+ function optionHandler(cm, val, old) {
if (old && old != CodeMirror.Init) {
clearMarks(cm);
cm.off("change", onChange);
- CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver);
- delete cm._lintState;
+ CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
+ delete cm.state.lint;
}
-
+
if (val) {
var gutters = cm.getOption("gutters"), hasLintGutter = false;
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
- var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter);
+ var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
cm.on("change", onChange);
- CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
+ if (state.options.tooltips != false)
+ CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);
+
startLinting(cm);
}
- });
+ }
+
+ CodeMirror.defineOption("lintWith", false, optionHandler); // deprecated
+ CodeMirror.defineOption("lint", false, optionHandler); // deprecated
})();
diff --git a/gulliver/js/codemirror/addon/merge/dep/diff_match_patch.js b/gulliver/js/codemirror/addon/merge/dep/diff_match_patch.js
new file mode 100644
index 000000000..ac34105fc
--- /dev/null
+++ b/gulliver/js/codemirror/addon/merge/dep/diff_match_patch.js
@@ -0,0 +1,50 @@
+// From https://code.google.com/p/google-diff-match-patch/ , licensed under the Apache License 2.0
+(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32}
+diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a,
+b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a};
+diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l=
+u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]};
+diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)};
+diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;
+var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]};
+diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}};
+diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);
+return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=
+h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
+diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)};
+diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+" ";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+" "}}return b.join("")};
+diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;ci)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=i);"="==f[g].charAt(0)?c[d++]=[0,h]:c[d++]=[-1,h];break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+
+f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
+diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return!f.Match_Distance?g?1:e:e+g/f.Match_Distance}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h};
+diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&&
+e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);
+if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,
+c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
+diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c 2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&
+(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c now) return false;
+
+ var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
+ var mid = editor.lineAtHeight(midY, "local");
+ var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
+ var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
+ var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit);
+ var ratio = (midY - off.top) / (off.bot - off.top);
+ var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top);
+
+ var botDist, mix;
+ // Some careful tweaking to make sure no space is left out of view
+ // when scrolling to top or bottom.
+ if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) {
+ targetPos = targetPos * mix + sInfo.top * (1 - mix);
+ } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) {
+ var otherInfo = other.getScrollInfo();
+ var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos;
+ if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
+ targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
+ }
+
+ other.scrollTo(sInfo.left, targetPos);
+ other.state.scrollSetAt = now;
+ other.state.scrollSetBy = dv;
+ return true;
+ }
+
+ function getOffsets(editor, around) {
+ var bot = around.after;
+ if (bot == null) bot = editor.lastLine() + 1;
+ return {top: editor.heightAtLine(around.before || 0, "local"),
+ bot: editor.heightAtLine(bot, "local")};
+ }
+
+ function setScrollLock(dv, val, action) {
+ dv.lockScroll = val;
+ if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
+ dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db \u21da";
+ }
+
+ // Updating the marks for editor content
+
+ function clearMarks(editor, arr, classes) {
+ for (var i = 0; i < arr.length; ++i) {
+ var mark = arr[i];
+ if (mark instanceof CodeMirror.TextMarker) {
+ mark.clear();
+ } else {
+ editor.removeLineClass(mark, "background", classes.chunk);
+ editor.removeLineClass(mark, "background", classes.start);
+ editor.removeLineClass(mark, "background", classes.end);
+ }
+ }
+ arr.length = 0;
+ }
+
+ // FIXME maybe add a margin around viewport to prevent too many updates
+ function updateMarks(editor, diff, state, type, classes) {
+ var vp = editor.getViewport();
+ editor.operation(function() {
+ if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
+ clearMarks(editor, state.marked, classes);
+ markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes);
+ state.from = vp.from; state.to = vp.to;
+ } else {
+ if (vp.from < state.from) {
+ markChanges(editor, diff, type, state.marked, vp.from, state.from, classes);
+ state.from = vp.from;
+ }
+ if (vp.to > state.to) {
+ markChanges(editor, diff, type, state.marked, state.to, vp.to, classes);
+ state.to = vp.to;
+ }
+ }
+ });
+ }
+
+ function markChanges(editor, diff, type, marks, from, to, classes) {
+ var pos = Pos(0, 0);
+ var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1));
+ var cls = type == DIFF_DELETE ? classes.del : classes.insert;
+ function markChunk(start, end) {
+ var bfrom = Math.max(from, start), bto = Math.min(to, end);
+ for (var i = bfrom; i < bto; ++i) {
+ var line = editor.addLineClass(i, "background", classes.chunk);
+ if (i == start) editor.addLineClass(line, "background", classes.start);
+ if (i == end - 1) editor.addLineClass(line, "background", classes.end);
+ marks.push(line);
+ }
+ // When the chunk is empty, make sure a horizontal line shows up
+ if (start == end && bfrom == end && bto == end) {
+ if (bfrom)
+ marks.push(editor.addLineClass(bfrom - 1, "background", classes.end));
+ else
+ marks.push(editor.addLineClass(bfrom, "background", classes.start));
+ }
+ }
+
+ var chunkStart = 0;
+ for (var i = 0; i < diff.length; ++i) {
+ var part = diff[i], tp = part[0], str = part[1];
+ if (tp == DIFF_EQUAL) {
+ var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1);
+ moveOver(pos, str);
+ var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0);
+ if (cleanTo > cleanFrom) {
+ if (i) markChunk(chunkStart, cleanFrom);
+ chunkStart = cleanTo;
+ }
+ } else {
+ if (tp == type) {
+ var end = moveOver(pos, str, true);
+ var a = posMax(top, pos), b = posMin(bot, end);
+ if (!posEq(a, b))
+ marks.push(editor.markText(a, b, {className: cls}));
+ pos = end;
+ }
+ }
+ }
+ if (chunkStart <= pos.line) markChunk(chunkStart, pos.line + 1);
+ }
+
+ // Updating the gap between editor and original
+
+ function drawConnectors(dv) {
+ if (!dv.showDifferences) return;
+
+ if (dv.svg) {
+ clear(dv.svg);
+ var w = dv.gap.offsetWidth;
+ attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
+ }
+ clear(dv.copyButtons);
+
+ var flip = dv.type == "left";
+ var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
+ var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
+ iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
+ if (topEdit > vpEdit.to || botEdit < vpEdit.from ||
+ topOrig > vpOrig.to || botOrig < vpOrig.from)
+ return;
+ var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx;
+ if (dv.svg) {
+ var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
+ if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
+ var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
+ var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
+ if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
+ var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
+ var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
+ attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
+ "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
+ "class", dv.classes.connect);
+ }
+ var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
+ "CodeMirror-merge-copy"));
+ copy.title = "Revert chunk";
+ copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
+ copy.style.top = top + "px";
+ });
+ }
+
+ function copyChunk(dv, chunk) {
+ if (dv.diffOutOfDate) return;
+ dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
+ Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0));
+ }
+
+ // Merge view, containing 0, 1, or 2 diff views.
+
+ var MergeView = CodeMirror.MergeView = function(node, options) {
+ if (!(this instanceof MergeView)) return new MergeView(node, options);
+
+ var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
+ var hasLeft = origLeft != null, hasRight = origRight != null;
+ var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
+ var wrap = [], left = this.left = null, right = this.right = null;
+
+ if (hasLeft) {
+ left = this.left = new DiffView(this, "left");
+ var leftPane = elt("div", null, "CodeMirror-merge-pane");
+ wrap.push(leftPane);
+ wrap.push(buildGap(left));
+ }
+
+ var editPane = elt("div", null, "CodeMirror-merge-pane");
+ wrap.push(editPane);
+
+ if (hasRight) {
+ right = this.right = new DiffView(this, "right");
+ wrap.push(buildGap(right));
+ var rightPane = elt("div", null, "CodeMirror-merge-pane");
+ wrap.push(rightPane);
+ }
+
+ (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost";
+
+ wrap.push(elt("div", null, null, "height: 0; clear: both;"));
+ var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane"));
+ this.edit = CodeMirror(editPane, copyObj(options));
+
+ if (left) left.init(leftPane, origLeft, options);
+ if (right) right.init(rightPane, origRight, options);
+
+ var onResize = function() {
+ if (left) drawConnectors(left);
+ if (right) drawConnectors(right);
+ };
+ CodeMirror.on(window, "resize", onResize);
+ var resizeInterval = setInterval(function() {
+ for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {}
+ if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); }
+ }, 5000);
+ };
+
+ function buildGap(dv) {
+ var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock");
+ lock.title = "Toggle locked scrolling";
+ var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap");
+ CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); });
+ dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type);
+ CodeMirror.on(dv.copyButtons, "click", function(e) {
+ var node = e.target || e.srcElement;
+ if (node.chunk) copyChunk(dv, node.chunk);
+ });
+ var gapElts = [dv.copyButtons, lockWrap];
+ var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
+ if (svg && !svg.createSVGRect) svg = null;
+ dv.svg = svg;
+ if (svg) gapElts.push(svg);
+
+ return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
+ }
+
+ MergeView.prototype = {
+ constuctor: MergeView,
+ editor: function() { return this.edit; },
+ rightOriginal: function() { return this.right && this.right.orig; },
+ leftOriginal: function() { return this.left && this.left.orig; },
+ setShowDifferences: function(val) {
+ if (this.right) this.right.setShowDifferences(val);
+ if (this.left) this.left.setShowDifferences(val);
+ }
+ };
+
+ function asString(obj) {
+ if (typeof obj == "string") return obj;
+ else return obj.getValue();
+ }
+
+ // Operations on diffs
+
+ var dmp = new diff_match_patch();
+ function getDiff(a, b) {
+ var diff = dmp.diff_main(a, b);
+ dmp.diff_cleanupSemantic(diff);
+ // The library sometimes leaves in empty parts, which confuse the algorithm
+ for (var i = 0; i < diff.length; ++i) {
+ var part = diff[i];
+ if (!part[1]) {
+ diff.splice(i--, 1);
+ } else if (i && diff[i - 1][0] == part[0]) {
+ diff.splice(i--, 1);
+ diff[i][1] += part[1];
+ }
+ }
+ return diff;
+ }
+
+ function iterateChunks(diff, f) {
+ var startEdit = 0, startOrig = 0;
+ var edit = Pos(0, 0), orig = Pos(0, 0);
+ for (var i = 0; i < diff.length; ++i) {
+ var part = diff[i], tp = part[0];
+ if (tp == DIFF_EQUAL) {
+ var startOff = startOfLineClean(diff, i) ? 0 : 1;
+ var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff;
+ moveOver(edit, part[1], null, orig);
+ var endOff = endOfLineClean(diff, i) ? 1 : 0;
+ var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff;
+ if (cleanToEdit > cleanFromEdit) {
+ if (i) f(startOrig, cleanFromOrig, startEdit, cleanFromEdit);
+ startEdit = cleanToEdit; startOrig = cleanToOrig;
+ }
+ } else {
+ moveOver(tp == DIFF_INSERT ? edit : orig, part[1]);
+ }
+ }
+ if (startEdit <= edit.line || startOrig <= orig.line)
+ f(startOrig, orig.line + 1, startEdit, edit.line + 1);
+ }
+
+ function endOfLineClean(diff, i) {
+ if (i == diff.length - 1) return true;
+ var next = diff[i + 1][1];
+ if (next.length == 1 || next.charCodeAt(0) != 10) return false;
+ if (i == diff.length - 2) return true;
+ next = diff[i + 2][1];
+ return next.length > 1 && next.charCodeAt(0) == 10;
+ }
+
+ function startOfLineClean(diff, i) {
+ if (i == 0) return true;
+ var last = diff[i - 1][1];
+ if (last.charCodeAt(last.length - 1) != 10) return false;
+ if (i == 1) return true;
+ last = diff[i - 2][1];
+ return last.charCodeAt(last.length - 1) == 10;
+ }
+
+ function chunkBoundariesAround(diff, n, nInEdit) {
+ var beforeE, afterE, beforeO, afterO;
+ iterateChunks(diff, function(fromOrig, toOrig, fromEdit, toEdit) {
+ var fromLocal = nInEdit ? fromEdit : fromOrig;
+ var toLocal = nInEdit ? toEdit : toOrig;
+ if (afterE == null) {
+ if (fromLocal > n) { afterE = fromEdit; afterO = fromOrig; }
+ else if (toLocal > n) { afterE = toEdit; afterO = toOrig; }
+ }
+ if (toLocal <= n) { beforeE = toEdit; beforeO = toOrig; }
+ else if (fromLocal <= n) { beforeE = fromEdit; beforeO = fromOrig; }
+ });
+ return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
+ }
+
+ // General utilities
+
+ function elt(tag, content, className, style) {
+ var e = document.createElement(tag);
+ if (className) e.className = className;
+ if (style) e.style.cssText = style;
+ if (typeof content == "string") e.appendChild(document.createTextNode(content));
+ else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
+ return e;
+ }
+
+ function clear(node) {
+ for (var count = node.childNodes.length; count > 0; --count)
+ node.removeChild(node.firstChild);
+ }
+
+ function attrs(elt) {
+ for (var i = 1; i < arguments.length; i += 2)
+ elt.setAttribute(arguments[i], arguments[i+1]);
+ }
+
+ function copyObj(obj, target) {
+ if (!target) target = {};
+ for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
+ return target;
+ }
+
+ function moveOver(pos, str, copy, other) {
+ var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0;
+ for (;;) {
+ var nl = str.indexOf("\n", at);
+ if (nl == -1) break;
+ ++out.line;
+ if (other) ++other.line;
+ at = nl + 1;
+ }
+ out.ch = (at ? 0 : out.ch) + (str.length - at);
+ if (other) other.ch = (at ? 0 : other.ch) + (str.length - at);
+ return out;
+ }
+
+ function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; }
+ function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; }
+ function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
+})();
diff --git a/gulliver/js/codemirror/addon/mode/multiplex.js b/gulliver/js/codemirror/addon/mode/multiplex.js
index e77ff2a9c..614ab1add 100644
--- a/gulliver/js/codemirror/addon/mode/multiplex.js
+++ b/gulliver/js/codemirror/addon/mode/multiplex.js
@@ -1,5 +1,5 @@
CodeMirror.multiplexingMode = function(outer /*, others */) {
- // Others should be {open, close, mode [, delimStyle]} objects
+ // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects
var others = Array.prototype.slice.call(arguments, 1);
var n_others = others.length;
@@ -47,7 +47,11 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
return outerToken;
} else {
var curInner = state.innerActive, oldContent = stream.string;
- var found = indexOf(oldContent, curInner.close, stream.pos);
+ if (!curInner.close && stream.sol()) {
+ state.innerActive = state.inner = null;
+ return this.token(stream, state);
+ }
+ var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos) : -1;
if (found == stream.pos) {
stream.match(curInner.close);
state.innerActive = state.inner = null;
@@ -56,12 +60,16 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
if (found > -1) stream.string = oldContent.slice(0, found);
var innerToken = curInner.mode.token(stream, state.inner);
if (found > -1) stream.string = oldContent;
- var cur = stream.current(), found = cur.indexOf(curInner.close);
- if (found > -1) stream.backUp(cur.length - found);
+
+ if (curInner.innerStyle) {
+ if (innerToken) innerToken = innerToken + ' ' + curInner.innerStyle;
+ else innerToken = curInner.innerStyle;
+ }
+
return innerToken;
}
},
-
+
indent: function(state, textAfter) {
var mode = state.innerActive ? state.innerActive.mode : outer;
if (!mode.indent) return CodeMirror.Pass;
@@ -81,7 +89,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) {
state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0);
}
}
- } else if (mode.close === "\n") {
+ } else if (state.innerActive.close === "\n") {
state.innerActive = state.inner = null;
}
},
diff --git a/gulliver/js/codemirror/addon/mode/multiplex_test.js b/gulliver/js/codemirror/addon/mode/multiplex_test.js
new file mode 100644
index 000000000..c0656357c
--- /dev/null
+++ b/gulliver/js/codemirror/addon/mode/multiplex_test.js
@@ -0,0 +1,30 @@
+(function() {
+ CodeMirror.defineMode("markdown_with_stex", function(){
+ var inner = CodeMirror.getMode({}, "stex");
+ var outer = CodeMirror.getMode({}, "markdown");
+
+ var innerOptions = {
+ open: '$',
+ close: '$',
+ mode: inner,
+ delimStyle: 'delim',
+ innerStyle: 'inner'
+ };
+
+ return CodeMirror.multiplexingMode(outer, innerOptions);
+ });
+
+ var mode = CodeMirror.getMode({}, "markdown_with_stex");
+
+ function MT(name) {
+ test.mode(
+ name,
+ mode,
+ Array.prototype.slice.call(arguments, 1),
+ 'multiplexing');
+ }
+
+ MT(
+ "stexInsideMarkdown",
+ "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]");
+})();
diff --git a/gulliver/js/codemirror/addon/mode/overlay.js b/gulliver/js/codemirror/addon/mode/overlay.js
index fba38987b..b7928a7bb 100644
--- a/gulliver/js/codemirror/addon/mode/overlay.js
+++ b/gulliver/js/codemirror/addon/mode/overlay.js
@@ -43,14 +43,14 @@ CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, comb
if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
else return state.overlayCur;
},
-
+
indent: base.indent && function(state, textAfter) {
return base.indent(state.base, textAfter);
},
electricChars: base.electricChars,
innerMode: function(state) { return {state: state.base, mode: base}; },
-
+
blankLine: function(state) {
if (base.blankLine) base.blankLine(state.base);
if (overlay.blankLine) overlay.blankLine(state.overlay);
diff --git a/gulliver/js/codemirror/addon/runmode/runmode-standalone.js b/gulliver/js/codemirror/addon/runmode/runmode-standalone.js
index 7a9b82ffa..ec06ba11c 100644
--- a/gulliver/js/codemirror/addon/runmode/runmode-standalone.js
+++ b/gulliver/js/codemirror/addon/runmode/runmode-standalone.js
@@ -2,11 +2,15 @@
window.CodeMirror = {};
+(function() {
+"use strict";
+
function splitLines(string){ return string.split(/\r?\n|\r/); };
function StringStream(string) {
this.pos = this.start = 0;
this.string = string;
+ this.lineStart = 0;
}
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
@@ -38,22 +42,29 @@ StringStream.prototype = {
if (found > -1) {this.pos = found; return true;}
},
backUp: function(n) {this.pos -= n;},
- column: function() {return this.start;},
+ column: function() {return this.start - this.lineStart;},
indentation: function() {return 0;},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
- if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
+ var substr = this.string.substr(this.pos, pattern.length);
+ if (cased(substr) == cased(pattern)) {
if (consume !== false) this.pos += pattern.length;
return true;
}
} else {
var match = this.string.slice(this.pos).match(pattern);
+ if (match && match.index > 0) return null;
if (match && consume !== false) this.pos += match[0].length;
return match;
}
},
- current: function(){return this.string.slice(this.start, this.pos);}
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
};
CodeMirror.StringStream = StringStream;
@@ -64,17 +75,26 @@ CodeMirror.startState = function (mode, a1, a2) {
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
CodeMirror.defineMode = function (name, mode) { modes[name] = mode; };
CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; };
-CodeMirror.getMode = function (options, spec) {
- if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
+CodeMirror.resolveMode = function(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
spec = mimeModes[spec];
- if (typeof spec == "string")
- var mname = spec, config = {};
- else if (spec != null)
- var mname = spec.name, config = spec;
- var mfactory = modes[mname];
- if (!mfactory) throw new Error("Unknown mode: " + spec);
- return mfactory(options, config || {});
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+ spec = mimeModes[spec.name];
+ }
+ if (typeof spec == "string") return {name: spec};
+ else return spec || {name: "null"};
};
+CodeMirror.getMode = function (options, spec) {
+ spec = CodeMirror.resolveMode(spec);
+ var mfactory = modes[spec.name];
+ if (!mfactory) throw new Error("Unknown mode: " + spec);
+ return mfactory(options, spec);
+};
+CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min;
+CodeMirror.defineMode("null", function() {
+ return {token: function(stream) {stream.skipToEnd();}};
+});
+CodeMirror.defineMIME("text/plain", "null");
CodeMirror.runMode = function (string, modespec, callback, options) {
var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec);
@@ -117,14 +137,15 @@ CodeMirror.runMode = function (string, modespec, callback, options) {
};
}
- var lines = splitLines(string), state = CodeMirror.startState(mode);
+ var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n");
var stream = new CodeMirror.StringStream(lines[i]);
while (!stream.eol()) {
var style = mode.token(stream, state);
- callback(stream.current(), style, i, stream.start);
+ callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos;
}
}
};
+})();
diff --git a/gulliver/js/codemirror/addon/runmode/runmode.js b/gulliver/js/codemirror/addon/runmode/runmode.js
index 3e1bed736..2cafa811f 100644
--- a/gulliver/js/codemirror/addon/runmode/runmode.js
+++ b/gulliver/js/codemirror/addon/runmode/runmode.js
@@ -1,5 +1,7 @@
CodeMirror.runMode = function(string, modespec, callback, options) {
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
+ var ie = /MSIE \d/.test(navigator.userAgent);
+ var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
if (callback.nodeType == 1) {
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
@@ -7,7 +9,9 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
node.innerHTML = "";
callback = function(text, style) {
if (text == "\n") {
- node.appendChild(document.createElement("br"));
+ // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
+ // Emitting a carriage return makes everything ok.
+ node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
col = 0;
return;
}
@@ -39,13 +43,13 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
};
}
- var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
+ var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n");
var stream = new CodeMirror.StringStream(lines[i]);
while (!stream.eol()) {
var style = mode.token(stream, state);
- callback(stream.current(), style, i, stream.start);
+ callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos;
}
}
diff --git a/gulliver/js/codemirror/addon/runmode/runmode.node.js b/gulliver/js/codemirror/addon/runmode/runmode.node.js
index 6449e77c8..e8bccb0cf 100644
--- a/gulliver/js/codemirror/addon/runmode/runmode.node.js
+++ b/gulliver/js/codemirror/addon/runmode/runmode.node.js
@@ -5,6 +5,7 @@ function splitLines(string){ return string.split(/\r?\n|\r/); };
function StringStream(string) {
this.pos = this.start = 0;
this.string = string;
+ this.lineStart = 0;
}
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
@@ -36,22 +37,29 @@ StringStream.prototype = {
if (found > -1) {this.pos = found; return true;}
},
backUp: function(n) {this.pos -= n;},
- column: function() {return this.start;},
+ column: function() {return this.start - this.lineStart;},
indentation: function() {return 0;},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
- if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
+ var substr = this.string.substr(this.pos, pattern.length);
+ if (cased(substr) == cased(pattern)) {
if (consume !== false) this.pos += pattern.length;
return true;
}
} else {
var match = this.string.slice(this.pos).match(pattern);
+ if (match && match.index > 0) return null;
if (match && consume !== false) this.pos += match[0].length;
return match;
}
},
- current: function(){return this.string.slice(this.start, this.pos);}
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
};
exports.StringStream = StringStream;
@@ -60,29 +68,46 @@ exports.startState = function(mode, a1, a2) {
};
var modes = exports.modes = {}, mimeModes = exports.mimeModes = {};
-exports.defineMode = function(name, mode) { modes[name] = mode; };
-exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
-exports.getMode = function(options, spec) {
- if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
- spec = mimeModes[spec];
- if (typeof spec == "string")
- var mname = spec, config = {};
- else if (spec != null)
- var mname = spec.name, config = spec;
- var mfactory = modes[mname];
- if (!mfactory) throw new Error("Unknown mode: " + spec);
- return mfactory(options, config || {});
+exports.defineMode = function(name, mode) {
+ if (arguments.length > 2) {
+ mode.dependencies = [];
+ for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
+ }
+ modes[name] = mode;
};
+exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; };
+
+exports.defineMode("null", function() {
+ return {token: function(stream) {stream.skipToEnd();}};
+});
+exports.defineMIME("text/plain", "null");
+
+exports.resolveMode = function(spec) {
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
+ spec = mimeModes[spec];
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
+ spec = mimeModes[spec.name];
+ }
+ if (typeof spec == "string") return {name: spec};
+ else return spec || {name: "null"};
+};
+exports.getMode = function(options, spec) {
+ spec = exports.resolveMode(mimeModes[spec]);
+ var mfactory = modes[spec.name];
+ if (!mfactory) throw new Error("Unknown mode: " + spec);
+ return mfactory(options, spec);
+};
+exports.registerHelper = exports.registerGlobalHelper = Math.min;
exports.runMode = function(string, modespec, callback) {
var mode = exports.getMode({indentUnit: 2}, modespec);
- var lines = splitLines(string), state = exports.startState(mode);
+ var lines = splitLines(string), state = (options && options.state) || exports.startState(mode);
for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n");
var stream = new exports.StringStream(lines[i]);
while (!stream.eol()) {
var style = mode.token(stream, state);
- callback(stream.current(), style, i, stream.start);
+ callback(stream.current(), style, i, stream.start, state);
stream.start = stream.pos;
}
}
diff --git a/gulliver/js/codemirror/addon/scroll/scrollpastend.js b/gulliver/js/codemirror/addon/scroll/scrollpastend.js
new file mode 100644
index 000000000..14d7d5aee
--- /dev/null
+++ b/gulliver/js/codemirror/addon/scroll/scrollpastend.js
@@ -0,0 +1,34 @@
+(function() {
+ "use strict";
+
+ CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) {
+ if (old && old != CodeMirror.Init) {
+ cm.off("change", onChange);
+ cm.display.lineSpace.parentNode.style.paddingBottom = "";
+ cm.state.scrollPastEndPadding = null;
+ }
+ if (val) {
+ cm.on("change", onChange);
+ updateBottomMargin(cm);
+ }
+ });
+
+ function onChange(cm, change) {
+ if (CodeMirror.changeEnd(change).line == cm.lastLine())
+ updateBottomMargin(cm);
+ }
+
+ function updateBottomMargin(cm) {
+ var padding = "";
+ if (cm.lineCount() > 1) {
+ var totalH = cm.display.scroller.clientHeight - 30,
+ lastLineH = cm.getLineHandle(cm.lastLine()).height;
+ padding = (totalH - lastLineH) + "px";
+ }
+ if (cm.state.scrollPastEndPadding != padding) {
+ cm.state.scrollPastEndPadding = padding;
+ cm.display.lineSpace.parentNode.style.paddingBottom = padding;
+ cm.setSize();
+ }
+ }
+})();
diff --git a/gulliver/js/codemirror/addon/search/match-highlighter.js b/gulliver/js/codemirror/addon/search/match-highlighter.js
index c6e35cd97..e5cbeacab 100644
--- a/gulliver/js/codemirror/addon/search/match-highlighter.js
+++ b/gulliver/js/codemirror/addon/search/match-highlighter.js
@@ -5,54 +5,85 @@
// document.
//
// The option can be set to true to simply enable it, or to a
-// {minChars, style} object to explicitly configure it. minChars is
-// the minimum amount of characters that should be selected for the
-// behavior to occur, and style is the token style to apply to the
-// matches. This will be prefixed by "cm-" to create an actual CSS
-// class name.
+// {minChars, style, showToken} object to explicitly configure it.
+// minChars is the minimum amount of characters that should be
+// selected for the behavior to occur, and style is the token style to
+// apply to the matches. This will be prefixed by "cm-" to create an
+// actual CSS class name. showToken, when enabled, will cause the
+// current token to be highlighted when nothing is selected.
(function() {
var DEFAULT_MIN_CHARS = 2;
var DEFAULT_TOKEN_STYLE = "matchhighlight";
-
+ var DEFAULT_DELAY = 100;
+
function State(options) {
- this.minChars = typeof options == "object" && options.minChars || DEFAULT_MIN_CHARS;
- this.style = typeof options == "object" && options.style || DEFAULT_TOKEN_STYLE;
- this.overlay = null;
+ if (typeof options == "object") {
+ this.minChars = options.minChars;
+ this.style = options.style;
+ this.showToken = options.showToken;
+ this.delay = options.delay;
+ }
+ if (this.style == null) this.style = DEFAULT_TOKEN_STYLE;
+ if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS;
+ if (this.delay == null) this.delay = DEFAULT_DELAY;
+ this.overlay = this.timeout = null;
}
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
- var prev = old && old != CodeMirror.Init;
- if (val && !prev) {
- cm._matchHighlightState = new State(val);
- cm.on("cursorActivity", highlightMatches);
- } else if (!val && prev) {
- var over = cm._matchHighlightState.overlay;
+ if (old && old != CodeMirror.Init) {
+ var over = cm.state.matchHighlighter.overlay;
if (over) cm.removeOverlay(over);
- cm._matchHighlightState = null;
- cm.off("cursorActivity", highlightMatches);
+ clearTimeout(cm.state.matchHighlighter.timeout);
+ cm.state.matchHighlighter = null;
+ cm.off("cursorActivity", cursorActivity);
+ }
+ if (val) {
+ cm.state.matchHighlighter = new State(val);
+ highlightMatches(cm);
+ cm.on("cursorActivity", cursorActivity);
}
});
+ function cursorActivity(cm) {
+ var state = cm.state.matchHighlighter;
+ clearTimeout(state.timeout);
+ state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay);
+ }
+
function highlightMatches(cm) {
cm.operation(function() {
- var state = cm._matchHighlightState;
+ var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
}
-
- if (!cm.somethingSelected()) return;
+ if (!cm.somethingSelected() && state.showToken) {
+ var re = state.showToken === true ? /[\w$]/ : state.showToken;
+ var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
+ while (start && re.test(line.charAt(start - 1))) --start;
+ while (end < line.length && re.test(line.charAt(end))) ++end;
+ if (start < end)
+ cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style));
+ return;
+ }
+ if (cm.getCursor("head").line != cm.getCursor("anchor").line) return;
var selection = cm.getSelection().replace(/^\s+|\s+$/g, "");
- if (selection.length < state.minChars) return;
-
- cm.addOverlay(state.overlay = makeOverlay(selection, state.style));
+ if (selection.length >= state.minChars)
+ cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style));
});
}
- function makeOverlay(query, style) {
+ function boundariesAround(stream, re) {
+ return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
+ (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
+ }
+
+ function makeOverlay(query, hasBoundary, style) {
return {token: function(stream) {
- if (stream.match(query)) return style;
+ if (stream.match(query) &&
+ (!hasBoundary || boundariesAround(stream, hasBoundary)))
+ return style;
stream.next();
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
}};
diff --git a/gulliver/js/codemirror/addon/search/search.js b/gulliver/js/codemirror/addon/search/search.js
index 6331b8655..049f72f3d 100644
--- a/gulliver/js/codemirror/addon/search/search.js
+++ b/gulliver/js/codemirror/addon/search/search.js
@@ -7,7 +7,15 @@
// Ctrl-G.
(function() {
- function searchOverlay(query) {
+ function searchOverlay(query, caseInsensitive) {
+ var startChar;
+ if (typeof query == "string") {
+ startChar = query.charAt(0);
+ query = new RegExp("^" + query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"),
+ caseInsensitive ? "i" : "");
+ } else {
+ query = new RegExp("^(?:" + query.source + ")", query.ignoreCase ? "i" : "");
+ }
if (typeof query == "string") return {token: function(stream) {
if (stream.match(query)) return "searching";
stream.next();
@@ -17,6 +25,8 @@
if (stream.match(query)) return "searching";
while (!stream.eol()) {
stream.next();
+ if (startChar)
+ stream.skipTo(startChar) || stream.skipToEnd();
if (stream.match(query, false)) break;
}
}};
@@ -27,15 +37,18 @@
this.overlay = null;
}
function getSearchState(cm) {
- return cm._searchState || (cm._searchState = new SearchState());
+ return cm.state.search || (cm.state.search = new SearchState());
+ }
+ function queryCaseInsensitive(query) {
+ return typeof query == "string" && query == query.toLowerCase();
}
function getSearchCursor(cm, query, pos) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
- return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
+ return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
}
- function dialog(cm, text, shortText, f) {
- if (cm.openDialog) cm.openDialog(text, f);
- else f(prompt(shortText, ""));
+ function dialog(cm, text, shortText, deflt, f) {
+ if (cm.openDialog) cm.openDialog(text, f, {value: deflt});
+ else f(prompt(shortText, deflt));
}
function confirmDialog(cm, text, shortText, fs) {
if (cm.openConfirm) cm.openConfirm(text, fs);
@@ -50,12 +63,12 @@
function doSearch(cm, rev) {
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
- dialog(cm, queryDialog, "Search for:", function(query) {
+ dialog(cm, queryDialog, "Search for:", cm.getSelection(), function(query) {
cm.operation(function() {
if (!query || state.query) return;
state.query = parseQuery(query);
- cm.removeOverlay(state.overlay);
- state.overlay = searchOverlay(query);
+ cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
+ state.overlay = searchOverlay(state.query);
cm.addOverlay(state.overlay);
state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev);
@@ -70,6 +83,7 @@
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
state.posFrom = cursor.from(); state.posTo = cursor.to();
});}
function clearSearch(cm) {cm.operation(function() {
@@ -84,10 +98,10 @@
var replacementQueryDialog = 'With: ';
var doReplaceConfirm = "Replace? Yes No Stop ";
function replace(cm, all) {
- dialog(cm, replaceQueryDialog, "Replace:", function(query) {
+ dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) {
if (!query) return;
query = parseQuery(query);
- dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
+ dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
if (all) {
cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
@@ -108,6 +122,7 @@
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
+ cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance]);
};
diff --git a/gulliver/js/codemirror/addon/search/searchcursor.js b/gulliver/js/codemirror/addon/search/searchcursor.js
index fd134636e..711cf4ce5 100644
--- a/gulliver/js/codemirror/addon/search/searchcursor.js
+++ b/gulliver/js/codemirror/addon/search/searchcursor.js
@@ -1,11 +1,11 @@
(function(){
var Pos = CodeMirror.Pos;
- function SearchCursor(cm, query, pos, caseFold) {
- this.atOccurrence = false; this.cm = cm;
+ function SearchCursor(doc, query, pos, caseFold) {
+ this.atOccurrence = false; this.doc = doc;
if (caseFold == null && typeof query == "string") caseFold = false;
- pos = pos ? cm.clipPos(pos) : Pos(0, 0);
+ pos = pos ? doc.clipPos(pos) : Pos(0, 0);
this.pos = {from: pos, to: pos};
// The matches method is filled in based on the type of query.
@@ -17,26 +17,37 @@
this.matches = function(reverse, pos) {
if (reverse) {
query.lastIndex = 0;
- var line = cm.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
+ var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
for (;;) {
query.lastIndex = cutOff;
var newMatch = query.exec(line);
if (!newMatch) break;
match = newMatch;
start = match.index;
- cutOff = match.index + 1;
+ cutOff = match.index + (match[0].length || 1);
+ if (cutOff == line.length) break;
+ }
+ var matchLen = (match && match[0].length) || 0;
+ if (!matchLen) {
+ if (start == 0 && line.length == 0) {match = undefined;}
+ else if (start != doc.getLine(pos.line).length) {
+ matchLen++;
+ }
}
} else {
query.lastIndex = pos.ch;
- var line = cm.getLine(pos.line), match = query.exec(line),
- start = match && match.index;
+ var line = doc.getLine(pos.line), match = query.exec(line);
+ var matchLen = (match && match[0].length) || 0;
+ var start = match && match.index;
+ if (start + matchLen != line.length && !matchLen) matchLen = 1;
}
- if (match && match[0])
+ if (match && matchLen)
return {from: Pos(pos.line, start),
- to: Pos(pos.line, start + match[0].length),
+ to: Pos(pos.line, start + matchLen),
match: match};
};
} else { // String query
+ var origQuery = query;
if (caseFold) query = query.toLowerCase();
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
var target = query.split("\n");
@@ -48,33 +59,45 @@
this.matches = function() {};
} else {
this.matches = function(reverse, pos) {
- var line = fold(cm.getLine(pos.line)), len = query.length, match;
- if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
- : (match = line.indexOf(query, pos.ch)) != -1)
- return {from: Pos(pos.line, match),
- to: Pos(pos.line, match + len)};
+ if (reverse) {
+ var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
+ var match = line.lastIndexOf(query);
+ if (match > -1) {
+ match = adjustPos(orig, line, match);
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
+ }
+ } else {
+ var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
+ var match = line.indexOf(query);
+ if (match > -1) {
+ match = adjustPos(orig, line, match) + pos.ch;
+ return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
+ }
+ }
};
}
} else {
+ var origTarget = origQuery.split("\n");
this.matches = function(reverse, pos) {
- var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln));
- var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
- if (reverse ? offsetA >= pos.ch || offsetA != match.length
- : offsetA <= pos.ch || offsetA != line.length - match.length)
- return;
- for (;;) {
- if (reverse ? !ln : ln == cm.lineCount() - 1) return;
- line = fold(cm.getLine(ln += reverse ? -1 : 1));
- match = target[reverse ? --idx : ++idx];
- if (idx > 0 && idx < target.length - 1) {
- if (line != match) return;
- else continue;
- }
- var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
- if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
- return;
- var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
- return {from: reverse ? end : start, to: reverse ? start : end};
+ var last = target.length - 1;
+ if (reverse) {
+ if (pos.line - (target.length - 1) < doc.firstLine()) return;
+ if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
+ var to = Pos(pos.line, origTarget[last].length);
+ for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
+ if (target[i] != fold(doc.getLine(ln))) return;
+ var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
+ if (fold(line.slice(cut)) != target[0]) return;
+ return {from: Pos(ln, cut), to: to};
+ } else {
+ if (pos.line + (target.length - 1) > doc.lastLine()) return;
+ var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
+ if (fold(line.slice(cut)) != target[0]) return;
+ var from = Pos(pos.line, cut);
+ for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
+ if (target[i] != fold(doc.getLine(ln))) return;
+ if (doc.getLine(ln).slice(0, origTarget[last].length) != target[last]) return;
+ return {from: from, to: Pos(ln, origTarget[last].length)};
}
};
}
@@ -86,7 +109,7 @@
findPrevious: function() {return this.find(true);},
find: function(reverse) {
- var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
+ var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
function savePosAndFail(line) {
var pos = Pos(line, 0);
self.pos = {from: pos, to: pos};
@@ -96,16 +119,15 @@
for (;;) {
if (this.pos = this.matches(reverse, pos)) {
- if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
this.atOccurrence = true;
return this.pos.match || true;
}
if (reverse) {
if (!pos.line) return savePosAndFail(0);
- pos = Pos(pos.line-1, this.cm.getLine(pos.line-1).length);
+ pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
}
else {
- var maxLine = this.cm.lineCount();
+ var maxLine = this.doc.lineCount();
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
pos = Pos(pos.line + 1, 0);
}
@@ -118,13 +140,28 @@
replace: function(newText) {
if (!this.atOccurrence) return;
var lines = CodeMirror.splitLines(newText);
- this.cm.replaceRange(lines, this.pos.from, this.pos.to);
+ this.doc.replaceRange(lines, this.pos.from, this.pos.to);
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
}
};
+ // Maps a position in a case-folded line back to a position in the original line
+ // (compensating for codepoints increasing in number during folding)
+ function adjustPos(orig, folded, pos) {
+ if (orig.length == folded.length) return pos;
+ for (var pos1 = Math.min(pos, orig.length);;) {
+ var len1 = orig.slice(0, pos1).toLowerCase().length;
+ if (len1 < pos) ++pos1;
+ else if (len1 > pos) --pos1;
+ else return pos1;
+ }
+ }
+
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
+ return new SearchCursor(this.doc, query, pos, caseFold);
+ });
+ CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this, query, pos, caseFold);
});
})();
diff --git a/gulliver/js/codemirror/addon/selection/active-line.js b/gulliver/js/codemirror/addon/selection/active-line.js
index 988a0ffbf..7cf7793c0 100644
--- a/gulliver/js/codemirror/addon/selection/active-line.js
+++ b/gulliver/js/codemirror/addon/selection/active-line.js
@@ -12,28 +12,34 @@
CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
- updateActiveLine(cm);
- cm.on("cursorActivity", updateActiveLine);
+ updateActiveLine(cm, cm.getCursor().line);
+ cm.on("beforeSelectionChange", selectionChange);
} else if (!val && prev) {
- cm.off("cursorActivity", updateActiveLine);
+ cm.off("beforeSelectionChange", selectionChange);
clearActiveLine(cm);
- delete cm._activeLine;
+ delete cm.state.activeLine;
}
});
-
+
function clearActiveLine(cm) {
- if ("_activeLine" in cm) {
- cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS);
- cm.removeLineClass(cm._activeLine, "background", BACK_CLASS);
+ if ("activeLine" in cm.state) {
+ cm.removeLineClass(cm.state.activeLine, "wrap", WRAP_CLASS);
+ cm.removeLineClass(cm.state.activeLine, "background", BACK_CLASS);
}
}
- function updateActiveLine(cm) {
- var line = cm.getLineHandle(cm.getCursor().line);
- if (cm._activeLine == line) return;
- clearActiveLine(cm);
- cm.addLineClass(line, "wrap", WRAP_CLASS);
- cm.addLineClass(line, "background", BACK_CLASS);
- cm._activeLine = line;
+ function updateActiveLine(cm, selectedLine) {
+ var line = cm.getLineHandleVisualStart(selectedLine);
+ if (cm.state.activeLine == line) return;
+ cm.operation(function() {
+ clearActiveLine(cm);
+ cm.addLineClass(line, "wrap", WRAP_CLASS);
+ cm.addLineClass(line, "background", BACK_CLASS);
+ cm.state.activeLine = line;
+ });
+ }
+
+ function selectionChange(cm, sel) {
+ updateActiveLine(cm, sel.head.line);
}
})();
diff --git a/gulliver/js/codemirror/addon/selection/mark-selection.js b/gulliver/js/codemirror/addon/selection/mark-selection.js
index d7ff30c9a..c97776e49 100644
--- a/gulliver/js/codemirror/addon/selection/mark-selection.js
+++ b/gulliver/js/codemirror/addon/selection/mark-selection.js
@@ -1,7 +1,8 @@
// Because sometimes you need to mark the selected *text*.
//
// Adds an option 'styleSelectedText' which, when enabled, gives
-// selected text the CSS class "CodeMirror-selectedtext".
+// selected text the CSS class given as option value, or
+// "CodeMirror-selectedtext" when the value is not a string.
(function() {
"use strict";
@@ -9,26 +10,99 @@
CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
- updateSelectedText(cm);
- cm.on("cursorActivity", updateSelectedText);
+ cm.state.markedSelection = [];
+ cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
+ reset(cm);
+ cm.on("cursorActivity", onCursorActivity);
+ cm.on("change", onChange);
} else if (!val && prev) {
- cm.off("cursorActivity", updateSelectedText);
- clearSelectedText(cm);
- delete cm._selectionMark;
+ cm.off("cursorActivity", onCursorActivity);
+ cm.off("change", onChange);
+ clear(cm);
+ cm.state.markedSelection = cm.state.markedSelectionStyle = null;
}
});
- function clearSelectedText(cm) {
- if (cm._selectionMark) cm._selectionMark.clear();
+ function onCursorActivity(cm) {
+ cm.operation(function() { update(cm); });
}
- function updateSelectedText(cm) {
- clearSelectedText(cm);
+ function onChange(cm) {
+ if (cm.state.markedSelection.length)
+ cm.operation(function() { clear(cm); });
+ }
- if (cm.somethingSelected())
- cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"),
- {className: "CodeMirror-selectedtext"});
- else
- cm._selectionMark = null;
+ var CHUNK_SIZE = 8;
+ var Pos = CodeMirror.Pos;
+
+ function cmp(pos1, pos2) {
+ return pos1.line - pos2.line || pos1.ch - pos2.ch;
+ }
+
+ function coverRange(cm, from, to, addAt) {
+ if (cmp(from, to) == 0) return;
+ var array = cm.state.markedSelection;
+ var cls = cm.state.markedSelectionStyle;
+ for (var line = from.line;;) {
+ var start = line == from.line ? from : Pos(line, 0);
+ var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
+ var end = atEnd ? to : Pos(endLine, 0);
+ var mark = cm.markText(start, end, {className: cls});
+ if (addAt == null) array.push(mark);
+ else array.splice(addAt++, 0, mark);
+ if (atEnd) break;
+ line = endLine;
+ }
+ }
+
+ function clear(cm) {
+ var array = cm.state.markedSelection;
+ for (var i = 0; i < array.length; ++i) array[i].clear();
+ array.length = 0;
+ }
+
+ function reset(cm) {
+ clear(cm);
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
+ coverRange(cm, from, to);
+ }
+
+ function update(cm) {
+ var from = cm.getCursor("start"), to = cm.getCursor("end");
+ if (cmp(from, to) == 0) return clear(cm);
+
+ var array = cm.state.markedSelection;
+ if (!array.length) return coverRange(cm, from, to);
+
+ var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
+ if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
+ cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
+ return reset(cm);
+
+ while (cmp(from, coverStart.from) > 0) {
+ array.shift().clear();
+ coverStart = array[0].find();
+ }
+ if (cmp(from, coverStart.from) < 0) {
+ if (coverStart.to.line - from.line < CHUNK_SIZE) {
+ array.shift().clear();
+ coverRange(cm, from, coverStart.to, 0);
+ } else {
+ coverRange(cm, from, coverStart.from, 0);
+ }
+ }
+
+ while (cmp(to, coverEnd.to) < 0) {
+ array.pop().clear();
+ coverEnd = array[array.length - 1].find();
+ }
+ if (cmp(to, coverEnd.to) > 0) {
+ if (to.line - coverEnd.from.line < CHUNK_SIZE) {
+ array.pop().clear();
+ coverRange(cm, coverEnd.from, to);
+ } else {
+ coverRange(cm, coverEnd.to, to);
+ }
+ }
}
})();
diff --git a/gulliver/js/codemirror/addon/tern/tern.css b/gulliver/js/codemirror/addon/tern/tern.css
new file mode 100644
index 000000000..eacc2f053
--- /dev/null
+++ b/gulliver/js/codemirror/addon/tern/tern.css
@@ -0,0 +1,85 @@
+.CodeMirror-Tern-completion {
+ padding-left: 22px;
+ position: relative;
+}
+.CodeMirror-Tern-completion:before {
+ position: absolute;
+ left: 2px;
+ bottom: 2px;
+ border-radius: 50%;
+ font-size: 12px;
+ font-weight: bold;
+ height: 15px;
+ width: 15px;
+ line-height: 16px;
+ text-align: center;
+ color: white;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.CodeMirror-Tern-completion-unknown:before {
+ content: "?";
+ background: #4bb;
+}
+.CodeMirror-Tern-completion-object:before {
+ content: "O";
+ background: #77c;
+}
+.CodeMirror-Tern-completion-fn:before {
+ content: "F";
+ background: #7c7;
+}
+.CodeMirror-Tern-completion-array:before {
+ content: "A";
+ background: #c66;
+}
+.CodeMirror-Tern-completion-number:before {
+ content: "1";
+ background: #999;
+}
+.CodeMirror-Tern-completion-string:before {
+ content: "S";
+ background: #999;
+}
+.CodeMirror-Tern-completion-bool:before {
+ content: "B";
+ background: #999;
+}
+
+.CodeMirror-Tern-completion-guess {
+ color: #999;
+}
+
+.CodeMirror-Tern-tooltip {
+ border: 1px solid silver;
+ border-radius: 3px;
+ color: #444;
+ padding: 2px 5px;
+ font-size: 90%;
+ font-family: monospace;
+ background-color: white;
+ white-space: pre-wrap;
+
+ max-width: 40em;
+ position: absolute;
+ z-index: 10;
+ -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+ box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+
+ transition: opacity 1s;
+ -moz-transition: opacity 1s;
+ -webkit-transition: opacity 1s;
+ -o-transition: opacity 1s;
+ -ms-transition: opacity 1s;
+}
+
+.CodeMirror-Tern-hint-doc {
+ max-width: 25em;
+}
+
+.CodeMirror-Tern-fname { color: black; }
+.CodeMirror-Tern-farg { color: #70a; }
+.CodeMirror-Tern-farg-current { text-decoration: underline; }
+.CodeMirror-Tern-type { color: #07c; }
+.CodeMirror-Tern-fhint-guess { opacity: .7; }
diff --git a/gulliver/js/codemirror/addon/tern/tern.js b/gulliver/js/codemirror/addon/tern/tern.js
new file mode 100644
index 000000000..7f83c4e4c
--- /dev/null
+++ b/gulliver/js/codemirror/addon/tern/tern.js
@@ -0,0 +1,632 @@
+// Glue code between CodeMirror and Tern.
+//
+// Create a CodeMirror.TernServer to wrap an actual Tern server,
+// register open documents (CodeMirror.Doc instances) with it, and
+// call its methods to activate the assisting functions that Tern
+// provides.
+//
+// Options supported (all optional):
+// * defs: An array of JSON definition data structures.
+// * plugins: An object mapping plugin names to configuration
+// options.
+// * getFile: A function(name, c) that can be used to access files in
+// the project that haven't been loaded yet. Simply do c(null) to
+// indicate that a file is not available.
+// * fileFilter: A function(value, docName, doc) that will be applied
+// to documents before passing them on to Tern.
+// * switchToDoc: A function(name) that should, when providing a
+// multi-file view, switch the view or focus to the named file.
+// * showError: A function(editor, message) that can be used to
+// override the way errors are displayed.
+// * completionTip: Customize the content in tooltips for completions.
+// Is passed a single argument—the completion's data as returned by
+// Tern—and may return a string, DOM node, or null to indicate that
+// no tip should be shown. By default the docstring is shown.
+// * typeTip: Like completionTip, but for the tooltips shown for type
+// queries.
+// * responseFilter: A function(doc, query, request, error, data) that
+// will be applied to the Tern responses before treating them
+//
+//
+// It is possible to run the Tern server in a web worker by specifying
+// these additional options:
+// * useWorker: Set to true to enable web worker mode. You'll probably
+// want to feature detect the actual value you use here, for example
+// !!window.Worker.
+// * workerScript: The main script of the worker. Point this to
+// wherever you are hosting worker.js from this directory.
+// * workerDeps: An array of paths pointing (relative to workerScript)
+// to the Acorn and Tern libraries and any Tern plugins you want to
+// load. Or, if you minified those into a single script and included
+// them in the workerScript, simply leave this undefined.
+
+(function() {
+ "use strict";
+ // declare global: tern
+
+ CodeMirror.TernServer = function(options) {
+ var self = this;
+ this.options = options || {};
+ var plugins = this.options.plugins || (this.options.plugins = {});
+ if (!plugins.doc_comment) plugins.doc_comment = true;
+ if (this.options.useWorker) {
+ this.server = new WorkerServer(this);
+ } else {
+ this.server = new tern.Server({
+ getFile: function(name, c) { return getFile(self, name, c); },
+ async: true,
+ defs: this.options.defs || [],
+ plugins: plugins
+ });
+ }
+ this.docs = Object.create(null);
+ this.trackChange = function(doc, change) { trackChange(self, doc, change); };
+
+ this.cachedArgHints = null;
+ this.activeArgHints = null;
+ this.jumpStack = [];
+ };
+
+ CodeMirror.TernServer.prototype = {
+ addDoc: function(name, doc) {
+ var data = {doc: doc, name: name, changed: null};
+ this.server.addFile(name, docValue(this, data));
+ CodeMirror.on(doc, "change", this.trackChange);
+ return this.docs[name] = data;
+ },
+
+ delDoc: function(name) {
+ var found = this.docs[name];
+ if (!found) return;
+ CodeMirror.off(found.doc, "change", this.trackChange);
+ delete this.docs[name];
+ this.server.delFile(name);
+ },
+
+ hideDoc: function(name) {
+ closeArgHints(this);
+ var found = this.docs[name];
+ if (found && found.changed) sendDoc(this, found);
+ },
+
+ complete: function(cm) {
+ var self = this;
+ CodeMirror.showHint(cm, function(cm, c) { return hint(self, cm, c); }, {async: true});
+ },
+
+ getHint: function(cm, c) { return hint(this, cm, c); },
+
+ showType: function(cm, pos) { showType(this, cm, pos); },
+
+ updateArgHints: function(cm) { updateArgHints(this, cm); },
+
+ jumpToDef: function(cm) { jumpToDef(this, cm); },
+
+ jumpBack: function(cm) { jumpBack(this, cm); },
+
+ rename: function(cm) { rename(this, cm); },
+
+ request: function (cm, query, c, pos) {
+ var self = this;
+ var doc = findDoc(this, cm.getDoc());
+ var request = buildRequest(this, doc, query, pos);
+
+ this.server.request(request, function (error, data) {
+ if (!error && self.options.responseFilter)
+ data = self.options.responseFilter(doc, query, request, error, data);
+ c(error, data);
+ });
+ }
+ };
+
+ var Pos = CodeMirror.Pos;
+ var cls = "CodeMirror-Tern-";
+ var bigDoc = 250;
+
+ function getFile(ts, name, c) {
+ var buf = ts.docs[name];
+ if (buf)
+ c(docValue(ts, buf));
+ else if (ts.options.getFile)
+ ts.options.getFile(name, c);
+ else
+ c(null);
+ }
+
+ function findDoc(ts, doc, name) {
+ for (var n in ts.docs) {
+ var cur = ts.docs[n];
+ if (cur.doc == doc) return cur;
+ }
+ if (!name) for (var i = 0;; ++i) {
+ n = "[doc" + (i || "") + "]";
+ if (!ts.docs[n]) { name = n; break; }
+ }
+ return ts.addDoc(name, doc);
+ }
+
+ function trackChange(ts, doc, change) {
+ var data = findDoc(ts, doc);
+
+ var argHints = ts.cachedArgHints;
+ if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0)
+ ts.cachedArgHints = null;
+
+ var changed = data.changed;
+ if (changed == null)
+ data.changed = changed = {from: change.from.line, to: change.from.line};
+ var end = change.from.line + (change.text.length - 1);
+ if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);
+ if (end >= changed.to) changed.to = end + 1;
+ if (changed.from > change.from.line) changed.from = change.from.line;
+
+ if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {
+ if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);
+ }, 200);
+ }
+
+ function sendDoc(ts, doc) {
+ ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) {
+ if (error) console.error(error);
+ else doc.changed = null;
+ });
+ }
+
+ // Completion
+
+ function hint(ts, cm, c) {
+ ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) {
+ if (error) return showError(ts, cm, error);
+ var completions = [], after = "";
+ var from = data.start, to = data.end;
+ if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" &&
+ cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]")
+ after = "\"]";
+
+ for (var i = 0; i < data.completions.length; ++i) {
+ var completion = data.completions[i], className = typeToIcon(completion.type);
+ if (data.guess) className += " " + cls + "guess";
+ completions.push({text: completion.name + after,
+ displayText: completion.name,
+ className: className,
+ data: completion});
+ }
+
+ var obj = {from: from, to: to, list: completions};
+ var tooltip = null;
+ CodeMirror.on(obj, "close", function() { remove(tooltip); });
+ CodeMirror.on(obj, "update", function() { remove(tooltip); });
+ CodeMirror.on(obj, "select", function(cur, node) {
+ remove(tooltip);
+ var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
+ if (content) {
+ tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
+ node.getBoundingClientRect().top + window.pageYOffset, content);
+ tooltip.className += " " + cls + "hint-doc";
+ }
+ });
+ c(obj);
+ });
+ }
+
+ function typeToIcon(type) {
+ var suffix;
+ if (type == "?") suffix = "unknown";
+ else if (type == "number" || type == "string" || type == "bool") suffix = type;
+ else if (/^fn\(/.test(type)) suffix = "fn";
+ else if (/^\[/.test(type)) suffix = "array";
+ else suffix = "object";
+ return cls + "completion " + cls + "completion-" + suffix;
+ }
+
+ // Type queries
+
+ function showType(ts, cm, pos) {
+ ts.request(cm, "type", function(error, data) {
+ if (error) return showError(ts, cm, error);
+ if (ts.options.typeTip) {
+ var tip = ts.options.typeTip(data);
+ } else {
+ var tip = elt("span", null, elt("strong", null, data.type || "not found"));
+ if (data.doc)
+ tip.appendChild(document.createTextNode(" — " + data.doc));
+ if (data.url) {
+ tip.appendChild(document.createTextNode(" "));
+ tip.appendChild(elt("a", null, "[docs]")).href = data.url;
+ }
+ }
+ tempTooltip(cm, tip);
+ }, pos);
+ }
+
+ // Maintaining argument hints
+
+ function updateArgHints(ts, cm) {
+ closeArgHints(ts);
+
+ if (cm.somethingSelected()) return;
+ var state = cm.getTokenAt(cm.getCursor()).state;
+ var inner = CodeMirror.innerMode(cm.getMode(), state);
+ if (inner.mode.name != "javascript") return;
+ var lex = inner.state.lexical;
+ if (lex.info != "call") return;
+
+ var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
+ for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
+ var str = cm.getLine(line), extra = 0;
+ for (var pos = 0;;) {
+ var tab = str.indexOf("\t", pos);
+ if (tab == -1) break;
+ extra += tabSize - (tab + extra) % tabSize - 1;
+ pos = tab + 1;
+ }
+ ch = lex.column - extra;
+ if (str.charAt(ch) == "(") {found = true; break;}
+ }
+ if (!found) return;
+
+ var start = Pos(line, ch);
+ var cache = ts.cachedArgHints;
+ if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
+ return showArgHints(ts, cm, argPos);
+
+ ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
+ if (error || !data.type || !(/^fn\(/).test(data.type)) return;
+ ts.cachedArgHints = {
+ start: pos,
+ type: parseFnType(data.type),
+ name: data.exprName || data.name || "fn",
+ guess: data.guess,
+ doc: cm.getDoc()
+ };
+ showArgHints(ts, cm, argPos);
+ });
+ }
+
+ function showArgHints(ts, cm, pos) {
+ closeArgHints(ts);
+
+ var cache = ts.cachedArgHints, tp = cache.type;
+ var tip = elt("span", cache.guess ? cls + "fhint-guess" : null,
+ elt("span", cls + "fname", cache.name), "(");
+ for (var i = 0; i < tp.args.length; ++i) {
+ if (i) tip.appendChild(document.createTextNode(", "));
+ var arg = tp.args[i];
+ tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?"));
+ if (arg.type != "?") {
+ tip.appendChild(document.createTextNode(":\u00a0"));
+ tip.appendChild(elt("span", cls + "type", arg.type));
+ }
+ }
+ tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
+ if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
+ var place = cm.cursorCoords(null, "page");
+ ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip);
+ }
+
+ function parseFnType(text) {
+ var args = [], pos = 3;
+
+ function skipMatching(upto) {
+ var depth = 0, start = pos;
+ for (;;) {
+ var next = text.charAt(pos);
+ if (upto.test(next) && !depth) return text.slice(start, pos);
+ if (/[{\[\(]/.test(next)) ++depth;
+ else if (/[}\]\)]/.test(next)) --depth;
+ ++pos;
+ }
+ }
+
+ // Parse arguments
+ if (text.charAt(pos) != ")") for (;;) {
+ var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
+ if (name) {
+ pos += name[0].length;
+ name = name[1];
+ }
+ args.push({name: name, type: skipMatching(/[\),]/)});
+ if (text.charAt(pos) == ")") break;
+ pos += 2;
+ }
+
+ var rettype = text.slice(pos).match(/^\) -> (.*)$/);
+
+ return {args: args, rettype: rettype && rettype[1]};
+ }
+
+ // Moving to the definition of something
+
+ function jumpToDef(ts, cm) {
+ function inner(varName) {
+ var req = {type: "definition", variable: varName || null};
+ var doc = findDoc(ts, cm.getDoc());
+ ts.server.request(buildRequest(ts, doc, req), function(error, data) {
+ if (error) return showError(ts, cm, error);
+ if (!data.file && data.url) { window.open(data.url); return; }
+
+ if (data.file) {
+ var localDoc = ts.docs[data.file], found;
+ if (localDoc && (found = findContext(localDoc.doc, data))) {
+ ts.jumpStack.push({file: doc.name,
+ start: cm.getCursor("from"),
+ end: cm.getCursor("to")});
+ moveTo(ts, doc, localDoc, found.start, found.end);
+ return;
+ }
+ }
+ showError(ts, cm, "Could not find a definition.");
+ });
+ }
+
+ if (!atInterestingExpression(cm))
+ dialog(cm, "Jump to variable", function(name) { if (name) inner(name); });
+ else
+ inner();
+ }
+
+ function jumpBack(ts, cm) {
+ var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];
+ if (!doc) return;
+ moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);
+ }
+
+ function moveTo(ts, curDoc, doc, start, end) {
+ doc.doc.setSelection(end, start);
+ if (curDoc != doc && ts.options.switchToDoc) {
+ closeArgHints(ts);
+ ts.options.switchToDoc(doc.name);
+ }
+ }
+
+ // The {line,ch} representation of positions makes this rather awkward.
+ function findContext(doc, data) {
+ var before = data.context.slice(0, data.contextOffset).split("\n");
+ var startLine = data.start.line - (before.length - 1);
+ var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);
+
+ var text = doc.getLine(startLine).slice(start.ch);
+ for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)
+ text += "\n" + doc.getLine(cur);
+ if (text.slice(0, data.context.length) == data.context) return data;
+
+ var cursor = doc.getSearchCursor(data.context, 0, false);
+ var nearest, nearestDist = Infinity;
+ while (cursor.findNext()) {
+ var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;
+ if (!dist) dist = Math.abs(from.ch - start.ch);
+ if (dist < nearestDist) { nearest = from; nearestDist = dist; }
+ }
+ if (!nearest) return null;
+
+ if (before.length == 1)
+ nearest.ch += before[0].length;
+ else
+ nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);
+ if (data.start.line == data.end.line)
+ var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));
+ else
+ var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);
+ return {start: nearest, end: end};
+ }
+
+ function atInterestingExpression(cm) {
+ var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos);
+ if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false;
+ return /\w/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));
+ }
+
+ // Variable renaming
+
+ function rename(ts, cm) {
+ var token = cm.getTokenAt(cm.getCursor());
+ if (!/\w/.test(token.string)) showError(ts, cm, "Not at a variable");
+ dialog(cm, "New name for " + token.string, function(newName) {
+ ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) {
+ if (error) return showError(ts, cm, error);
+ applyChanges(ts, data.changes);
+ });
+ });
+ }
+
+ var nextChangeOrig = 0;
+ function applyChanges(ts, changes) {
+ var perFile = Object.create(null);
+ for (var i = 0; i < changes.length; ++i) {
+ var ch = changes[i];
+ (perFile[ch.file] || (perFile[ch.file] = [])).push(ch);
+ }
+ for (var file in perFile) {
+ var known = ts.docs[file], chs = perFile[file];;
+ if (!known) continue;
+ chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
+ var origin = "*rename" + (++nextChangeOrig);
+ for (var i = 0; i < chs.length; ++i) {
+ var ch = chs[i];
+ known.doc.replaceRange(ch.text, ch.start, ch.end, origin);
+ }
+ }
+ }
+
+ // Generic request-building helper
+
+ function buildRequest(ts, doc, query, pos) {
+ var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
+ if (!allowFragments) delete query.fullDocs;
+ if (typeof query == "string") query = {type: query};
+ query.lineCharPositions = true;
+ if (query.end == null) {
+ query.end = pos || doc.doc.getCursor("end");
+ if (doc.doc.somethingSelected())
+ query.start = doc.doc.getCursor("start");
+ }
+ var startPos = query.start || query.end;
+
+ if (doc.changed) {
+ if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&
+ doc.changed.to - doc.changed.from < 100 &&
+ doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
+ files.push(getFragmentAround(doc, startPos, query.end));
+ query.file = "#0";
+ var offsetLines = files[0].offsetLines;
+ if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
+ query.end = Pos(query.end.line - offsetLines, query.end.ch);
+ } else {
+ files.push({type: "full",
+ name: doc.name,
+ text: docValue(ts, doc)});
+ query.file = doc.name;
+ doc.changed = null;
+ }
+ } else {
+ query.file = doc.name;
+ }
+ for (var name in ts.docs) {
+ var cur = ts.docs[name];
+ if (cur.changed && cur != doc) {
+ files.push({type: "full", name: cur.name, text: docValue(ts, cur)});
+ cur.changed = null;
+ }
+ }
+
+ return {query: query, files: files};
+ }
+
+ function getFragmentAround(data, start, end) {
+ var doc = data.doc;
+ var minIndent = null, minLine = null, endLine, tabSize = 4;
+ for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
+ var line = doc.getLine(p), fn = line.search(/\bfunction\b/);
+ if (fn < 0) continue;
+ var indent = CodeMirror.countColumn(line, null, tabSize);
+ if (minIndent != null && minIndent <= indent) continue;
+ minIndent = indent;
+ minLine = p;
+ }
+ if (minLine == null) minLine = min;
+ var max = Math.min(doc.lastLine(), end.line + 20);
+ if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))
+ endLine = max;
+ else for (endLine = end.line + 1; endLine < max; ++endLine) {
+ var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
+ if (indent <= minIndent) break;
+ }
+ var from = Pos(minLine, 0);
+
+ return {type: "part",
+ name: data.name,
+ offsetLines: from.line,
+ text: doc.getRange(from, Pos(endLine, 0))};
+ }
+
+ // Generic utilities
+
+ function cmpPos(a, b) { return a.line - b.line || a.ch - b.ch; }
+
+ function elt(tagname, cls /*, ... elts*/) {
+ var e = document.createElement(tagname);
+ if (cls) e.className = cls;
+ for (var i = 2; i < arguments.length; ++i) {
+ var elt = arguments[i];
+ if (typeof elt == "string") elt = document.createTextNode(elt);
+ e.appendChild(elt);
+ }
+ return e;
+ }
+
+ function dialog(cm, text, f) {
+ if (cm.openDialog)
+ cm.openDialog(text + ": ", f);
+ else
+ f(prompt(text, ""));
+ }
+
+ // Tooltips
+
+ function tempTooltip(cm, content) {
+ var where = cm.cursorCoords();
+ var tip = makeTooltip(where.right + 1, where.bottom, content);
+ function clear() {
+ if (!tip.parentNode) return;
+ cm.off("cursorActivity", clear);
+ fadeOut(tip);
+ }
+ setTimeout(clear, 1700);
+ cm.on("cursorActivity", clear);
+ }
+
+ function makeTooltip(x, y, content) {
+ var node = elt("div", cls + "tooltip", content);
+ node.style.left = x + "px";
+ node.style.top = y + "px";
+ document.body.appendChild(node);
+ return node;
+ }
+
+ function remove(node) {
+ var p = node && node.parentNode;
+ if (p) p.removeChild(node);
+ }
+
+ function fadeOut(tooltip) {
+ tooltip.style.opacity = "0";
+ setTimeout(function() { remove(tooltip); }, 1100);
+ }
+
+ function showError(ts, cm, msg) {
+ if (ts.options.showError)
+ ts.options.showError(cm, msg);
+ else
+ tempTooltip(cm, String(msg));
+ }
+
+ function closeArgHints(ts) {
+ if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; }
+ }
+
+ function docValue(ts, doc) {
+ var val = doc.doc.getValue();
+ if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);
+ return val;
+ }
+
+ // Worker wrapper
+
+ function WorkerServer(ts) {
+ var worker = new Worker(ts.options.workerScript);
+ worker.postMessage({type: "init",
+ defs: ts.options.defs,
+ plugins: ts.options.plugins,
+ scripts: ts.options.workerDeps});
+ var msgId = 0, pending = {};
+
+ function send(data, c) {
+ if (c) {
+ data.id = ++msgId;
+ pending[msgId] = c;
+ }
+ worker.postMessage(data);
+ }
+ worker.onmessage = function(e) {
+ var data = e.data;
+ if (data.type == "getFile") {
+ getFile(ts, data.name, function(err, text) {
+ send({type: "getFile", err: String(err), text: text, id: data.id});
+ });
+ } else if (data.type == "debug") {
+ console.log(data.message);
+ } else if (data.id && pending[data.id]) {
+ pending[data.id](data.err, data.body);
+ delete pending[data.id];
+ }
+ };
+ worker.onerror = function(e) {
+ for (var id in pending) pending[id](e);
+ pending = {};
+ };
+
+ this.addFile = function(name, text) { send({type: "add", name: name, text: text}); };
+ this.delFile = function(name) { send({type: "del", name: name}); };
+ this.request = function(body, c) { send({type: "req", body: body}, c); };
+ }
+})();
diff --git a/gulliver/js/codemirror/addon/tern/worker.js b/gulliver/js/codemirror/addon/tern/worker.js
new file mode 100644
index 000000000..1ff63de41
--- /dev/null
+++ b/gulliver/js/codemirror/addon/tern/worker.js
@@ -0,0 +1,41 @@
+// declare global: tern, server
+
+var server;
+
+this.onmessage = function(e) {
+ var data = e.data;
+ switch (data.type) {
+ case "init": return startServer(data.defs, data.plugins, data.scripts);
+ case "add": return server.addFile(data.name, data.text);
+ case "del": return server.delFile(data.name);
+ case "req": return server.request(data.body, function(err, reqData) {
+ postMessage({id: data.id, body: reqData, err: err && String(err)});
+ });
+ case "getFile":
+ var c = pending[data.id];
+ delete pending[data.id];
+ return c(data.err, data.text);
+ default: throw new Error("Unknown message type: " + data.type);
+ }
+};
+
+var nextId = 0, pending = {};
+function getFile(file, c) {
+ postMessage({type: "getFile", name: file, id: ++nextId});
+ pending[nextId] = c;
+}
+
+function startServer(defs, plugins, scripts) {
+ if (scripts) importScripts.apply(null, scripts);
+
+ server = new tern.Server({
+ getFile: getFile,
+ async: true,
+ defs: defs,
+ plugins: plugins
+ });
+}
+
+var console = {
+ log: function(v) { postMessage({type: "debug", message: v}); }
+};
diff --git a/gulliver/js/codemirror/addon/wrap/hardwrap.js b/gulliver/js/codemirror/addon/wrap/hardwrap.js
new file mode 100644
index 000000000..f6d99212a
--- /dev/null
+++ b/gulliver/js/codemirror/addon/wrap/hardwrap.js
@@ -0,0 +1,111 @@
+(function() {
+ "use strict";
+
+ var Pos = CodeMirror.Pos;
+
+ function findParagraph(cm, pos, options) {
+ var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
+ for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
+ var line = cm.getLine(start);
+ if (startRE && startRE.test(line)) break;
+ if (!/\S/.test(line)) { ++start; break; }
+ }
+ var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
+ for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
+ var line = cm.getLine(end);
+ if (endRE && endRE.test(line)) { ++end; break; }
+ if (!/\S/.test(line)) break;
+ }
+ return {from: start, to: end};
+ }
+
+ function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
+ for (var at = column; at > 0; --at)
+ if (wrapOn.test(text.slice(at - 1, at + 1))) break;
+ if (at == 0) at = column;
+ var endOfText = at;
+ if (killTrailingSpace)
+ while (text.charAt(endOfText - 1) == " ") --endOfText;
+ return {from: endOfText, to: at};
+ }
+
+ function wrapRange(cm, from, to, options) {
+ from = cm.clipPos(from); to = cm.clipPos(to);
+ var column = options.column || 80;
+ var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
+ var killTrailing = options.killTrailingSpace !== false;
+ var changes = [], curLine = "", curNo = from.line;
+ var lines = cm.getRange(from, to, false);
+ if (!lines.length) return null;
+ var leadingSpace = lines[0].match(/^[ \t]*/)[0];
+
+ for (var i = 0; i < lines.length; ++i) {
+ var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
+ if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
+ curLine += " ";
+ spaceInserted = 1;
+ }
+ var spaceTrimmed = "";
+ if (i) {
+ spaceTrimmed = text.match(/^\s*/)[0];
+ text = text.slice(spaceTrimmed.length);
+ }
+ curLine += text;
+ if (i) {
+ var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
+ findBreakPoint(curLine, column, wrapOn, killTrailing);
+ // If this isn't broken, or is broken at a different point, remove old break
+ if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
+ changes.push({text: [spaceInserted ? " " : ""],
+ from: Pos(curNo, oldLen),
+ to: Pos(curNo + 1, spaceTrimmed.length)});
+ } else {
+ curLine = leadingSpace + text;
+ ++curNo;
+ }
+ }
+ while (curLine.length > column) {
+ var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
+ changes.push({text: ["", leadingSpace],
+ from: Pos(curNo, bp.from),
+ to: Pos(curNo, bp.to)});
+ curLine = leadingSpace + curLine.slice(bp.to);
+ ++curNo;
+ }
+ }
+ if (changes.length) cm.operation(function() {
+ for (var i = 0; i < changes.length; ++i) {
+ var change = changes[i];
+ cm.replaceRange(change.text, change.from, change.to);
+ }
+ });
+ return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;
+ }
+
+ CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
+ options = options || {};
+ if (!pos) pos = this.getCursor();
+ var para = findParagraph(this, pos, options);
+ return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
+ });
+
+ CodeMirror.defineExtension("wrapRange", function(from, to, options) {
+ return wrapRange(this, from, to, options || {});
+ });
+
+ CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
+ options = options || {};
+ var cm = this, paras = [];
+ for (var line = from.line; line <= to.line;) {
+ var para = findParagraph(cm, Pos(line, 0), options);
+ paras.push(para);
+ line = para.to;
+ }
+ var madeChange = false;
+ if (paras.length) cm.operation(function() {
+ for (var i = paras.length - 1; i >= 0; --i)
+ madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
+ });
+ return madeChange;
+ });
+})();
diff --git a/gulliver/js/codemirror/bin/authors.sh b/gulliver/js/codemirror/bin/authors.sh
new file mode 100644
index 000000000..b3ee99c6d
--- /dev/null
+++ b/gulliver/js/codemirror/bin/authors.sh
@@ -0,0 +1,6 @@
+# Combine existing list of authors with everyone known in git, sort, add header.
+tail --lines=+3 AUTHORS > AUTHORS.tmp
+git log --format='%aN' >> AUTHORS.tmp
+echo -e "List of CodeMirror contributors. Updated before every release.\n" > AUTHORS
+sort -u AUTHORS.tmp >> AUTHORS
+rm -f AUTHORS.tmp
diff --git a/gulliver/js/codemirror/bin/compress b/gulliver/js/codemirror/bin/compress
index d059b618b..809fbe83d 100755
--- a/gulliver/js/codemirror/bin/compress
+++ b/gulliver/js/codemirror/bin/compress
@@ -29,14 +29,15 @@ function help(ok) {
process.exit(ok ? 0 : 1);
}
-var local = null, args = null, files = [], blob = "";
+var local = null, args = [], extraArgs = null, files = [], blob = "";
for (var i = 2; i < process.argv.length; ++i) {
var arg = process.argv[i];
if (arg == "--local" && i + 1 < process.argv.length) {
var parts = process.argv[++i].split(/\s+/);
local = parts[0];
- args = parts.slice(1);
+ extraArgs = parts.slice(1);
+ if (!extraArgs.length) extraArgs = ["-c", "-m"];
} else if (arg == "--help") {
help(true);
} else if (arg[0] != "-") {
@@ -73,7 +74,7 @@ if (files.length) {
}
if (local) {
- require("child_process").spawn(local, args, {stdio: ["ignore", process.stdout, process.stderr]});
+ require("child_process").spawn(local, args.concat(extraArgs), {stdio: ["ignore", process.stdout, process.stderr]});
} else {
var data = new Buffer("js_code=" + require("querystring").escape(blob), "utf8");
var req = require("http").request({
diff --git a/gulliver/js/codemirror/bin/lint b/gulliver/js/codemirror/bin/lint
new file mode 100644
index 000000000..4f70994c5
--- /dev/null
+++ b/gulliver/js/codemirror/bin/lint
@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+var lint = require("../test/lint/lint"),
+ path = require("path");
+
+if (process.argv.length > 2) {
+ lint.checkDir(process.argv[2]);
+} else {
+ process.chdir(path.resolve(__dirname, ".."));
+ lint.checkDir("lib");
+ lint.checkDir("mode");
+ lint.checkDir("addon");
+ lint.checkDir("keymap");
+}
+
+process.exit(lint.success() ? 0 : 1);
diff --git a/gulliver/js/codemirror/bin/release b/gulliver/js/codemirror/bin/release
new file mode 100644
index 000000000..f92ab006d
--- /dev/null
+++ b/gulliver/js/codemirror/bin/release
@@ -0,0 +1,41 @@
+#!/usr/bin/env node
+
+var fs = require("fs"), child = require("child_process");
+
+var number, bumpOnly;
+
+for (var i = 2; i < process.argv.length; i++) {
+ if (process.argv[i] == "-bump") bumpOnly = true;
+ else if (/^\d+\.\d+\.\d+$/.test(process.argv[i])) number = process.argv[i];
+ else { console.log("Bogus command line arg: " + process.argv[i]); process.exit(1); }
+}
+
+if (!number) { console.log("Must give a version"); process.exit(1); }
+
+function rewrite(file, f) {
+ fs.writeFileSync(file, f(fs.readFileSync(file, "utf8")), "utf8");
+}
+
+rewrite("lib/codemirror.js", function(lib) {
+ return lib.replace(/CodeMirror\.version = "\d+\.\d+\.\d+"/,
+ "CodeMirror.version = \"" + number + "\"");
+});
+rewrite("package.json", function(pack) {
+ return pack.replace(/"version":"\d+\.\d+\.\d+"/, "\"version\":\"" + number + "\"");
+});
+
+if (bumpOnly) process.exit(0);
+
+child.exec("bash bin/authors.sh", function(){});
+
+var simple = number.slice(0, number.lastIndexOf("."));
+
+rewrite("doc/compress.html", function(cmp) {
+ return cmp.replace(/HEAD<\/option>/,
+ " HEAD \n " + simple + " ");
+});
+
+rewrite("index.html", function(index) {
+ return index.replace(/version 3.20<\/strong>/,
+ "version " + simple + " ");
+});
diff --git a/gulliver/js/codemirror/bin/source-highlight b/gulliver/js/codemirror/bin/source-highlight
new file mode 100644
index 000000000..7596ed776
--- /dev/null
+++ b/gulliver/js/codemirror/bin/source-highlight
@@ -0,0 +1,61 @@
+#!/usr/bin/env node
+
+// Simple command-line code highlighting tool. Reads code from stdin,
+// spits html to stdout. For example:
+//
+// echo 'function foo(a) { return a; }' | bin/source-highlight -s javascript
+// bin/source-highlight -s
+
+var fs = require("fs");
+
+CodeMirror = require("../addon/runmode/runmode.node.js");
+require("../mode/meta.js");
+
+var sPos = process.argv.indexOf("-s");
+if (sPos == -1 || sPos == process.argv.length - 1) {
+ console.error("Usage: source-highlight -s language");
+ process.exit(1);
+}
+var lang = process.argv[sPos + 1].toLowerCase(), modeName = lang;
+CodeMirror.modeInfo.forEach(function(info) {
+ if (info.mime == lang) {
+ modeName = info.mode;
+ } else if (info.name.toLowerCase() == lang) {
+ modeName = info.mode;
+ lang = info.mime;
+ }
+});
+
+function ensureMode(name) {
+ if (CodeMirror.modes[name] || name == "null") return;
+ try {
+ require("../mode/" + name + "/" + name + ".js");
+ } catch(e) {
+ console.error("Could not load mode " + name + ".");
+ process.exit(1);
+ }
+ var obj = CodeMirror.modes[name];
+ if (obj.dependencies) obj.dependencies.forEach(ensureMode);
+}
+ensureMode(modeName);
+
+function esc(str) {
+ return str.replace(/[<&]/, function(ch) { return ch == "&" ? "&" : "<"; });
+}
+
+var code = fs.readFileSync("/dev/stdin", "utf8");
+var curStyle = null, accum = "";
+function flush() {
+ if (curStyle) process.stdout.write("" + esc(accum) + " ");
+ else process.stdout.write(esc(accum));
+}
+
+CodeMirror.runMode(code, lang, function(text, style) {
+ if (style != curStyle) {
+ flush();
+ curStyle = style; accum = text;
+ } else {
+ accum += text;
+ }
+});
+flush();
diff --git a/gulliver/js/codemirror/bower.json b/gulliver/js/codemirror/bower.json
new file mode 100644
index 000000000..66e049dfb
--- /dev/null
+++ b/gulliver/js/codemirror/bower.json
@@ -0,0 +1,15 @@
+{
+ "name": "CodeMirror",
+ "main": ["lib/codemirror.js", "lib/codemirror.css"],
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "components",
+ "bin",
+ "demo",
+ "doc",
+ "test",
+ "index.html",
+ "package.json"
+ ]
+}
diff --git a/gulliver/js/codemirror/demo/activeline.html b/gulliver/js/codemirror/demo/activeline.html
deleted file mode 100644
index b0ea9b907..000000000
--- a/gulliver/js/codemirror/demo/activeline.html
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
- CodeMirror: Active Line Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Active Line Demo
-
-
-
-
-
- Styling the current cursor line.
-
-
-
diff --git a/gulliver/js/codemirror/demo/bidi.html b/gulliver/js/codemirror/demo/bidi.html
deleted file mode 100644
index 47feb8c5a..000000000
--- a/gulliver/js/codemirror/demo/bidi.html
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
- CodeMirror: Bi-directional Text Demo
-
-
-
-
-
-
-
-
- CodeMirror: Bi-directional Text Demo
-
-
-
-
- value (string or Doc)
- قيمة البداية المحرر. يمكن أن تكون سلسلة، أو. كائن مستند.
- mode (string or object)
- وضع الاستخدام. عندما لا تعطى، وهذا الافتراضي إلى الطريقة الاولى
- التي تم تحميلها. قد يكون من سلسلة، والتي إما أسماء أو ببساطة هو وضع
- MIME نوع المرتبطة اسطة. بدلا من ذلك، قد يكون من كائن يحتوي على
- خيارات التكوين لواسطة، مع name الخاصية التي وضع أسماء
- (على سبيل المثال {name: "javascript", json: true}).
- صفحات التجريبي لكل وضع تحتوي على معلومات حول ما معلمات تكوين وضع
- يدعمها. يمكنك أن تطلب CodeMirror التي تم تعريفها طرق وأنواع MIME
- الكشف على CodeMirror.modes
- و CodeMirror.mimeModes الكائنات. وضع خرائط الأسماء
- الأولى لمنشئات الخاصة بهم، وخرائط لأنواع MIME 2 المواصفات
- واسطة.
- theme (string)
- موضوع لنمط المحرر مع. يجب عليك التأكد من الملف CSS تحديد
- المقابلة .cm-s-[name] يتم تحميل أنماط (انظر
- theme الدليل في التوزيع).
- الافتراضي هو "default" ، والتي تم تضمينها في
- الألوان codemirror.css. فمن الممكن استخدام فئات متعددة
- في تطبيق السمات مرة واحدة على سبيل المثال "foo bar"
- سيتم تعيين كل من cm-s-foo و cm-s-bar
- الطبقات إلى المحرر.
-
-
-
-
-
- Demonstration of bi-directional text support. See
- the related
- blog post for more background.
-
-
-
diff --git a/gulliver/js/codemirror/demo/btree.html b/gulliver/js/codemirror/demo/btree.html
deleted file mode 100644
index 5e5ce0abf..000000000
--- a/gulliver/js/codemirror/demo/btree.html
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- CodeMirror: B-Tree visualization
-
-
-
-
-
-
-
- CodeMirror: B-Tree visualization
-
- Shows a visual representation of the b-tree that CodeMirror
- uses to store its document. See
- the corresponding
- blog post for a description of this format. The gray blocks
- under each leaf show the lines it holds (with their width
- representing the line height). Add and remove content to see how
- the nodes are split and merged to keep the tree balanced.
-
-
-
-
type here, see a summary of the document b-tree to the right
-
-
-
-
-
-
-Add a lot of content
-
-
-
diff --git a/gulliver/js/codemirror/demo/buffers.html b/gulliver/js/codemirror/demo/buffers.html
deleted file mode 100644
index bfd8248e4..000000000
--- a/gulliver/js/codemirror/demo/buffers.html
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
- CodeMirror: Multiple Buffer & Split View Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Multiple Buffer & Split View Demo
-
-
-
- Select buffer:
- New buffer
-
-
-
- Select buffer:
- New buffer
-
-
-
-
- Demonstration of
- using linked documents
- to provide a split view on a document, and
- using swapDoc
- to use a single editor to display multiple documents.
-
-
-
diff --git a/gulliver/js/codemirror/demo/changemode.html b/gulliver/js/codemirror/demo/changemode.html
deleted file mode 100644
index 364c5cdb0..000000000
--- a/gulliver/js/codemirror/demo/changemode.html
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
- CodeMirror: Mode-Changing Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Mode-Changing demo
-
-
-;; If there is Scheme code in here, the editor will be in Scheme mode.
-;; If you put in JS instead, it'll switch to JS mode.
-
-(define (double x)
- (* x x))
-
-
-On changes to the content of the above editor, a (crude) script
-tries to auto-detect the language used, and switches the editor to
-either JavaScript or Scheme mode based on that.
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/closebrackets.html b/gulliver/js/codemirror/demo/closebrackets.html
deleted file mode 100644
index 47304ea88..000000000
--- a/gulliver/js/codemirror/demo/closebrackets.html
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
- CodeMirror: Closebrackets Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Closebrackets Demo
-
- Type a bracket like '[', '(', '{', '"', or '''
- and the addon
- will auto-close it. Type the closing variant when directly in
- front of a matching character and it will overwrite it.
-
- If you backspace over a starting bracket while inside empty brackets
- (e.g. {|}), it will delete the closing bracket for you.
-
-
- (function() {
- var DEFAULT_BRACKETS = "()[]{}''\"\"";
-
- CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
- var wasOn = old && old != CodeMirror.Init;
- if (val && !wasOn)
- cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS));
- else if (!val && wasOn)
- cm.removeKeyMap("autoCloseBrackets");
- });
-
- function buildKeymap(pairs) {
- var map = {name : "autoCloseBrackets"};
- for (var i = 0; i < pairs.length; i += 2) (function(left, right) {
- function maybeOverwrite(cm) {
- var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1));
- if (ahead != right) return CodeMirror.Pass;
- else cm.execCommand("goCharRight");
- }
- map["'" + left + "'"] = function(cm) {
- if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return;
- var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1);
- cm.replaceSelection(left + right, {head: ahead, anchor: ahead});
- };
- if (left != right) map["'" + right + "'"] = maybeOverwrite;
- })(pairs.charAt(i), pairs.charAt(i + 1));
- return map;
- }
-})();
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/closetag.html b/gulliver/js/codemirror/demo/closetag.html
deleted file mode 100644
index 87f4f019f..000000000
--- a/gulliver/js/codemirror/demo/closetag.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- CodeMirror: Close-Tag Demo
-
-
-
-
-
-
-
-
-
-
-
-
- Close-Tag Demo
-
- Type an html tag. When you type '>' or '/', the tag will auto-close/complete. Block-level tags will indent.
- There are options for disabling tag closing or customizing the list of tags to indent.
- Works with "text/html" (based on htmlmixed.js or xml.js) mode.
- View source for key binding details.
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/complete.html b/gulliver/js/codemirror/demo/complete.html
deleted file mode 100644
index 02ce65888..000000000
--- a/gulliver/js/codemirror/demo/complete.html
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
- CodeMirror: Autocomplete Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Autocomplete demo
-
-
-function getCompletions(token, context) {
- var found = [], start = token.string;
- function maybeAdd(str) {
- if (str.indexOf(start) == 0) found.push(str);
- }
- function gatherCompletions(obj) {
- if (typeof obj == "string") forEach(stringProps, maybeAdd);
- else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
- else if (obj instanceof Function) forEach(funcProps, maybeAdd);
- for (var name in obj) maybeAdd(name);
- }
-
- if (context) {
- // If this is a property, see if it belongs to some object we can
- // find in the current environment.
- var obj = context.pop(), base;
- if (obj.className == "js-variable")
- base = window[obj.string];
- else if (obj.className == "js-string")
- base = "";
- else if (obj.className == "js-atom")
- base = 1;
- while (base != null && context.length)
- base = base[context.pop().string];
- if (base != null) gatherCompletions(base);
- }
- else {
- // If not, just look in the window object and any local scope
- // (reading into JS mode internals to get at the local variables)
- for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
- gatherCompletions(window);
- forEach(keywords, maybeAdd);
- }
- return found;
-}
-
-
-Press ctrl-space to activate autocompletion. See
-the code (here
-and here ) to figure out
-how it works.
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/completePHP.html b/gulliver/js/codemirror/demo/completePHP.html
deleted file mode 100644
index 9fcd486c0..000000000
--- a/gulliver/js/codemirror/demo/completePHP.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- CodeMirror: Autocomplete Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Autocomplete demo
-
-
-function getData($data) {
- $tre = $data . " fffoX ";
- return $tre;
-}
-
-$sa = "";
-PMFAddInputDocument(
-
-$list = array("a" => 1, "b" => 2, "c" => 4 );
-
-get Text
-insert
-replace marked
-Press ctrl-space to activate autocompletion. See
-the code (here
-and here ) to figure out
-how it works.
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/emacs.html b/gulliver/js/codemirror/demo/emacs.html
deleted file mode 100644
index b37a46b04..000000000
--- a/gulliver/js/codemirror/demo/emacs.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
- CodeMirror: Emacs bindings demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Emacs bindings demo
-
-
-#include "syscalls.h"
-/* getchar: simple buffered version */
-int getchar(void)
-{
- static char buf[BUFSIZ];
- static char *bufp = buf;
- static int n = 0;
- if (n == 0) { /* buffer is empty */
- n = read(0, buf, sizeof buf);
- bufp = buf;
- }
- return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
-}
-
-
-The emacs keybindings are enabled by
-including keymap/emacs.js and setting
-the keyMap option to "emacs". Because
-CodeMirror's internal API is quite different from Emacs, they are only
-a loose approximation of actual emacs bindings, though.
-
-Also note that a lot of browsers disallow certain keys from being
-captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the
-result that idiomatic use of Emacs keys will constantly close your tab
-or open a new window.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/folding.html b/gulliver/js/codemirror/demo/folding.html
deleted file mode 100644
index cd0417aac..000000000
--- a/gulliver/js/codemirror/demo/folding.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
- CodeMirror: Code Folding Demo
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Code Folding Demo
-
- Demonstration of code folding using the code
- in foldcode.js .
- Press ctrl-q or click on the gutter to fold a block, again
- to unfold.
-
- JavaScript:
- HTML:
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/fullscreen.html b/gulliver/js/codemirror/demo/fullscreen.html
deleted file mode 100644
index 2709ebb4b..000000000
--- a/gulliver/js/codemirror/demo/fullscreen.html
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
-
- CodeMirror: Full Screen Editing
-
-
-
-
-
-
-
-
-
- CodeMirror: Full Screen Editing
-
-
- indentWithTabs (boolean)
- Whether, when indenting, the first N*8 spaces should be
- replaced by N tabs. Default is false.
-
- tabMode (string)
- Determines what happens when the user presses the tab key.
- Must be one of the following:
-
- "classic" (the default)
- When nothing is selected, insert a tab. Otherwise,
- behave like the "shift" mode. (When shift is
- held, this behaves like the "indent" mode.)
- "shift"
- Indent all selected lines by
- one indentUnit .
- If shift was held while pressing tab, un-indent all selected
- lines one unit.
- "indent"
- Indent the line the 'correctly', based on its syntactic
- context. Only works if the
- mode supports it.
- "default"
- Do not capture tab presses, let the browser apply its
- default behaviour (which usually means it skips to the next
- control).
-
-
- enterMode (string)
- Determines whether and how new lines are indented when the
- enter key is pressed. The following modes are supported:
-
- "indent" (the default)
- Use the mode's indentation rules to give the new line
- the correct indentation.
- "keep"
- Indent the line the same as the previous line.
- "flat"
- Do not indent the new line.
-
-
- enterMode (string)
- Determines whether and how new lines are indented when the
- enter key is pressed. The following modes are supported:
-
- "indent" (the default)
- Use the mode's indentation rules to give the new line
- the correct indentation.
- "keep"
- Indent the line the same as the previous line.
- "flat"
- Do not indent the new line.
-
-
- enterMode (string)
- Determines whether and how new lines are indented when the
- enter key is pressed. The following modes are supported:
-
- "indent" (the default)
- Use the mode's indentation rules to give the new line
- the correct indentation.
- "keep"
- Indent the line the same as the previous line.
- "flat"
- Do not indent the new line.
-
-
- enterMode (string)
- Determines whether and how new lines are indented when the
- enter key is pressed. The following modes are supported:
-
- "indent" (the default)
- Use the mode's indentation rules to give the new line
- the correct indentation.
- "keep"
- Indent the line the same as the previous line.
- "flat"
- Do not indent the new line.
-
-
-
-
-
- Press F11 when cursor is in the editor to toggle full screen editing. Esc can also be used to exit full screen editing.
-
-
diff --git a/gulliver/js/codemirror/demo/html5complete.html b/gulliver/js/codemirror/demo/html5complete.html
deleted file mode 100644
index 5091354ae..000000000
--- a/gulliver/js/codemirror/demo/html5complete.html
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
- CodeMirror: Close-Tag Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- HTML5 code completation demo
-
- Type an html tag. If you press Ctrl+Space a hint panel show the code suggest. You can type to autocomplete tags, attributes if your cursor are inner a tag or attribute values if your cursor are inner a attribute value.
-
-
-
-
-
-
-
-
- Home - W2S Web IDE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
W2S Cloud IDE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/indentwrap.html b/gulliver/js/codemirror/demo/indentwrap.html
deleted file mode 100644
index c367c945d..000000000
--- a/gulliver/js/codemirror/demo/indentwrap.html
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
- CodeMirror: Indented wrapped line demo
-
-
-
-
-
-
-
-
- CodeMirror: Indented wrapped line demo
-
-
-
-
- Overview
-
- CodeMirror is a code-editor component that can be embedded in Web pages. The core library provides only the editor component, no accompanying buttons, auto-completion, or other IDE functionality. It does provide a rich API on top of which such functionality can be straightforwardly implemented. See the add-ons included in the distribution, and the CodeMirror UI project, for reusable implementations of extra features.
-
- CodeMirror works with language-specific modes. Modes are JavaScript programs that help color (and optionally indent) text written in a given language. The distribution comes with a number of modes (see the mode/ directory), and it isn't hard to write new ones for other languages.
-
-
-
- This page uses a hack on top of the "renderLine"
- event to make wrapped text line up with the base indentation of
- the line.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/lint.html b/gulliver/js/codemirror/demo/lint.html
deleted file mode 100644
index ece8b1cef..000000000
--- a/gulliver/js/codemirror/demo/lint.html
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
- CodeMirror: Linter Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Linter Demo
-
- var widgets = []
-function updateHints() {
- editor.operation(function(){
- for (var i = 0; i < widgets.length; ++i)
- editor.removeLineWidget(widgets[i]);
- widgets.length = 0;
-
- JSHINT(editor.getValue());
- for (var i = 0; i < JSHINT.errors.length; ++i) {
- var err = JSHINT.errors[i];
- if (!err) continue;
- var msg = document.createElement("div");
- var icon = msg.appendChild(document.createElement("span"));
- icon.innerHTML = "!!";
- icon.className = "lint-error-icon";
- msg.appendChild(document.createTextNode(err.reason));
- msg.className = "lint-error";
- widgets.push(editor.addLineWidget(err.line - 1, msg, {coverGutter: false, noHScroll: true}));
- }
- });
- var info = editor.getScrollInfo();
- var after = editor.charCoords({line: editor.getCursor().line + 1, ch: 0}, "local").top;
- if (info.top + info.clientHeight < after)
- editor.scrollTo(null, after - info.clientHeight + 3);
-}
-
-
- [
- {
- _id: "post 1",
- "author": "Bob",
- "content": "...",
- "page_views": 5
- },
- {
- "_id": "post 2",
- "author": "Bob",
- "content": "...",
- "page_views": 9
- },
- {
- "_id": "post 3",
- "author": "Bob",
- "content": "...",
- "page_views": 8
- }
-]
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/loadmode.html b/gulliver/js/codemirror/demo/loadmode.html
deleted file mode 100644
index 1bd958f70..000000000
--- a/gulliver/js/codemirror/demo/loadmode.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- CodeMirror: Lazy Mode Loading Demo
-
-
-
-
-
-
-
-
- CodeMirror: Lazy Mode Loading
-
- This is the editor.
-// It starts out in plain text mode,
-# use the control below to load and apply a mode
- "you'll see the highlighting of" this text /*change*/.
-
- change mode
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/marker.html b/gulliver/js/codemirror/demo/marker.html
deleted file mode 100644
index f0981e4d5..000000000
--- a/gulliver/js/codemirror/demo/marker.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- CodeMirror: Breakpoint Demo
-
-
-
-
-
-
-
-
- CodeMirror: Breakpoint demo
-
-
-var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
- lineNumbers: true,
- gutters: ["CodeMirror-linenumbers", "breakpoints"]
-});
-editor.on("gutterClick", function(cm, n) {
- var info = cm.lineInfo(n);
- cm.setGutterMarker(n, "breakpoints", info.markers ? null : makeMarker());
-});
-
-function makeMarker() {
- var marker = document.createElement("div");
- marker.innerHTML = "●";
- marker.className = "breakpoint";
- return marker;
-}
-
-
-Click the line-number gutter to add or remove 'breakpoints'.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/markselection.html b/gulliver/js/codemirror/demo/markselection.html
deleted file mode 100644
index e1c054869..000000000
--- a/gulliver/js/codemirror/demo/markselection.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
- CodeMirror: Match Highlighter Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Mark Selection Demo
-
- Select something from here.
-You'll see that the selection's foreground color changes to white!
-Since, by default, CodeMirror only puts an independent "marker" layer
-behind the text, you'll need something like this to change its colour.
-
-
-
- Simple addon to easily mark (and style) selected text.
-
-
-
diff --git a/gulliver/js/codemirror/demo/matchhighlighter.html b/gulliver/js/codemirror/demo/matchhighlighter.html
deleted file mode 100644
index c574fbae8..000000000
--- a/gulliver/js/codemirror/demo/matchhighlighter.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
- CodeMirror: Match Highlighter Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Match Highlighter Demo
-
- Select this text: hardToSpotVar
- And everywhere else in your code where hardToSpotVar appears will automatically illuminate.
-Give it a try! No more hardToSpotVars.
-
-
-
- Search and highlight occurences of the selected text.
-
-
-
diff --git a/gulliver/js/codemirror/demo/multiplex.html b/gulliver/js/codemirror/demo/multiplex.html
deleted file mode 100644
index 9ebe8f357..000000000
--- a/gulliver/js/codemirror/demo/multiplex.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
- CodeMirror: Multiplexing Parser Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Multiplexing Parser Demo
-
-
-
-
- << this is not >
- <<
- multiline
- not html
- at all : &
- >>
- this is html again
-
-
-
-
-
-
- Demonstration of a multiplexing mode, which, at certain
- boundary strings, switches to one or more inner modes. The out
- (HTML) mode does not get fed the content of the <<
- >> blocks. See
- the manual and
- the source for more
- information.
-
-
-
diff --git a/gulliver/js/codemirror/demo/mustache.html b/gulliver/js/codemirror/demo/mustache.html
deleted file mode 100644
index 9d2081dc4..000000000
--- a/gulliver/js/codemirror/demo/mustache.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- CodeMirror: Overlay Parser Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Overlay Parser Demo
-
-
-
-
- {{title}}
- These are links to {{things}}:
-
-
-
-
-
-
-
- Demonstration of a mode that parses HTML, highlighting
- the Mustache templating
- directives inside of it by using the code
- in overlay.js . View
- source to see the 15 lines of code needed to accomplish this.
-
-
-
diff --git a/gulliver/js/codemirror/demo/placeholder.html b/gulliver/js/codemirror/demo/placeholder.html
deleted file mode 100644
index b0f245695..000000000
--- a/gulliver/js/codemirror/demo/placeholder.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
- CodeMirror: Placeholder demo
-
-
-
-
-
-
-
-
- CodeMirror: Placeholder demo
-
-
-
- The placeholder
- plug-in adds an option placeholder that can be set to
- make text appear in the editor when it is empty and not focused.
- If the source textarea has a placeholder attribute,
- it will automatically be inherited.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/preview.html b/gulliver/js/codemirror/demo/preview.html
deleted file mode 100644
index f70cdb009..000000000
--- a/gulliver/js/codemirror/demo/preview.html
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
- CodeMirror: HTML5 preview
-
-
-
-
-
-
-
-
-
-
- CodeMirror: HTML5 preview
-
-
-
-
-
- HTML5 canvas demo
-
-
-
- Canvas pane goes here:
-
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/resize.html b/gulliver/js/codemirror/demo/resize.html
deleted file mode 100644
index 7badc2bfb..000000000
--- a/gulliver/js/codemirror/demo/resize.html
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
- CodeMirror: Autoresize Demo
-
-
-
-
-
-
-
-
- CodeMirror: Autoresize demo
-
-
-.CodeMirror {
- border: 1px solid #eee;
- height: auto;
-}
-.CodeMirror-scroll {
- overflow-y: hidden;
- overflow-x: auto;
-}
-
-
-By setting a few CSS properties, and giving
-the viewportMargin
-a value of Infinity, CodeMirror can be made to
-automatically resize to fit its content.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/runmode.html b/gulliver/js/codemirror/demo/runmode.html
deleted file mode 100644
index dba808ba7..000000000
--- a/gulliver/js/codemirror/demo/runmode.html
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
- CodeMirror: Mode Runner Demo
-
-
-
-
-
-
-
- CodeMirror: Mode Runner Demo
-
-
-
- Enter your xml here and press the button below to display
- it as highlighted by the CodeMirror XML mode
-
-
- Highlight!
-
-
-
-
- Running a CodeMirror mode outside of the editor.
- The CodeMirror.runMode function, defined
- in lib/runmode.js takes the following arguments:
-
-
- text (string)
- The document to run through the highlighter.
- mode (mode spec )
- The mode to use (must be loaded as normal).
- output (function or DOM node)
- If this is a function, it will be called for each token with
- two arguments, the token's text and the token's style class (may
- be null for unstyled tokens). If it is a DOM node,
- the tokens will be converted to span elements as in
- an editor, and inserted into the node
- (through innerHTML).
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/search.html b/gulliver/js/codemirror/demo/search.html
deleted file mode 100644
index d72107156..000000000
--- a/gulliver/js/codemirror/demo/search.html
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
- CodeMirror: Search/Replace Demo
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Search/Replace Demo
-
-
- indentWithTabs (boolean)
- Whether, when indenting, the first N*8 spaces should be
- replaced by N tabs. Default is false.
-
- tabMode (string)
- Determines what happens when the user presses the tab key.
- Must be one of the following:
-
- "classic" (the default)
- When nothing is selected, insert a tab. Otherwise,
- behave like the "shift" mode. (When shift is
- held, this behaves like the "indent" mode.)
- "shift"
- Indent all selected lines by
- one indentUnit .
- If shift was held while pressing tab, un-indent all selected
- lines one unit.
- "indent"
- Indent the line the 'correctly', based on its syntactic
- context. Only works if the
- mode supports it.
- "default"
- Do not capture tab presses, let the browser apply its
- default behaviour (which usually means it skips to the next
- control).
-
-
- enterMode (string)
- Determines whether and how new lines are indented when the
- enter key is pressed. The following modes are supported:
-
- "indent" (the default)
- Use the mode's indentation rules to give the new line
- the correct indentation.
- "keep"
- Indent the line the same as the previous line.
- "flat"
- Do not indent the new line.
-
-
-
-
-
- Demonstration of primitive search/replace functionality. The
- keybindings (which can be overridden by custom keymaps) are:
-
- Ctrl-F / Cmd-F Start searching
- Ctrl-G / Cmd-G Find next
- Shift-Ctrl-G / Shift-Cmd-G Find previous
- Shift-Ctrl-F / Cmd-Option-F Replace
- Shift-Ctrl-R / Shift-Cmd-Option-F Replace all
-
- Searching is enabled by
- including addon/search/search.js
- and addon/search/searchcursor.js .
- For good-looking input dialogs, you also want to include
- addon/dialog/dialog.js
- and addon/dialog/dialog.css .
-
-
diff --git a/gulliver/js/codemirror/demo/spanaffectswrapping_shim.html b/gulliver/js/codemirror/demo/spanaffectswrapping_shim.html
deleted file mode 100644
index 733db067f..000000000
--- a/gulliver/js/codemirror/demo/spanaffectswrapping_shim.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
- CodeMirror: Automatically derive odd wrapping behavior for your browser
-
-
-
- CodeMirror: odd wrapping shim
-
- This is a hack to automatically derive
- a spanAffectsWrapping regexp for a browser. See the
- comments above that variable
- in lib/codemirror.js
- for some more details.
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/theme.html b/gulliver/js/codemirror/demo/theme.html
deleted file mode 100644
index 046d1fc3e..000000000
--- a/gulliver/js/codemirror/demo/theme.html
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- CodeMirror: Theme Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Theme demo
-
-
-function findSequence(goal) {
- function find(start, history) {
- if (start == goal)
- return history;
- else if (start > goal)
- return null;
- else
- return find(start + 5, "(" + history + " + 5)") ||
- find(start * 3, "(" + history + " * 3)");
- }
- return find(1, "1");
-}
-
-Select a theme:
- default
- ambiance
- blackboard
- cobalt
- eclipse
- elegant
- erlang-dark
- lesser-dark
- monokai
- neat
- night
- rubyblue
- solarized dark
- solarized light
- twilight
- vibrant-ink
- xq-dark
- xq-light
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/variableheight.html b/gulliver/js/codemirror/demo/variableheight.html
deleted file mode 100644
index b00f7e454..000000000
--- a/gulliver/js/codemirror/demo/variableheight.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
- CodeMirror: Variable Height Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Variable Height Demo
-
- # A First Level Header
-
-**Bold** text in a normal-size paragraph.
-
-And a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long, wrapped line with a piece of **big** text inside of it.
-
-## A Second Level Header
-
-Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.
-
-The quick brown fox jumped over the lazy
-dog's back.
-
-### Header 3
-
-> This is a blockquote.
->
-> This is the second paragraph in the blockquote.
->
-> ## This is an H2 in a blockquote
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/vim.html b/gulliver/js/codemirror/demo/vim.html
deleted file mode 100644
index c5835d40d..000000000
--- a/gulliver/js/codemirror/demo/vim.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
- CodeMirror: Vim bindings demo
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Vim bindings demo
-
-
-#include "syscalls.h"
-/* getchar: simple buffered version */
-int getchar(void)
-{
- static char buf[BUFSIZ];
- static char *bufp = buf;
- static int n = 0;
- if (n == 0) { /* buffer is empty */
- n = read(0, buf, sizeof buf);
- bufp = buf;
- }
- return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
-}
-
-
-
- I am another file! You can yank from my neighbor and paste here.
-
-
-The vim keybindings are enabled by
-including keymap/vim.js and setting
-the keyMap option to "vim". Because
-CodeMirror's internal API is quite different from Vim, they are only
-a loose approximation of actual vim bindings, though.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/visibletabs.html b/gulliver/js/codemirror/demo/visibletabs.html
deleted file mode 100644
index 109d1a6b0..000000000
--- a/gulliver/js/codemirror/demo/visibletabs.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
- CodeMirror: Visible tabs demo
-
-
-
-
-
-
-
-
- CodeMirror: Visible tabs demo
-
-
-#include "syscalls.h"
-/* getchar: simple buffered version */
-int getchar(void)
-{
- static char buf[BUFSIZ];
- static char *bufp = buf;
- static int n = 0;
- if (n == 0) { /* buffer is empty */
- n = read(0, buf, sizeof buf);
- bufp = buf;
- }
- return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
-}
-
-
-Tabs inside the editor are spans with the
-class cm-tab, and can be styled.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/demo/widget.html b/gulliver/js/codemirror/demo/widget.html
deleted file mode 100644
index a3b27a9e4..000000000
--- a/gulliver/js/codemirror/demo/widget.html
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
- CodeMirror: Inline Widget Demo
-
-
-
-
-
-
-
-
-
- CodeMirror: Inline Widget Demo
-
-
-
-This demo runs JSHint over the code
-in the editor (which is the script used on this page), and
-inserts line widgets to
-display the warnings that JSHint comes up with.
-
-
diff --git a/gulliver/js/codemirror/demo/xmlcomplete.html b/gulliver/js/codemirror/demo/xmlcomplete.html
deleted file mode 100644
index 28a50638f..000000000
--- a/gulliver/js/codemirror/demo/xmlcomplete.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- CodeMirror: XML Autocomplete Demo
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: XML Autocomplete demo
-
-
-
- Type '<' or space inside tag or
- press ctrl-space to activate autocompletion. See
- the code (here
- and here ) to figure out how
- it works.
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/baboon.png b/gulliver/js/codemirror/doc/baboon.png
deleted file mode 100644
index 55d97f70b..000000000
Binary files a/gulliver/js/codemirror/doc/baboon.png and /dev/null differ
diff --git a/gulliver/js/codemirror/doc/baboon_vector.svg b/gulliver/js/codemirror/doc/baboon_vector.svg
deleted file mode 100644
index dc1667af9..000000000
--- a/gulliver/js/codemirror/doc/baboon_vector.svg
+++ /dev/null
@@ -1,153 +0,0 @@
-
-
-
-image/svg+xml
\ No newline at end of file
diff --git a/gulliver/js/codemirror/doc/compress.html b/gulliver/js/codemirror/doc/compress.html
deleted file mode 100644
index 06ed4970a..000000000
--- a/gulliver/js/codemirror/doc/compress.html
+++ /dev/null
@@ -1,197 +0,0 @@
-
-
-
-
- CodeMirror: Compression Helper
-
-
-
-
-
-
-
-
-
-
-/* Script compression
- helper */
-
-
-
- To optimize loading CodeMirror, especially when including a
- bunch of different modes, it is recommended that you combine and
- minify (and preferably also gzip) the scripts. This page makes
- those first two steps very easy. Simply select the version and
- scripts you need in the form below, and
- click Compress to download the minified script
- file.
-
-
-
- Version:
- HEAD
- 3.11
- 3.1
- 3.02
- 3.01
- 3.0
- 2.38
- 2.37
- 2.36
- 2.35
- 2.34
- 2.33
- 2.32
- 2.31
- 2.3
- 2.25
- 2.24
- 2.23
- 2.22
- 2.21
- 2.2
- 2.18
- 2.16
- 2.15
- 2.13
- 2.12
- 2.11
- 2.1
- 2.02
- 2.01
- 2.0
- beta2
- beta1
-
-
-
-
- codemirror.js
-
-
- apl.js
- clike.js
- clojure.js
- coffeescript.js
- commonlisp.js
- css.js
- d.js
- diff.js
- ecl.js
- erlang.js
- gfm.js
- go.js
- groovy.js
- haskell.js
- haxe.js
- htmlembedded.js
- htmlmixed.js
- http.js
- javascript.js
- jinja2.js
- less.js
- livescript.js
- lua.js
- markdown.js
- mirc.js
- ntriples.js
- ocaml.js
- pascal.js
- perl.js
- php.js
- pig.js
- properties.js
- python.js
- q.js
- r.js
- rpm/changes.js
- rpm/spec.js
- rst.js
- ruby.js
- rust.js
- sass.js
- scala.js
- scheme.js
- shell.js
- sieve.js
- smalltalk.js
- smarty.js
- sql.js
- sparql.js
- stex.js
- tcl.js
- tiddlywiki.js
- tiki.js
- turtle.js
- vb.js
- vbscript.js
- velocity.js
- verilog.js
- xml.js
- xquery.js
- yaml.js
- z80.js
-
-
- dialog.js
- closetag.js
- continuecomment.js
- continuelist.js
- matchbrackets.js
- closebrackets.js
- foldcode.js
- xml-fold.js
- brace-fold.js
- indent-fold.js
- javascript-hint.js
- xml-hint.js
- html-hint.js
- pig-hint.js
- python-hint.js
- loadmode.js
- overlay.js
- multiplex.js
- colorize.js
- runmode.js
- runmode-standalone.js
- runmode.node.js
- search.js
- searchcursor.js
- match-highlighter.js
- mark-selection.js
- active-line.js
- lint.js
- javascript-lint.js
- json-lint.js
-
-
- emacs.js
- vim.js
-
-
-
-
- Compress with UglifyJS
-
-
- Custom code to add to the compressed file:
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/docs.css b/gulliver/js/codemirror/doc/docs.css
deleted file mode 100644
index 170cd4124..000000000
--- a/gulliver/js/codemirror/doc/docs.css
+++ /dev/null
@@ -1,167 +0,0 @@
-body {
- font-family: Droid Sans, Arial, sans-serif;
- line-height: 1.5;
- max-width: 64.3em;
- margin: 3em auto;
- padding: 0 1em;
-}
-
-h1 {
- letter-spacing: -3px;
- font-size: 3.23em;
- font-weight: bold;
- margin: 0;
-}
-
-h2 {
- font-size: 1.23em;
- font-weight: bold;
- margin: .5em 0;
- letter-spacing: -1px;
-}
-
-h3 {
- font-size: 1.1em;
- font-weight: bold;
- margin: .4em 0;
-}
-
-pre {
- background-color: #eee;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
- border-radius: 6px;
- padding: 1em;
-}
-
-pre.code {
- margin: 0 1em;
-}
-
-.grey {
- background-color: #eee;
- border-radius: 6px;
- margin-bottom: 1.65em;
- margin-top: 0.825em;
- padding: 0.825em 1.65em;
- position: relative;
-}
-
-img.logo {
- position: absolute;
- right: -1em;
- bottom: 4px;
- max-width: 23.6875em; /* Scale image down with text to prevent clipping */
-}
-
-.grey > pre {
- background:none;
- border-radius:0;
- padding:0;
- margin:0;
- font-size:2.2em;
- line-height:1.2em;
-}
-
-a:link, a:visited, .quasilink {
- color: #df0019;
- cursor: pointer;
- text-decoration: none;
-}
-
-a:hover, .quasilink:hover {
- color: #800004;
-}
-
-h1 a:link, h1 a:visited, h1 a:hover {
- color: black;
-}
-
-ul {
- margin: 0;
- padding-left: 1.2em;
-}
-
-a.download {
- color: white;
- background-color: #df0019;
- width: 100%;
- display: block;
- text-align: center;
- font-size: 1.23em;
- font-weight: bold;
- text-decoration: none;
- -moz-border-radius: 6px;
- -webkit-border-radius: 6px;
- border-radius: 6px;
- padding: .5em 0;
- margin-bottom: 1em;
-}
-
-a.download:hover {
- background-color: #bb0010;
-}
-
-.rel {
- margin-bottom: 0;
-}
-
-.rel-note {
- color: #777;
- font-size: .9em;
- margin-top: .1em;
-}
-
-.logo-braces {
- color: #df0019;
- position: relative;
- top: -4px;
-}
-
-.blk {
- float: left;
-}
-
-.left {
- margin-right: 20.68em;
- max-width: 37em;
- padding-right: 6.53em;
- padding-bottom: 1em;
-}
-
-.left1 {
- width: 15.24em;
- padding-right: 6.45em;
-}
-
-.left2 {
- max-width: 15.24em;
-}
-
-.right {
- width: 20.68em;
- margin-left: -20.68em;
-}
-
-.leftbig {
- width: 42.44em;
- padding-right: 6.53em;
-}
-
-.rightsmall {
- width: 15.24em;
-}
-
-.clear:after {
- visibility: hidden;
- display: block;
- font-size: 0;
- content: " ";
- clear: both;
- height: 0;
-}
-.clear { display: inline-block; }
-/* start commented backslash hack \*/
-* html .clear { height: 1%; }
-.clear { display: block; }
-/* close commented backslash hack */
diff --git a/gulliver/js/codemirror/doc/internals.html b/gulliver/js/codemirror/doc/internals.html
deleted file mode 100644
index 9139528f3..000000000
--- a/gulliver/js/codemirror/doc/internals.html
+++ /dev/null
@@ -1,505 +0,0 @@
-
-
-
-
- CodeMirror: Internals
-
-
-
-
-
-
-
-
-
-
-
-/* (Re-) Implementing A Syntax-
- Highlighting Editor in JavaScript */
-
-
-
-
-
-
- Topic: JavaScript, code editor implementation
- Author: Marijn Haverbeke
- Date: March 2nd 2011 (updated November 13th 2011)
-
-
-
Caution : this text was written briefly after
-version 2 was initially written. It no longer (even including the
-update at the bottom) fully represents the current implementation. I'm
-leaving it here as a historic document. For more up-to-date
-information, look at the entries
-tagged cm-internals
-on my blog.
-
-
This is a followup to
-my Brutal Odyssey to the
-Dark Side of the DOM Tree story. That one describes the
-mind-bending process of implementing (what would become) CodeMirror 1.
-This one describes the internals of CodeMirror 2, a complete rewrite
-and rethink of the old code base. I wanted to give this piece another
-Hunter Thompson copycat subtitle, but somehow that would be out of
-place—the process this time around was one of straightforward
-engineering, requiring no serious mind-bending whatsoever.
-
-
So, what is wrong with CodeMirror 1? I'd estimate, by mailing list
-activity and general search-engine presence, that it has been
-integrated into about a thousand systems by now. The most prominent
-one, since a few weeks,
-being Google
-code's project hosting . It works, and it's being used widely.
-
-
Still, I did not start replacing it because I was bored. CodeMirror
-1 was heavily reliant on designMode
-or contentEditable (depending on the browser). Neither of
-these are well specified (HTML5 tries
-to specify
-their basics), and, more importantly, they tend to be one of the more
-obscure and buggy areas of browser functionality—CodeMirror, by using
-this functionality in a non-typical way, was constantly running up
-against browser bugs. WebKit wouldn't show an empty line at the end of
-the document, and in some releases would suddenly get unbearably slow.
-Firefox would show the cursor in the wrong place. Internet Explorer
-would insist on linkifying everything that looked like a URL or email
-address, a behaviour that can't be turned off. Some bugs I managed to
-work around (which was often a frustrating, painful process), others,
-such as the Firefox cursor placement, I gave up on, and had to tell
-user after user that they were known problems, but not something I
-could help.
-
-
Also, there is the fact that designMode (which seemed
-to be less buggy than contentEditable in Webkit and
-Firefox, and was thus used by CodeMirror 1 in those browsers) requires
-a frame. Frames are another tricky area. It takes some effort to
-prevent getting tripped up by domain restrictions, they don't
-initialize synchronously, behave strangely in response to the back
-button, and, on several browsers, can't be moved around the DOM
-without having them re-initialize. They did provide a very nice way to
-namespace the library, though—CodeMirror 1 could freely pollute the
-namespace inside the frame.
-
-
Finally, working with an editable document means working with
-selection in arbitrary DOM structures. Internet Explorer (8 and
-before) has an utterly different (and awkward) selection API than all
-of the other browsers, and even among the different implementations of
-document.selection, details about how exactly a selection
-is represented vary quite a bit. Add to that the fact that Opera's
-selection support tended to be very buggy until recently, and you can
-imagine why CodeMirror 1 contains 700 lines of selection-handling
-code.
-
-
And that brings us to the main issue with the CodeMirror 1
-code base: The proportion of browser-bug-workarounds to real
-application code was getting dangerously high. By building on top of a
-few dodgy features, I put the system in a vulnerable position—any
-incompatibility and bugginess in these features, I had to paper over
-with my own code. Not only did I have to do some serious stunt-work to
-get it to work on older browsers (as detailed in the
-previous story ), things
-also kept breaking in newly released versions, requiring me to come up
-with new scary hacks in order to keep up. This was starting
-to lose its appeal.
-
-
General Approach
-
-
What CodeMirror 2 does is try to sidestep most of the hairy hacks
-that came up in version 1. I owe a lot to the
-ACE editor for inspiration on how to
-approach this.
-
-
I absolutely did not want to be completely reliant on key events to
-generate my input. Every JavaScript programmer knows that key event
-information is horrible and incomplete. Some people (most awesomely
-Mihai Bazon with Ymacs ) have been able
-to build more or less functioning editors by directly reading key
-events, but it takes a lot of work (the kind of never-ending, fragile
-work I described earlier), and will never be able to properly support
-things like multi-keystoke international character
-input. [see below for caveat]
-
-
So what I do is focus a hidden textarea, and let the browser
-believe that the user is typing into that. What we show to the user is
-a DOM structure we built to represent his document. If this is updated
-quickly enough, and shows some kind of believable cursor, it feels
-like a real text-input control.
-
-
Another big win is that this DOM representation does not have to
-span the whole document. Some CodeMirror 1 users insisted that they
-needed to put a 30 thousand line XML document into CodeMirror. Putting
-all that into the DOM takes a while, especially since, for some
-reason, an editable DOM tree is slower than a normal one on most
-browsers. If we have full control over what we show, we must only
-ensure that the visible part of the document has been added, and can
-do the rest only when needed. (Fortunately, the onscroll
-event works almost the same on all browsers, and lends itself well to
-displaying things only as they are scrolled into view.)
-
-
-
-
ACE uses its hidden textarea only as a text input shim, and does
-all cursor movement and things like text deletion itself by directly
-handling key events. CodeMirror's way is to let the browser do its
-thing as much as possible, and not, for example, define its own set of
-key bindings. One way to do this would have been to have the whole
-document inside the hidden textarea, and after each key event update
-the display DOM to reflect what's in that textarea.
-
-
That'd be simple, but it is not realistic. For even medium-sized
-document the editor would be constantly munging huge strings, and get
-terribly slow. What CodeMirror 2 does is put the current selection,
-along with an extra line on the top and on the bottom, into the
-textarea.
-
-
This means that the arrow keys (and their ctrl-variations), home,
-end, etcetera, do not have to be handled specially. We just read the
-cursor position in the textarea, and update our cursor to match it.
-Also, copy and paste work pretty much for free, and people get their
-native key bindings, without any special work on my part. For example,
-I have emacs key bindings configured for Chrome and Firefox. There is
-no way for a script to detect this. [no longer the case]
-
-
Of course, since only a small part of the document sits in the
-textarea, keys like page up and ctrl-end won't do the right thing.
-CodeMirror is catching those events and handling them itself.
-
-
Selection
-
-
Getting and setting the selection range of a textarea in modern
-browsers is trivial—you just use the selectionStart
-and selectionEnd properties. On IE you have to do some
-insane stuff with temporary ranges and compensating for the fact that
-moving the selection by a 'character' will treat \r\n as a single
-character, but even there it is possible to build functions that
-reliably set and get the selection range.
-
-
But consider this typical case: When I'm somewhere in my document,
-press shift, and press the up arrow, something gets selected. Then, if
-I, still holding shift, press the up arrow again, the top of my
-selection is adjusted. The selection remembers where its head
-and its anchor are, and moves the head when we shift-move.
-This is a generally accepted property of selections, and done right by
-every editing component built in the past twenty years.
-
-
But not something that the browser selection APIs expose.
-
-
Great. So when someone creates an 'upside-down' selection, the next
-time CodeMirror has to update the textarea, it'll re-create the
-selection as an 'upside-up' selection, with the anchor at the top, and
-the next cursor motion will behave in an unexpected way—our second
-up-arrow press in the example above will not do anything, since it is
-interpreted in exactly the same way as the first.
-
-
No problem. We'll just, ehm, detect that the selection is
-upside-down (you can tell by the way it was created), and then, when
-an upside-down selection is present, and a cursor-moving key is
-pressed in combination with shift, we quickly collapse the selection
-in the textarea to its start, allow the key to take effect, and then
-combine its new head with its old anchor to get the real
-selection.
-
-
In short, scary hacks could not be avoided entirely in CodeMirror
-2.
-
-
And, the observant reader might ask, how do you even know that a
-key combo is a cursor-moving combo, if you claim you support any
-native key bindings? Well, we don't, but we can learn. The editor
-keeps a set known cursor-movement combos (initialized to the
-predictable defaults), and updates this set when it observes that
-pressing a certain key had (only) the effect of moving the cursor.
-This, of course, doesn't work if the first time the key is used was
-for extending an inverted selection, but it works most of the
-time.
-
-
Intelligent Updating
-
-
One thing that always comes up when you have a complicated internal
-state that's reflected in some user-visible external representation
-(in this case, the displayed code and the textarea's content) is
-keeping the two in sync. The naive way is to just update the display
-every time you change your state, but this is not only error prone
-(you'll forget), it also easily leads to duplicate work on big,
-composite operations. Then you start passing around flags indicating
-whether the display should be updated in an attempt to be efficient
-again and, well, at that point you might as well give up completely.
-
-
I did go down that road, but then switched to a much simpler model:
-simply keep track of all the things that have been changed during an
-action, and then, only at the end, use this information to update the
-user-visible display.
-
-
CodeMirror uses a concept of operations , which start by
-calling a specific set-up function that clears the state and end by
-calling another function that reads this state and does the required
-updating. Most event handlers, and all the user-visible methods that
-change state are wrapped like this. There's a method
-called operation that accepts a function, and returns
-another function that wraps the given function as an operation.
-
-
It's trivial to extend this (as CodeMirror does) to detect nesting,
-and, when an operation is started inside an operation, simply
-increment the nesting count, and only do the updating when this count
-reaches zero again.
-
-
If we have a set of changed ranges and know the currently shown
-range, we can (with some awkward code to deal with the fact that
-changes can add and remove lines, so we're dealing with a changing
-coordinate system) construct a map of the ranges that were left
-intact. We can then compare this map with the part of the document
-that's currently visible (based on scroll offset and editor height) to
-determine whether something needs to be updated.
-
-
CodeMirror uses two update algorithms—a full refresh, where it just
-discards the whole part of the DOM that contains the edited text and
-rebuilds it, and a patch algorithm, where it uses the information
-about changed and intact ranges to update only the out-of-date parts
-of the DOM. When more than 30 percent (which is the current heuristic,
-might change) of the lines need to be updated, the full refresh is
-chosen (since it's faster to do than painstakingly finding and
-updating all the changed lines), in the other case it does the
-patching (so that, if you scroll a line or select another character,
-the whole screen doesn't have to be
-re-rendered). [the full-refresh
-algorithm was dropped, it wasn't really faster than the patching
-one]
-
-
All updating uses innerHTML rather than direct DOM
-manipulation, since that still seems to be by far the fastest way to
-build documents. There's a per-line function that combines the
-highlighting, marking , and
-selection info for that line into a snippet of HTML. The patch updater
-uses this to reset individual lines, the refresh updater builds an
-HTML chunk for the whole visible document at once, and then uses a
-single innerHTML update to do the refresh.
-
-
Parsers can be Simple
-
-
When I wrote CodeMirror 1, I
-thought interruptable
-parsers were a hugely scary and complicated thing, and I used a
-bunch of heavyweight abstractions to keep this supposed complexity
-under control: parsers
-were iterators
-that consumed input from another iterator, and used funny
-closure-resetting tricks to copy and resume themselves.
-
-
This made for a rather nice system, in that parsers formed strictly
-separate modules, and could be composed in predictable ways.
-Unfortunately, it was quite slow (stacking three or four iterators on
-top of each other), and extremely intimidating to people not used to a
-functional programming style.
-
-
With a few small changes, however, we can keep all those
-advantages, but simplify the API and make the whole thing less
-indirect and inefficient. CodeMirror
-2's mode API uses explicit state
-objects, and makes the parser/tokenizer a function that simply takes a
-state and a character stream abstraction, advances the stream one
-token, and returns the way the token should be styled. This state may
-be copied, optionally in a mode-defined way, in order to be able to
-continue a parse at a given point. Even someone who's never touched a
-lambda in his life can understand this approach. Additionally, far
-fewer objects are allocated in the course of parsing now.
-
-
The biggest speedup comes from the fact that the parsing no longer
-has to touch the DOM though. In CodeMirror 1, on an older browser, you
-could see the parser work its way through the document,
-managing some twenty lines in each 50-millisecond time slice it got. It
-was reading its input from the DOM, and updating the DOM as it went
-along, which any experienced JavaScript programmer will immediately
-spot as a recipe for slowness. In CodeMirror 2, the parser usually
-finishes the whole document in a single 100-millisecond time slice—it
-manages some 1500 lines during that time on Chrome. All it has to do
-is munge strings, so there is no real reason for it to be slow
-anymore.
-
-
What Gives?
-
-
Given all this, what can you expect from CodeMirror 2?
-
-
-
-Small. the base library is
-some 45k when minified
-now, 17k when gzipped. It's smaller than
-its own logo.
-
-Lightweight. CodeMirror 2 initializes very
-quickly, and does almost no work when it is not focused. This means
-you can treat it almost like a textarea, have multiple instances on a
-page without trouble.
-
-Huge document support. Since highlighting is
-really fast, and no DOM structure is being built for non-visible
-content, you don't have to worry about locking up your browser when a
-user enters a megabyte-sized document.
-
-Extended API. Some things kept coming up in the
-mailing list, such as marking pieces of text or lines, which were
-extremely hard to do with CodeMirror 1. The new version has proper
-support for these built in.
-
-Tab support. Tabs inside editable documents were,
-for some reason, a no-go. At least six different people announced they
-were going to add tab support to CodeMirror 1, none survived (I mean,
-none delivered a working version). CodeMirror 2 no longer removes tabs
-from your document.
-
-Sane styling. iframe nodes aren't
-really known for respecting document flow. Now that an editor instance
-is a plain div element, it is much easier to size it to
-fit the surrounding elements. You don't even have to make it scroll if
-you do not want to .
-
-
-
-
On the downside, a CodeMirror 2 instance is not a native
-editable component. Though it does its best to emulate such a
-component as much as possible, there is functionality that browsers
-just do not allow us to hook into. Doing select-all from the context
-menu, for example, is not currently detected by CodeMirror.
-
-
[Updates from November 13th 2011] Recently, I've made
-some changes to the codebase that cause some of the text above to no
-longer be current. I've left the text intact, but added markers at the
-passages that are now inaccurate. The new situation is described
-below.
-
-
Content Representation
-
-
The original implementation of CodeMirror 2 represented the
-document as a flat array of line objects. This worked well—splicing
-arrays will require the part of the array after the splice to be
-moved, but this is basically just a simple memmove of a
-bunch of pointers, so it is cheap even for huge documents.
-
-
However, I recently added line wrapping and code folding (line
-collapsing, basically). Once lines start taking up a non-constant
-amount of vertical space, looking up a line by vertical position
-(which is needed when someone clicks the document, and to determine
-the visible part of the document during scrolling) can only be done
-with a linear scan through the whole array, summing up line heights as
-you go. Seeing how I've been going out of my way to make big documents
-fast, this is not acceptable.
-
-
The new representation is based on a B-tree. The leaves of the tree
-contain arrays of line objects, with a fixed minimum and maximum size,
-and the non-leaf nodes simply hold arrays of child nodes. Each node
-stores both the amount of lines that live below them and the vertical
-space taken up by these lines. This allows the tree to be indexed both
-by line number and by vertical position, and all access has
-logarithmic complexity in relation to the document size.
-
-
I gave line objects and tree nodes parent pointers, to the node
-above them. When a line has to update its height, it can simply walk
-these pointers to the top of the tree, adding or subtracting the
-difference in height from each node it encounters. The parent pointers
-also make it cheaper (in complexity terms, the difference is probably
-tiny in normal-sized documents) to find the current line number when
-given a line object. In the old approach, the whole document array had
-to be searched. Now, we can just walk up the tree and count the sizes
-of the nodes coming before us at each level.
-
-
I chose B-trees, not regular binary trees, mostly because they
-allow for very fast bulk insertions and deletions. When there is a big
-change to a document, it typically involves adding, deleting, or
-replacing a chunk of subsequent lines. In a regular balanced tree, all
-these inserts or deletes would have to be done separately, which could
-be really expensive. In a B-tree, to insert a chunk, you just walk
-down the tree once to find where it should go, insert them all in one
-shot, and then break up the node if needed. This breaking up might
-involve breaking up nodes further up, but only requires a single pass
-back up the tree. For deletion, I'm somewhat lax in keeping things
-balanced—I just collapse nodes into a leaf when their child count goes
-below a given number. This means that there are some weird editing
-patterns that may result in a seriously unbalanced tree, but even such
-an unbalanced tree will perform well, unless you spend a day making
-strangely repeating edits to a really big document.
-
-
Keymaps
-
-
Above , I claimed that directly catching key
-events for things like cursor movement is impractical because it
-requires some browser-specific kludges. I then proceeded to explain
-some awful hacks that were needed to make it
-possible for the selection changes to be detected through the
-textarea. In fact, the second hack is about as bad as the first.
-
-
On top of that, in the presence of user-configurable tab sizes and
-collapsed and wrapped lines, lining up cursor movement in the textarea
-with what's visible on the screen becomes a nightmare. Thus, I've
-decided to move to a model where the textarea's selection is no longer
-depended on.
-
-
So I moved to a model where all cursor movement is handled by my
-own code. This adds support for a goal column, proper interaction of
-cursor movement with collapsed lines, and makes it possible for
-vertical movement to move through wrapped lines properly, instead of
-just treating them like non-wrapped lines.
-
-
The key event handlers now translate the key event into a string,
-something like Ctrl-Home or Shift-Cmd-R, and
-use that string to look up an action to perform. To make keybinding
-customizable, this lookup goes through
-a table , using a scheme that
-allows such tables to be chained together (for example, the default
-Mac bindings fall through to a table named 'emacsy', which defines
-basic Emacs-style bindings like Ctrl-F, and which is also
-used by the custom Emacs bindings).
-
-
A new
-option extraKeys
-allows ad-hoc keybindings to be defined in a much nicer way than what
-was possible with the
-old onKeyEvent
-callback. You simply provide an object mapping key identifiers to
-functions, instead of painstakingly looking at raw key events.
-
-
Built-in commands map to strings, rather than functions, for
-example "goLineUp" is the default action bound to the up
-arrow key. This allows new keymaps to refer to them without
-duplicating any code. New commands can be defined by assigning to
-the CodeMirror.commands object, which maps such commands
-to functions.
-
-
The hidden textarea now only holds the current selection, with no
-extra characters around it. This has a nice advantage: polling for
-input becomes much, much faster. If there's a big selection, this text
-does not have to be read from the textarea every time—when we poll,
-just noticing that something is still selected is enough to tell us
-that no new text was typed.
-
-
The reason that cheap polling is important is that many browsers do
-not fire useful events on IME (input method engine) input, which is
-the thing where people inputting a language like Japanese or Chinese
-use multiple keystrokes to create a character or sequence of
-characters. Most modern browsers fire input when the
-composing is finished, but many don't fire anything when the character
-is updated during composition. So we poll, whenever the
-editor is focused, to provide immediate updates of the display.
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/manual.html b/gulliver/js/codemirror/doc/manual.html
deleted file mode 100644
index f1a157cf1..000000000
--- a/gulliver/js/codemirror/doc/manual.html
+++ /dev/null
@@ -1,1841 +0,0 @@
-
-
-
-
- CodeMirror: User Manual
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/* User manual and
- reference guide */
-
-
-
-
-
-
Overview
-
-
CodeMirror is a code-editor component that can be embedded in
- Web pages. The core library provides only the editor
- component, no accompanying buttons, auto-completion, or other IDE
- functionality. It does provide a rich API on top of which such
- functionality can be straightforwardly implemented. See
- the add-ons included in the distribution,
- and
- the CodeMirror
- UI project, for reusable implementations of extra features.
-
-
CodeMirror works with language-specific modes. Modes are
- JavaScript programs that help color (and optionally indent) text
- written in a given language. The distribution comes with a number
- of modes (see the mode/
- directory), and it isn't hard to write new
- ones for other languages.
-
-
Basic Usage
-
-
The easiest way to use CodeMirror is to simply load the script
- and style sheet found under lib/ in the distribution,
- plus a mode script from one of the mode/ directories.
- (See the compression helper for an
- easy way to combine scripts.) For example:
-
-
<script src="lib/codemirror.js"></script>
-<link rel="stylesheet" href="../lib/codemirror.css">
-<script src="mode/javascript/javascript.js"></script>
-
-
Having done this, an editor instance can be created like
- this:
-
-
var myCodeMirror = CodeMirror(document.body);
-
-
The editor will be appended to the document body, will start
- empty, and will use the mode that we loaded. To have more control
- over the new editor, a configuration object can be passed
- to CodeMirror as a second argument:
-
-
var myCodeMirror = CodeMirror(document.body, {
- value: "function myScript(){return 100;}\n",
- mode: "javascript"
-});
-
-
This will initialize the editor with a piece of code already in
- it, and explicitly tell it to use the JavaScript mode (which is
- useful when multiple modes are loaded).
- See below for a full discussion of the
- configuration options that CodeMirror accepts.
-
-
In cases where you don't want to append the editor to an
- element, and need more control over the way it is inserted, the
- first argument to the CodeMirror function can also
- be a function that, when given a DOM element, inserts it into the
- document somewhere. This could be used to, for example, replace a
- textarea with a real editor:
-
-
var myCodeMirror = CodeMirror(function(elt) {
- myTextArea.parentNode.replaceChild(elt, myTextArea);
-}, {value: myTextArea.value});
-
-
However, for this use case, which is a common way to use
- CodeMirror, the library provides a much more powerful
- shortcut:
-
-
var myCodeMirror = CodeMirror.fromTextArea(myTextArea);
-
-
This will, among other things, ensure that the textarea's value
- is updated with the editor's contents when the form (if it is part
- of a form) is submitted. See the API
- reference for a full description of this method.
-
-
Configuration
-
-
Both the CodeMirror function and
- its fromTextArea method take as second (optional)
- argument an object containing configuration options. Any option
- not supplied like this will be taken
- from CodeMirror.defaults, an object containing the
- default options. You can update this object to change the defaults
- on your page.
-
-
Options are not checked in any way, so setting bogus option
- values is bound to lead to odd errors.
-
-
These are the supported options:
-
-
- value (string or Doc)
- The starting value of the editor. Can be a string, or
- a document object .
-
- mode (string or object)
- The mode to use. When not given, this will default to the
- first mode that was loaded. It may be a string, which either
- simply names the mode or is
- a MIME type
- associated with the mode. Alternatively, it may be an object
- containing configuration options for the mode, with
- a name property that names the mode (for
- example {name: "javascript", json: true}). The demo
- pages for each mode contain information about what configuration
- parameters the mode supports. You can ask CodeMirror which modes
- and MIME types have been defined by inspecting
- the CodeMirror.modes
- and CodeMirror.mimeModes objects. The first maps
- mode names to their constructors, and the second maps MIME types
- to mode specs.
-
- theme (string)
- The theme to style the editor with. You must make sure the
- CSS file defining the corresponding .cm-s-[name]
- styles is loaded (see
- the theme directory in the
- distribution). The default is "default", for which
- colors are included in codemirror.css. It is
- possible to use multiple theming classes at once—for
- example "foo bar" will assign both
- the cm-s-foo and the cm-s-bar classes
- to the editor.
-
- indentUnit (integer)
- How many spaces a block (whatever that means in the edited
- language) should be indented. The default is 2.
-
- smartIndent (boolean)
- Whether to use the context-sensitive indentation that the
- mode provides (or just indent the same as the line before).
- Defaults to true.
-
- tabSize (integer)
- The width of a tab character. Defaults to 4.
-
- indentWithTabs (boolean)
- Whether, when indenting, the first N*tabSize
- spaces should be replaced by N tabs. Default is false.
-
- electricChars (boolean)
- Configures whether the editor should re-indent the current
- line when a character is typed that might change its proper
- indentation (only works if the mode supports indentation).
- Default is true.
-
- rtlMoveVisually (boolean)
- Determines whether horizontal cursor movement through
- right-to-left (Arabic, Hebrew) text is visual (pressing the left
- arrow moves the cursor left) or logical (pressing the left arrow
- moves to the next lower index in the string, which is visually
- right in right-to-left text). The default is false
- on Windows, and true on other platforms.
-
- keyMap (string)
- Configures the keymap to use. The default
- is "default", which is the only keymap defined
- in codemirror.js itself. Extra keymaps are found in
- the keymap directory. See
- the section on keymaps for more
- information.
-
-
- Can be used to specify extra keybindings for the editor,
- alongside the ones defined
- by keyMap . Should be
- either null, or a valid keymap value.
-
- lineWrapping (boolean)
- Whether CodeMirror should scroll or wrap for long lines.
- Defaults to false (scroll).
-
- lineNumbers (boolean)
- Whether to show line numbers to the left of the editor.
-
- firstLineNumber (integer)
- At which number to start counting lines. Default is 1.
-
- lineNumberFormatter (function)
- A function used to format line numbers. The function is
- passed the line number, and should return a string that will be
- shown in the gutter.
-
- gutters (array)
- Can be used to add extra gutters (beyond or instead of the
- line number gutter). Should be an array of CSS class names, each
- of which defines a width (and optionally a
- background), and which will be used to draw the background of
- the gutters. May include
- the CodeMirror-linenumbers class, in order to
- explicitly set the position of the line number gutter (it will
- default to be to the right of all other gutters). These class
- names are the keys passed
- to setGutterMarker .
-
- fixedGutter (boolean)
- Determines whether the gutter scrolls along with the content
- horizontally (false) or whether it stays fixed during horizontal
- scrolling (true, the default).
-
- readOnly (boolean)
- This disables editing of the editor content by the user. If
- the special value "nocursor" is given (instead of
- simply true), focusing of the editor is also
- disallowed.
-
- showCursorWhenSelecting (boolean)
- Whether the cursor should be drawn when a selection is
- active. Defaults to false.
-
- undoDepth (integer)
- The maximum number of undo levels that the editor stores.
- Defaults to 40.
-
- tabindex (integer)
- The tab
- index to assign to the editor. If not given, no tab index
- will be assigned.
-
- autofocus (boolean)
- Can be used to make CodeMirror focus itself on
- initialization. Defaults to off.
- When fromTextArea is
- used, and no explicit value is given for this option, it will be
- set to true when either the source textarea is focused, or it
- has an autofocus attribute and no other element is
- focused.
-
-
-
Below this a few more specialized, low-level options are
- listed. These are only useful in very specific situations, you
- might want to skip them the first time you read this manual.
-
-
- dragDrop (boolean)
- Controls whether drag-and-drop is enabled. On by default.
-
- onDragEvent (function)
- When given, this will be called when the editor is handling
- a dragenter, dragover,
- or drop event. It will be passed the editor instance
- and the event object as arguments. The callback can choose to
- handle the event itself, in which case it should
- return true to indicate that CodeMirror should not
- do anything further.
-
- onKeyEvent (function)
- This provides a rather low-level hook into CodeMirror's key
- handling. If provided, this function will be called on
- every keydown, keyup,
- and keypress event that CodeMirror captures. It
- will be passed two arguments, the editor instance and the key
- event. This key event is pretty much the raw key event, except
- that a stop() method is always added to it. You
- could feed it to, for example, jQuery.Event to
- further normalize it. This function can inspect the key
- event, and handle it if it wants to. It may return true to tell
- CodeMirror to ignore the event. Be wary that, on some browsers,
- stopping a keydown does not stop
- the keypress from firing, whereas on others it
- does. If you respond to an event, you should probably inspect
- its type property and only do something when it
- is keydown (or keypress for actions
- that need character data).
-
- cursorBlinkRate (number)
- Half-period in milliseconds used for cursor blinking. The default blink
- rate is 530ms.
-
- cursorHeight (number)
- Determines the height of the cursor. Default is 1, meaning
- it spans the whole height of the line. For some fonts (and by
- some tastes) a smaller height (for example 0.85),
- which causes the cursor to not reach all the way to the bottom
- of the line, looks better
-
- workTime, workDelay (number)
- Highlighting is done by a pseudo background-thread that will
- work for workTime milliseconds, and then use
- timeout to sleep for workDelay milliseconds. The
- defaults are 200 and 300, you can change these options to make
- the highlighting more or less aggressive.
-
- pollInterval (number)
- Indicates how quickly CodeMirror should poll its input
- textarea for changes (when focused). Most input is captured by
- events, but some things, like IME input on some browsers, don't
- generate events that allow CodeMirror to properly detect it.
- Thus, it polls. Default is 100 milliseconds.
-
- flattenSpans (boolean)
- By default, CodeMirror will combine adjacent tokens into a
- single span if they have the same class. This will result in a
- simpler DOM tree, and thus perform better. With some kinds of
- styling (such as rounded corners), this will change the way the
- document looks. You can set this option to false to disable this
- behavior.
-
- viewportMargin (integer)
- Specifies the amount of lines that are rendered above and
- below the part of the document that's currently scrolled into
- view. This affects the amount of updates needed when scrolling,
- and the amount of work that such an update does. You should
- usually leave it at its default, 10. Can be set
- to Infinity to make sure the whole document is
- always rendered, and thus the browser's text search works on it.
- This will have bad effects on performance of big
- documents.
-
-
-
Events
-
-
A CodeMirror instance emits a number of events, which allow
- client code to react to various situations. These are registered
- with the on method (and
- removed with the off
- method). These are the events that fire on the instance object.
- The name of the event is followed by the arguments that will be
- passed to the handler. The instance argument always
- refers to the editor instance.
-
-
- "change" (instance, changeObj)
- Fires every time the content of the editor is changed.
- The changeObj is a {from, to, text, removed,
- next} object containing information about the changes
- that occurred as second argument. from
- and to are the positions (in the pre-change
- coordinate system) where the change started and ended (for
- example, it might be {ch:0, line:18} if the
- position is at the beginning of line #19). text is
- an array of strings representing the text that replaced the
- changed range (split by line). removed is the text
- that used to be between from and to,
- which is overwritten by this change. If multiple changes
- happened during a single operation, the object will have
- a next property pointing to another change object
- (which may point to another, etc).
-
- "beforeChange" (instance, change)
- This event is fired before a change is applied, and its
- handler may choose to modify or cancel the change.
- The change object
- has from, to, and text
- properties, as with
- the "change" event, but
- never a next property, since this is fired for each
- individual change, and not batched per operation. It also
- has update(from, to, text)
- and cancel() methods, which may be used to modify
- or cancel the change. All three arguments to update
- are optional, and can be left off to leave the existing value
- for that field intact. Note: you may not do
- anything from a "beforeChange" handler that would
- cause changes to the document or its visualization. Doing so
- will, since this handler is called directly from the bowels of
- the CodeMirror implementation, probably cause the editor to
- become corrupted.
-
- "cursorActivity" (instance)
- Will be fired when the cursor or selection moves, or any
- change is made to the editor content.
-
- "beforeSelectionChange" (instance, selection)
- This event is fired before the selection is moved. Its
- handler may modify the resulting selection head and anchor.
- The selection parameter is an object
- with head and anchor properties
- holding {line, ch} objects, which the handler can
- read and update. Handlers for this event have the same
- restriction
- as "beforeChange"
- handlers — they should not do anything to directly update the
- state of the editor.
-
- "viewportChange" (instance, from, to)
- Fires whenever the view port of
- the editor changes (due to scrolling, editing, or any other
- factor). The from and to arguments
- give the new start and end of the viewport.
-
- "gutterClick" (instance, line, gutter, clickEvent)
- Fires when the editor gutter (the line-number area) is
- clicked. Will pass the editor instance as first argument, the
- (zero-based) number of the line that was clicked as second
- argument, the CSS class of the gutter that was clicked as third
- argument, and the raw mousedown event object as
- fourth argument.
-
- "focus", "blur" (instance)
- These fire whenever the editor is focused or unfocused.
-
- "scroll" (instance)
- Fires when the editor is scrolled.
-
- "update" (instance)
- Will be fired whenever CodeMirror updates its DOM display.
-
- "renderLine" (instance, line, element)
- Fired whenever a line is (re-)rendered to the DOM. Fired
- right after the DOM element is built, before it is
- added to the document. The handler may mess with the style of
- the resulting element, or add event handlers, but
- should not try to change the state of the editor.
-
-
-
It is also possible to register events on
- other objects. Use CodeMirror.on(handle, "eventName",
- func) to register handlers on objects that don't have their
- own on method. Document objects (instances
- of CodeMirror.Doc ) emit the
- following events:
-
-
- "change" (doc, changeObj)
- Fired whenever a change occurs to the
- document. changeObj has a similar type as the
- object passed to the
- editor's "change"
- event, but it never has a next property, because
- document change events are not batched (whereas editor change
- events are).
-
- "beforeChange" (doc, change)
- See the description of the
- same event on editor instances.
-
- "cursorActivity" (doc)
- Fired whenever the cursor or selection in this document
- changes.
-
- "beforeSelectionChange" (doc, selection)
- Equivalent to
- the event by the same
- name as fired on editor instances.
-
-
-
Line handles (as returned by, for
- example, getLineHandle )
- support these events:
-
-
- "delete" ()
- Will be fired when the line object is deleted. A line object
- is associated with the start of the line. Mostly useful
- when you need to find out when your gutter
- markers on a given line are removed.
- "change" (line, changeObj)
- Fires when the line's text content is changed in any way
- (but the line is not deleted outright). The change
- object is similar to the one passed
- to change event on the editor
- object.
-
-
-
Marked range handles, as returned
- by markText
- and setBookmark , emit the
- following events:
-
-
- "beforeCursorEnter" ()
- Fired when the cursor enters the marked range. From this
- event handler, the editor state may be inspected
- but not modified, with the exception that the range on
- which the event fires may be cleared.
- "clear" ()
- Fired when the range is cleared, either through cursor
- movement in combination
- with clearOnEnter
- or through a call to its clear() method. Will only
- be fired once per handle. Note that deleting the range through
- text editing does not fire this event, because an undo
- action might bring the range back into existence.
- "hide" ()
- Fired when the last part of the marker is removed from the
- document by editing operations.
- "unhide" ()
- Fired when, after the marker was removed by editing, a undo
- operation brought the marker back.
-
-
-
Line widgets, returned
- by addLineWidget , fire
- these events:
-
-
- "redraw" ()
- Fired whenever the editor re-adds the widget to the DOM.
- This will happen once right after the widget is added (if it is
- scrolled into view), and then again whenever it is scrolled out
- of view and back in again, or when changes to the editor options
- or the line the widget is on require the widget to be
- redrawn.
-
-
-
Keymaps
-
-
Keymaps are ways to associate keys with functionality. A keymap
- is an object mapping strings that identify the keys to functions
- that implement their functionality.
-
-
Keys are identified either by name or by character.
- The CodeMirror.keyNames object defines names for
- common keys and associates them with their key codes. Examples of
- names defined here are Enter, F5,
- and Q. These can be prefixed
- with Shift-, Cmd-, Ctrl-,
- and Alt- (in that order!) to specify a modifier. So
- for example, Shift-Ctrl-Space would be a valid key
- identifier.
-
-
Common example: map the Tab key to insert spaces instead of a tab
- character.
-
-
-{
- Tab: function(cm) {
- var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
- cm.replaceSelection(spaces, "end", "+input");
- }
-}
-
-
Alternatively, a character can be specified directly by
- surrounding it in single quotes, for example '$'
- or 'q'. Due to limitations in the way browsers fire
- key events, these may not be prefixed with modifiers.
-
-
The CodeMirror.keyMap object associates keymaps
- with names. User code and keymap definitions can assign extra
- properties to this object. Anywhere where a keymap is expected, a
- string can be given, which will be looked up in this object. It
- also contains the "default" keymap holding the
- default bindings.
-
-
The values of properties in keymaps can be either functions of
- a single argument (the CodeMirror instance), strings, or
- false. Such strings refer to properties of the
- CodeMirror.commands object, which defines a number of
- common commands that are used by the default keybindings, and maps
- them to functions. If the property is set to false,
- CodeMirror leaves handling of the key up to the browser. A key
- handler function may return CodeMirror.Pass to indicate
- that it has decided not to handle the key, and other handlers (or
- the default behavior) should be given a turn.
-
-
Keys mapped to command names that start with the
- characters "go" (which should be used for
- cursor-movement actions) will be fired even when an
- extra Shift modifier is present (i.e. "Up":
- "goLineUp" matches both up and shift-up). This is used to
- easily implement shift-selection.
-
-
Keymaps can defer to each other by defining
- a fallthrough property. This indicates that when a
- key is not found in the map itself, one or more other maps should
- be searched. It can hold either a single keymap or an array of
- keymaps.
-
-
When a keymap contains a nofallthrough property
- set to true, keys matched against that map will be
- ignored if they don't match any of the bindings in the map (no
- further child maps will be tried, and the default effect of
- inserting a character will not occur).
-
-
Customized Styling
-
-
Up to a certain extent, CodeMirror's look can be changed by
- modifying style sheet files. The style sheets supplied by modes
- simply provide the colors for that mode, and can be adapted in a
- very straightforward way. To style the editor itself, it is
- possible to alter or override the styles defined
- in codemirror.css .
-
-
Some care must be taken there, since a lot of the rules in this
- file are necessary to have CodeMirror function properly. Adjusting
- colors should be safe, of course, and with some care a lot of
- other things can be changed as well. The CSS classes defined in
- this file serve the following roles:
-
-
- CodeMirror
- The outer element of the editor. This should be used for the
- editor width, height, borders and positioning. Can also be used
- to set styles that should hold for everything inside the editor
- (such as font and font size), or to set a background.
-
- CodeMirror-scroll
- Whether the editor scrolls (overflow: auto +
- fixed height). By default, it does. Setting
- the CodeMirror class to have height:
- auto and giving this class overflow-x: auto;
- overflow-y: hidden; will cause the editor
- to resize to fit its
- content .
-
- CodeMirror-focused
- Whenever the editor is focused, the top element gets this
- class. This is used to hide the cursor and give the selection a
- different color when the editor is not focused.
-
- CodeMirror-gutters
- This is the backdrop for all gutters. Use it to set the
- default gutter background color, and optionally add a border on
- the right of the gutters.
-
- CodeMirror-linenumbers
- Use this for giving a background or width to the line number
- gutter.
-
- CodeMirror-linenumber
- Used to style the actual individual line numbers. These
- won't be children of the CodeMirror-linenumbers
- (plural) element, but rather will be absolutely positioned to
- overlay it. Use this to set alignment and text properties for
- the line numbers.
-
- CodeMirror-lines
- The visible lines. This is where you specify vertical
- padding for the editor content.
-
- CodeMirror-cursor
- The cursor is a block element that is absolutely positioned.
- You can make it look whichever way you want.
-
- CodeMirror-selected
- The selection is represented by span elements
- with this class.
-
- CodeMirror-matchingbracket,
- CodeMirror-nonmatchingbracket
- These are used to style matched (or unmatched) brackets.
-
-
-
If your page's style sheets do funky things to
- all div or pre elements (you probably
- shouldn't do that), you'll have to define rules to cancel these
- effects out again for elements under the CodeMirror
- class.
-
-
Themes are also simply CSS files, which define colors for
- various syntactic elements. See the files in
- the theme directory.
-
-
Programming API
-
-
A lot of CodeMirror features are only available through its
- API. Thus, you need to write code (or
- use add-ons ) if you want to expose them to
- your users.
-
-
Whenever points in the document are represented, the API uses
- objects with line and ch properties.
- Both are zero-based. CodeMirror makes sure to 'clip' any positions
- passed by client code so that they fit inside the document, so you
- shouldn't worry too much about sanitizing your coordinates. If you
- give ch a value of null, or don't
- specify it, it will be replaced with the length of the specified
- line.
-
-
Methods prefixed with doc. can, unless otherwise
- specified, be called both on CodeMirror (editor)
- instances and CodeMirror.Doc instances. Methods
- prefixed with cm. are only available
- on CodeMirror instances.
-
-
Content manipulation methods
-
-
- doc.getValue() → string
- Get the current editor content. You can pass it an optional
- argument to specify the string to be used to separate lines
- (defaults to "\n").
- doc.setValue(string)
- Set the editor content.
-
- doc.getRange(from, to) → string
- Get the text between the given points in the editor, which
- should be {line, ch} objects. An optional third
- argument can be given to indicate the line separator string to
- use (defaults to "\n").
- doc.replaceRange(string, from, to)
- Replace the part of the document between from
- and to with the given string. from
- and to must be {line, ch}
- objects. to can be left off to simply insert the
- string at position from.
-
- doc.getLine(n) → string
- Get the content of line n.
- doc.setLine(n, text)
- Set the content of line n.
- doc.removeLine(n)
- Remove the given line from the document.
-
- doc.lineCount() → number
- Get the number of lines in the editor.
- doc.firstLine() → number
- doc.lastLine() → number
- Get the first and last lines of the editor. This will
- usually be zero and doc.lineCount() - 1 respectively,
- but for linked sub-views ,
- or documents instantiated with a non-zero
- first line, it might return other values.
-
- doc.getLineHandle(num) → lineHandle
- Fetches the line handle for the given line number.
- doc.getLineNumber(handle) → integer
- Given a line handle, returns the current position of that
- line (or null when it is no longer in the
- document).
- doc.eachLine(f) | doc.eachLine(start, end, f)
- Iterate over the whole document, or if start
- and end line numbers are given, the range
- from start up to (not including) end,
- and call f for each line, passing the line handle.
- This is a faster way to visit a range of line handlers than
- calling getLineHandle
- for each of them. Note that line handles have
- a text property containing the line's content (as a
- string).
-
- doc.markClean()
- Set the editor content as 'clean', a flag that it will
- retain until it is edited, and which will be set again when such
- an edit is undone again. Useful to track whether the content
- needs to be saved.
- doc.isClean() → boolean
- Returns whether the document is currently clean (not
- modified since initialization or the last call
- to markClean ).
-
-
-
Cursor and selection methods
-
-
- doc.getSelection() → string
- Get the currently selected code.
- doc.replaceSelection(string)
- Replace the selection with the given string.
-
- doc.getCursor(start) → object
- start is a an optional string indicating which
- end of the selection to return. It may
- be "start", "end", "head"
- (the side of the selection that moves when you press
- shift+arrow), or "anchor" (the fixed side of the
- selection). Omitting the argument is the same as
- passing "head". A {line, ch} object
- will be returned.
- doc.somethingSelected() → boolean
- Return true if any text is selected.
- doc.setCursor(pos)
- Set the cursor position. You can either pass a
- single {line, ch} object, or the line and the
- character as two separate parameters.
- doc.setSelection(anchor, head)
- Set the selection range. anchor
- and head should be {line, ch}
- objects. head defaults to anchor when
- not given.
- doc.extendSelection(pos, pos2)
- Similar
- to setSelection , but
- will, if shift is held or
- the extending flag is set, move the
- head of the selection while leaving the anchor at its current
- place. pos2 is optional, and can be passed to
- ensure a region (for example a word or paragraph) will end up
- selected (in addition to whatever lies between that region and
- the current anchor).
- doc.setExtending(bool)
- Sets or clears the 'extending' flag, which acts similar to
- the shift key, in that it will cause cursor movement and calls
- to extendSelection
- to leave the selection anchor in place.
-
- cm.hasFocus() → bool
- Tells you whether the editor currently has focus.
-
- cm.findPosH(start, amount, unit, visually) → object
- Used to find the target position for horizontal cursor
- motion. start is a {line, ch}
- object, amount an integer (may be negative),
- and unit one of the
- string "char", "column",
- or "word". Will return a position that is produced
- by moving amount times the distance specified
- by unit. When visually is true, motion
- in right-to-left text will be visual rather than logical. When
- the motion was clipped by hitting the end or start of the
- document, the returned value will have a hitSide
- property set to true.
- cm.findPosV(start, amount, unit) → object
- Similar to findPosH ,
- but used for vertical motion. unit may
- be "line" or "page". The other
- arguments and the returned value have the same interpretation as
- they have in findPosH.
-
-
-
Configuration methods
-
-
- cm.setOption(option, value)
- Change the configuration of the editor. option
- should the name of an option ,
- and value should be a valid value for that
- option.
- cm.getOption(option) → value
- Retrieves the current value of the given option for this
- editor instance.
-
- cm.addKeyMap(map, bottom)
- Attach an additional keymap to the
- editor. This is mostly useful for add-ons that need to register
- some key handlers without trampling on
- the extraKeys
- option. Maps added in this way have a higher precedence than
- the extraKeys
- and keyMap options,
- and between them, the maps added earlier have a lower precedence
- than those added later, unless the bottom argument
- was passed, in which case they end up below other keymaps added
- with this method.
- cm.removeKeyMap(map)
- Disable a keymap added
- with addKeyMap . Either
- pass in the keymap object itself, or a string, which will be
- compared against the name property of the active
- keymaps.
-
- cm.addOverlay(mode, options)
- Enable a highlighting overlay. This is a stateless mini-mode
- that can be used to add extra highlighting. For example,
- the search add-on uses it to
- highlight the term that's currently being
- searched. mode can be a mode
- spec or a mode object (an object with
- a token method).
- The options parameter is optional. If given, it
- should be an object. Currently, only the opaque
- option is recognized. This defaults to off, but can be given to
- allow the overlay styling, when not null, to
- override the styling of the base mode entirely, instead of the
- two being applied together.
- cm.removeOverlay(mode)
- Pass this the exact argument passed for
- the mode parameter
- to addOverlay to remove
- an overlay again.
-
- cm.on(type, func)
- Register an event handler for the given event type (a
- string) on the editor instance. There is also
- a CodeMirror.on(object, type, func) version
- that allows registering of events on any object.
- cm.off(type, func)
- Remove an event handler on the editor instance. An
- equivalent CodeMirror.off(object, type,
- func) also exists.
-
-
-
Document management methods
-
-
Each editor is associated with an instance
- of CodeMirror.Doc, its document. A document
- represents the editor content, plus a selection, an undo history,
- and a mode . A document can only be
- associated with a single editor at a time. You can create new
- documents by calling the CodeMirror.Doc(text, mode,
- firstLineNumber) constructor. The last two arguments are
- optional and can be used to set a mode for the document and make
- it start at a line number other than 0, respectively.
-
-
- cm.getDoc() → doc
- Retrieve the currently active document from an editor.
- doc.getEditor() → editor
- Retrieve the editor associated with a document. May
- return null.
-
- cm.swapDoc(doc) → doc
- Attach a new document to the editor. Returns the old
- document, which is now no longer associated with an editor.
-
- doc.copy(copyHistory) → doc
- Create an identical copy of the given doc.
- When copyHistory is true, the history will also be
- copied. Can not be called directly on an editor.
-
- doc.linkedDoc(options) → doc
- Create a new document that's linked to the target document.
- Linked documents will stay in sync (changes to one are also
- applied to the other) until unlinked .
- These are the options that are supported:
-
- sharedHist (boolean)
- When turned on, the linked copy will share an undo
- history with the original. Thus, something done in one of
- the two can be undone in the other, and vice versa.
- from, to (integer)
- Can be given to make the new document a subview of the
- original. Subviews only show a given range of lines. Note
- that line coordinates inside the subview will be consistent
- with those of the parent, so that for example a subview
- starting at line 10 will refer to its first line as line 10,
- not 0.
- mode (mode spec)
- By default, the new document inherits the mode of the
- parent. This option can be set to
- a mode spec to give it a
- different mode.
-
- doc.unlinkDoc(doc)
- Break the link between two documents. After calling this,
- changes will no longer propagate between the documents, and, if
- they had a shared history, the history will become
- separate.
- doc.iterLinkedDocs(function)
- Will call the given function for all documents linked to the
- target document. It will be passed two arguments, the linked document
- and a boolean indicating whether that document shares history
- with the target.
-
-
-
History-related methods
-
-
- doc.undo()
- Undo one edit (if any undo events are stored).
- doc.redo()
- Redo one undone edit.
-
- doc.historySize() → object
- Returns an object with {undo, redo} properties,
- both of which hold integers, indicating the amount of stored
- undo and redo operations.
- doc.clearHistory()
- Clears the editor's undo history.
- doc.getHistory() → object
- Get a (JSON-serializeable) representation of the undo history.
- doc.setHistory(object)
- Replace the editor's undo history with the one provided,
- which must be a value as returned
- by getHistory . Note that
- this will have entirely undefined results if the editor content
- isn't also the same as it was when getHistory was
- called.
-
-
-
Text-marking methods
-
-
- doc.markText(from, to, options) → object
- Can be used to mark a range of text with a specific CSS
- class name. from and to should
- be {line, ch} objects. The options
- parameter is optional. When given, it should be an object that
- may contain the following configuration options:
-
- className (string)
- Assigns a CSS class to the marked stretch of text.
- inclusiveLeft (boolean)Determines whether
- text inserted on the left of the marker will end up inside
- or outside of it.
- inclusiveRight (boolean)Like inclusiveLeft,
- but for the right side.
- atomic (boolean)
- Atomic ranges act as a single unit when cursor movement is
- concerned—i.e. it is impossible to place the cursor inside of
- them. In atomic ranges, inclusiveLeft
- and inclusiveRight have a different meaning—they
- will prevent the cursor from being placed respectively
- directly before and directly after the range.
- collapsed (boolean)
- Collapsed ranges do not show up in the display. Setting a
- range to be collapsed will automatically make it atomic.
- clearOnEnter (boolean)
- When enabled, will cause the mark to clear itself whenever
- the cursor enters its range. This is mostly useful for
- text-replacement widgets that need to 'snap open' when the
- user tries to edit them. A
- the "clear" event
- fired on the range handle can be used to be notified when this
- happens.
- replacedWith (dom node)
- Use a given node to display this range. Implies both
- collapsed and atomic. The given DOM node must be an
- inline element (as opposed to a block element).
- readOnly
- A read-only span can, as long as it is not cleared, not be
- modified except by
- calling setValue to reset
- the whole document. Note: adding a read-only span
- currently clears the undo history of the editor, because
- existing undo events being partially nullified by read-only
- spans would corrupt the history (in the current
- implementation).
- startStyleCan be used to specify
- an extra CSS class to be applied to the leftmost span that
- is part of the marker.
- endStyleEquivalent
- to startStyle, but for the rightmost span.
- sharedWhen the
- target document is linked to other
- documents, you can set shared to true to make the
- marker appear in all documents. By default, a marker appears
- only in its target document.
-
- The method will return an object that represents the marker
- (with constuctor CodeMirror.TextMarker), which
- exposes three methods:
- clear(), to remove the mark,
- find(), which returns a {from, to}
- object (both holding document positions), indicating the current
- position of the marked range, or undefined if the
- marker is no longer in the document, and
- finally getOptions(copyWidget), which returns an
- object representing the options for the marker.
- If copyWidget is given an true, it will clone the
- value of
- the replacedWith
- option, if any.
-
- doc.setBookmark(pos, options) → object
- Inserts a bookmark, a handle that follows the text around it
- as it is being edited, at the given position. A bookmark has two
- methods find() and clear(). The first
- returns the current position of the bookmark, if it is still in
- the document, and the second explicitly removes the bookmark.
- The options argument is optional. If given, the following
- properties are recognized:
-
- widgetCan be used to display a DOM
- node at the current location of the bookmark (analogous to
- the replacedWith
- option to markText).
- insertLeftBy default, text typed
- when the cursor is on top of the bookmark will end up to the
- right of the bookmark. Set this option to true to make it go
- to the left instead.
-
-
- doc.findMarksAt(pos) → array
- Returns an array of all the bookmarks and marked ranges
- present at the given position.
- doc.getAllMarks() → array
- Returns an array containing all marked ranges in the document.
-
-
-
Widget, gutter, and decoration methods
-
-
- cm.setGutterMarker(line, gutterID, value) → lineHandle
- Sets the gutter marker for the given gutter (identified by
- its CSS class, see
- the gutters option)
- to the given value. Value can be either null, to
- clear the marker, or a DOM element, to set it. The DOM element
- will be shown in the specified gutter next to the specified
- line.
-
- cm.clearGutter(gutterID)
- Remove all gutter markers in
- the gutter with the given ID.
-
- cm.addLineClass(line, where, class) → lineHandle
- Set a CSS class name for the given line. line
- can be a number or a line handle. where determines
- to which element this class should be applied, can can be one
- of "text" (the text element, which lies in front of
- the selection), "background" (a background element
- that will be behind the selection), or "wrap" (the
- wrapper node that wraps all of the line's elements, including
- gutter elements). class should be the name of the
- class to apply.
-
- cm.removeLineClass(line, where, class) → lineHandle
- Remove a CSS class from a line. line can be a
- line handle or number. where should be one
- of "text", "background",
- or "wrap"
- (see addLineClass ). class
- can be left off to remove all classes for the specified node, or
- be a string to remove only a specific class.
-
- cm.lineInfo(line) → object
- Returns the line number, text content, and marker status of
- the given line, which can be either a number or a line handle.
- The returned object has the structure {line, handle, text,
- gutterMarkers, textClass, bgClass, wrapClass, widgets},
- where gutterMarkers is an object mapping gutter IDs
- to marker elements, and widgets is an array
- of line widgets attached to this
- line, and the various class properties refer to classes added
- with addLineClass .
-
- cm.addWidget(pos, node, scrollIntoView)
- Puts node, which should be an absolutely
- positioned DOM node, into the editor, positioned right below the
- given {line, ch} position.
- When scrollIntoView is true, the editor will ensure
- that the entire node is visible (if possible). To remove the
- widget again, simply use DOM methods (move it somewhere else, or
- call removeChild on its parent).
-
- cm.addLineWidget(line, node, options) → object
- Adds a line widget, an element shown below a line, spanning
- the whole of the editor's width, and moving the lines below it
- downwards. line should be either an integer or a
- line handle, and node should be a DOM node, which
- will be displayed below the given line. options,
- when given, should be an object that configures the behavior of
- the widget. The following options are supported (all default to
- false):
-
- coverGutter (boolean)
- Whether the widget should cover the gutter.
- noHScroll (boolean)
- Whether the widget should stay fixed in the face of
- horizontal scrolling.
- above (boolean)
- Causes the widget to be placed above instead of below
- the text of the line.
- showIfHidden (boolean)
- When true, will cause the widget to be rendered even if
- the line it is associated with is hidden.
-
- Note that the widget node will become a descendant of nodes with
- CodeMirror-specific CSS classes, and those classes might in some
- cases affect it. This method returns an object that represents
- the widget placement. It'll have a line property
- pointing at the line handle that it is associated with, and the following methods:
-
- clear()Removes the widget.
- changed()Call
- this if you made some change to the widget's DOM node that
- might affect its height. It'll force CodeMirror to update
- the height of the line that contains the widget.
-
-
-
- Sizing, scrolling and positioning methods
-
-
- cm.setSize(width, height)
- Programatically set the size of the editor (overriding the
- applicable CSS
- rules ). width and height height
- can be either numbers (interpreted as pixels) or CSS units
- ("100%", for example). You can
- pass null for either of them to indicate that that
- dimension should not be changed.
-
- cm.scrollTo(x, y)
- Scroll the editor to a given (pixel) position. Both
- arguments may be left as null
- or undefined to have no effect.
- cm.getScrollInfo()
- Get an {left, top, width, height, clientWidth,
- clientHeight} object that represents the current scroll
- position, the size of the scrollable area, and the size of the
- visible area (minus scrollbars).
- cm.scrollIntoView(pos, margin)
- Scrolls the given element into view. pos may be
- either a {line, ch} position, referring to a given
- character, null, to refer to the cursor, or
- a {left, top, right, bottom} object, in
- editor-local coordinates. The margin parameter is
- optional. When given, it indicates the amount of pixels around
- the given area that should be made visible as well.
-
- cm.cursorCoords(where, mode) → object
- Returns an {left, top, bottom} object
- containing the coordinates of the cursor position.
- If mode is "local", they will be
- relative to the top-left corner of the editable document. If it
- is "page" or not given, they are relative to the
- top-left corner of the page. where can be a boolean
- indicating whether you want the start (true) or the
- end (false) of the selection, or, if a {line,
- ch} object is given, it specifies the precise position at
- which you want to measure.
- cm.charCoords(pos, mode) → object
- Returns the position and dimensions of an arbitrary
- character. pos should be a {line, ch}
- object. This differs from cursorCoords in that
- it'll give the size of the whole character, rather than just the
- position that the cursor would have when it would sit at that
- position.
- cm.coordsChar(object, mode) → pos
- Given an {left, top} object, returns
- the {line, ch} position that corresponds to it. The
- optional mode parameter determines relative to what
- the coordinates are interpreted. It may
- be "window", "page" (the default),
- or "local".
- cm.defaultTextHeight() → number
- Returns the line height of the default font for the editor.
- cm.defaultCharWidth() → number
- Returns the pixel width of an 'x' in the default font for
- the editor. (Note that for non-monospace fonts, this is mostly
- useless, and even for monospace fonts, non-ascii characters
- might have a different width).
-
- cm.getViewport() → object
- Returns a {from, to} object indicating the
- start (inclusive) and end (exclusive) of the currently rendered
- part of the document. In big documents, when most content is
- scrolled out of view, CodeMirror will only render the visible
- part, and a margin around it. See also
- the viewportChange
- event.
-
- cm.refresh()
- If your code does something to change the size of the editor
- element (window resizes are already listened for), or unhides
- it, you should probably follow up by calling this method to
- ensure CodeMirror is still looking as intended.
-
-
- Mode, state, and token-related methods
-
- When writing language-aware functionality, it can often be
- useful to hook into the knowledge that the CodeMirror language
- mode has. See the section on modes for a
- more detailed description of how these work.
-
-
- doc.getMode() → object
- Gets the mode object for the editor. Note that this is
- distinct from getOption("mode"), which gives you
- the mode specification, rather than the resolved, instantiated
- mode object .
-
- cm.getTokenAt(pos) → object
- Retrieves information about the token the current mode found
- before the given position (a {line, ch} object). The
- returned object has the following properties:
-
- startThe character (on the given line) at which the token starts.
- endThe character at which the token ends.
- stringThe token's string.
- typeThe token type the mode assigned
- to the token, such as "keyword"
- or "comment" (may also be null).
- stateThe mode's state at the end of this token.
-
-
- cm.getStateAfter(line) → state
- Returns the mode's parser state, if any, at the end of the
- given line number. If no line number is given, the state at the
- end of the document is returned. This can be useful for storing
- parsing errors in the state, or getting other kinds of
- contextual information for a line.
-
-
- Miscellaneous methods
-
-
- cm.operation(func) → result
- CodeMirror internally buffers changes and only updates its
- DOM structure after it has finished performing some operation.
- If you need to perform a lot of operations on a CodeMirror
- instance, you can call this method with a function argument. It
- will call the function, buffering up all changes, and only doing
- the expensive update after the function returns. This can be a
- lot faster. The return value from this method will be the return
- value of your function.
-
- cm.indentLine(line, dir)
- Adjust the indentation of the given line. The second
- argument (which defaults to "smart") may be one of:
-
- "prev"
- Base indentation on the indentation of the previous line.
- "smart"
- Use the mode's smart indentation if available, behave
- like "prev" otherwise.
- "add"
- Increase the indentation of the line by
- one indent unit .
- "subtract"
- Reduce the indentation of the line.
-
-
- doc.posFromIndex(index) → object
- Calculates and returns a {line, ch} object for a
- zero-based index who's value is relative to the start of the
- editor's text. If the index is out of range of the text then
- the returned object is clipped to start or end of the text
- respectively.
- doc.indexFromPos(object) → number
- The reverse of posFromIndex .
-
- cm.focus()
- Give the editor focus.
-
- cm.getInputField() → textarea
- Returns the hidden textarea used to read input.
- cm.getWrapperElement() → node
- Returns the DOM node that represents the editor, and
- controls its size. Remove this from your tree to delete an
- editor instance.
- cm.getScrollerElement() → node
- Returns the DOM node that is responsible for the scrolling
- of the editor.
- cm.getGutterElement() → node
- Fetches the DOM node that contains the editor gutters.
-
-
- Static properties
-
- The CodeMirror object itself provides
- several useful properties. Firstly, its version
- property contains a string that indicates the version of the
- library. For releases, this simply
- contains "major.minor" (for
- example "2.33". For beta versions, " B"
- (space, capital B) is added at the end of the string, for
- development snapshots, " +" (space, plus) is
- added.
-
- The CodeMirror.fromTextArea
- method provides another way to initialize an editor. It takes a
- textarea DOM node as first argument and an optional configuration
- object as second. It will replace the textarea with a CodeMirror
- instance, and wire up the form of that textarea (if any) to make
- sure the editor contents are put into the textarea when the form
- is submitted. A CodeMirror instance created this way has three
- additional methods:
-
-
- cm.save()
- Copy the content of the editor into the textarea.
-
- cm.toTextArea()
- Remove the editor, and restore the original textarea (with
- the editor's current content).
-
- cm.getTextArea() → textarea
- Returns the textarea that the instance was based on.
-
-
- If you want to define extra methods in terms
- of the CodeMirror API, it is possible to
- use CodeMirror.defineExtension(name, value). This
- will cause the given value (usually a method) to be added to all
- CodeMirror instances created from then on.
-
- Similarly, CodeMirror.defineOption(name,
- default, updateFunc) can be used to define new options for
- CodeMirror. The updateFunc will be called with the
- editor instance and the new value when an editor is initialized,
- and whenever the option is modified
- through setOption .
-
- If your extention just needs to run some
- code whenever a CodeMirror instance is initialized,
- use CodeMirror.defineInitHook. Give it a function as
- its only argument, and from then on, that function will be called
- (with the instance as argument) whenever a new CodeMirror instance
- is initialized.
-
- Add-ons
-
- The addon directory in the distribution contains a
- number of reusable components that implement extra editor
- functionality. In brief, they are:
-
-
- dialog/dialog.js
- Provides a very simple way to query users for text input.
- Adds an openDialog method to CodeMirror instances,
- which can be called with an HTML fragment that provides the
- prompt (should include an input tag), and a
- callback function that is called when text has been entered.
- Depends on addon/dialog/dialog.css.
- search/searchcursor.js
- Adds the getSearchCursor(query, start, caseFold) →
- cursor method to CodeMirror instances, which can be used
- to implement search/replace functionality. query
- can be a regular expression or a string (only strings will match
- across lines—if they contain newlines). start
- provides the starting position of the search. It can be
- a {line, ch} object, or can be left off to default
- to the start of the document. caseFold is only
- relevant when matching a string. It will cause the search to be
- case-insensitive. A search cursor has the following methods:
-
- findNext(), findPrevious() → boolean
- Search forward or backward from the current position.
- The return value indicates whether a match was found. If
- matching a regular expression, the return value will be the
- array returned by the match method, in case you
- want to extract matched groups.
- from(), to() → object
- These are only valid when the last call
- to findNext or findPrevious did
- not return false. They will return {line, ch}
- objects pointing at the start and end of the match.
- replace(text)
- Replaces the currently found match with the given text
- and adjusts the cursor position to reflect the
- replacement.
-
-
- search/search.js
- Implements the search commands. CodeMirror has keys bound to
- these by default, but will not do anything with them unless an
- implementation is provided. Depends
- on searchcursor.js, and will make use
- of openDialog when
- available to make prompting for search queries less ugly.
- edit/matchbrackets.js
- Defines an option matchBrackets which, when set
- to true, causes matching brackets to be highlighted whenever the
- cursor is next to them. It also adds a
- method matchBrackets that forces this to happen
- once, and a method findMatchingBracket that can be
- used to run the bracket-finding algorithm that this uses
- internally.
- edit/closebrackets.js
- Defines an option autoCloseBrackets that will
- auto-close brackets and quotes when typed. By default, it'll
- auto-close ()[]{}''"", but you can pass it a
- string similar to that (containing pairs of matching characters)
- to customize it. Demo
- here .
- fold/foldcode.js
- Helps with code folding.
- See the demo for an example.
- Call CodeMirror.newFoldFunction with a range-finder
- helper function to create a function that will, when applied to
- a CodeMirror instance and a line number, attempt to fold or
- unfold the block starting at the given line. A range-finder is a
- language-specific function that also takes an instance and a
- line number, and returns an range to be folded, or null if no
- block is started on that line. There are files in
- the addon/fold/
- directory providing CodeMirror.braceRangeFinder,
- which finds blocks in brace languages (JavaScript, C, Java,
- etc), CodeMirror.indentRangeFinder, for languages
- where indentation determines block structure (Python, Haskell),
- and CodeMirror.tagRangeFinder, for XML-style
- languages.
- runmode/runmode.js
- Can be used to run a CodeMirror mode over text without
- actually opening an editor instance.
- See the demo for an example.
- There are alternate versions of the file avaible for
- running stand-alone
- (without including all of CodeMirror) and
- for running under
- node.js .
- mode/overlay.js
- Mode combinator that can be used to extend a mode with an
- 'overlay' — a secondary mode is run over the stream, along with
- the base mode, and can color specific pieces of text without
- interfering with the base mode.
- Defines CodeMirror.overlayMode, which is used to
- create such a mode. See this
- demo for a detailed example.
- mode/multiplex.js
- Mode combinator that can be used to easily 'multiplex'
- between several modes.
- Defines CodeMirror.multiplexingMode which, when
- given as first argument a mode object, and as other arguments
- any number of {open, close, mode [, delimStyle]}
- objects, will return a mode object that starts parsing using the
- mode passed as first argument, but will switch to another mode
- as soon as it encounters a string that occurs in one of
- the open fields of the passed objects. When in a
- sub-mode, it will go back to the top mode again when
- the close string is encountered.
- Pass "\n" for open or close
- if you want to switch on a blank line.
- When delimStyle is specified, it will be the token
- style returned for the delimiter tokens. The outer mode will not
- see the content between the delimiters.
- See this demo for an
- example.
- hint/show-hint.js
- Provides a framework for showing autocompletion hints.
- Defines CodeMirror.showHint, which takes a
- CodeMirror instance and a hinting function, and pops up a widget
- that allows the user to select a completion. Hinting functions
- are function that take an editor instance, and return
- a {list, from, to} object, where list
- is an array of strings (the completions), and from
- and to give the start and end of the token that is
- being completed. Depends
- on addon/hint/show-hint.css. See the other files in
- the addon/hint for
- hint sources for various languages. Check
- out the demo for an
- example.
- match-highlighter.js
- Adds a highlightSelectionMatches option that
- can be enabled to highlight all instances of a currently
- selected word.
- Demo here .
- lint/lint.js
- Defines an interface component for showing linting warnings,
- with pluggable warning sources
- (see json-lint.js
- and javascript-lint.js
- in the same directory). Defines a lintWith option
- that can be set to a warning source (for
- example CodeMirror.javascriptValidator). Depends
- on addon/lint/lint.css. A demo can be
- found here .
- selection/mark-selection.js
- Causes the selected text to be marked with the CSS class
- CodeMirror-selectedtext when the styleSelectedText option
- is enabled. Useful to change the colour of the selection (in addition to the background),
- like in this demo .
- selection/active-line.js
- Defines a styleActiveLine option that, when enabled,
- gives the wrapper of the active line the class CodeMirror-activeline,
- and adds a background with the class CodeMirror-activeline-background.
- is enabled. See the demo .
- edit/closetag.js
- Provides utility functions for adding automatic tag closing
- to XML modes. See
- the demo .
- mode/loadmode.js
- Defines a CodeMirror.requireMode(modename,
- callback) function that will try to load a given mode and
- call the callback when it succeeded. You'll have to
- set CodeMirror.modeURL to a string that mode paths
- can be constructed from, for
- example "mode/%N/%N.js"—the %N's will
- be replaced with the mode name. Also
- defines CodeMirror.autoLoadMode(instance, mode),
- which will ensure the given mode is loaded and cause the given
- editor instance to refresh its mode when the loading
- succeeded. See the demo .
-
- Adds an continueComments option, which can be
- set to true to have the editor prefix new lines inside C-like
- block comments with an asterisk when Enter is pressed. It can
- also be set to a string in order to bind this functionality to a
- specific key..
- display/placeholder.js
- Adds a placeholder option that can be used to
- make text appear in the editor when it is empty and not focused.
- Also gives the editor a CodeMirror-empty CSS class
- whenever it doesn't contain any text.
- See the demo .
-
-
- Writing CodeMirror Modes
-
- Modes typically consist of a single JavaScript file. This file
- defines, in the simplest case, a lexer (tokenizer) for your
- language—a function that takes a character stream as input,
- advances it past a token, and returns a style for that token. More
- advanced modes can also handle indentation for the language.
-
- The mode script should
- call CodeMirror.defineMode to register itself with
- CodeMirror. This function takes two arguments. The first should be
- the name of the mode, for which you should use a lowercase string,
- preferably one that is also the name of the files that define the
- mode (i.e. "xml" is defined in xml.js). The
- second argument should be a function that, given a CodeMirror
- configuration object (the thing passed to
- the CodeMirror function) and an optional mode
- configuration object (as in
- the mode option), returns
- a mode object.
-
- Typically, you should use this second argument
- to defineMode as your module scope function (modes
- should not leak anything into the global scope!), i.e. write your
- whole mode inside this function.
-
- The main responsibility of a mode script is parsing
- the content of the editor. Depending on the language and the
- amount of functionality desired, this can be done in really easy
- or extremely complicated ways. Some parsers can be stateless,
- meaning that they look at one element (token ) of the code
- at a time, with no memory of what came before. Most, however, will
- need to remember something. This is done by using a state
- object , which is an object that is always passed when
- reading a token, and which can be mutated by the tokenizer.
-
- Modes that use a state must define
- a startState method on their mode object. This is a
- function of no arguments that produces a state object to be used
- at the start of a document.
-
- The most important part of a mode object is
- its token(stream, state) method. All modes must
- define this method. It should read one token from the stream it is
- given as an argument, optionally update its state, and return a
- style string, or null for tokens that do not have to
- be styled. For your styles, you are encouraged to use the
- 'standard' names defined in the themes (without
- the cm- prefix). If that fails, it is also possible
- to come up with your own and write your own CSS theme file.
-
-
The stream object that's passed
- to token encapsulates a line of code (tokens may
- never span lines) and our current position in that line. It has
- the following API:
-
-
- eol() → boolean
- Returns true only if the stream is at the end of the
- line.
- sol() → boolean
- Returns true only if the stream is at the start of the
- line.
-
- peek() → character
- Returns the next character in the stream without advancing
- it. Will return an null at the end of the
- line.
- next() → character
- Returns the next character in the stream and advances it.
- Also returns null when no more characters are
- available.
-
- eat(match) → character
- match can be a character, a regular expression,
- or a function that takes a character and returns a boolean. If
- the next character in the stream 'matches' the given argument,
- it is consumed and returned. Otherwise, undefined
- is returned.
- eatWhile(match) → boolean
- Repeatedly calls eat with the given argument,
- until it fails. Returns true if any characters were eaten.
- eatSpace() → boolean
- Shortcut for eatWhile when matching
- white-space.
- skipToEnd()
- Moves the position to the end of the line.
- skipTo(ch) → boolean
- Skips to the next occurrence of the given character, if
- found on the current line (doesn't advance the stream if the
- character does not occur on the line). Returns true if the
- character was found.
- match(pattern, consume, caseFold) → boolean
- Act like a
- multi-character eat—if consume is true
- or not given—or a look-ahead that doesn't update the stream
- position—if it is false. pattern can be either a
- string or a regular expression starting with ^.
- When it is a string, caseFold can be set to true to
- make the match case-insensitive. When successfully matching a
- regular expression, the returned value will be the array
- returned by match, in case you need to extract
- matched groups.
-
- backUp(n)
- Backs up the stream n characters. Backing it up
- further than the start of the current token will cause things to
- break, so be careful.
- column() → integer
- Returns the column (taking into account tabs) at which the
- current token starts.
- indentation() → integer
- Tells you how far the current line has been indented, in
- spaces. Corrects for tab characters.
-
- current() → string
- Get the string between the start of the current token and
- the current stream position.
-
-
- By default, blank lines are simply skipped when
- tokenizing a document. For languages that have significant blank
- lines, you can define a blankLine(state) method on
- your mode that will get called whenever a blank line is passed
- over, so that it can update the parser state.
-
- Because state object are mutated, and CodeMirror
- needs to keep valid versions of a state around so that it can
- restart a parse at any line, copies must be made of state objects.
- The default algorithm used is that a new state object is created,
- which gets all the properties of the old object. Any properties
- which hold arrays get a copy of these arrays (since arrays tend to
- be used as mutable stacks). When this is not correct, for example
- because a mode mutates non-array properties of its state object, a
- mode object should define a copyState method,
- which is given a state and should return a safe copy of that
- state.
-
- If you want your mode to provide smart indentation
- (through the indentLine
- method and the indentAuto
- and newlineAndIndent commands, to which keys can be
- bound ), you must define
- an indent(state, textAfter) method on your mode
- object.
-
- The indentation method should inspect the given state object,
- and optionally the textAfter string, which contains
- the text on the line that is being indented, and return an
- integer, the amount of spaces to indent. It should usually take
- the indentUnit
- option into account. An indentation method may
- return CodeMirror.Pass to indicate that it
- could not come up with a precise indentation.
-
- Finally, a mode may define
- an electricChars property, which should hold a string
- containing all the characters that should trigger the behaviour
- described for
- the electricChars
- option.
-
- So, to summarize, a mode must provide
- a token method, and it may
- provide startState, copyState,
- and indent methods. For an example of a trivial mode,
- see the diff mode , for a more
- involved example, see the C-like
- mode .
-
- Sometimes, it is useful for modes to nest —to have one
- mode delegate work to another mode. An example of this kind of
- mode is the mixed-mode HTML
- mode . To implement such nesting, it is usually necessary to
- create mode objects and copy states yourself. To create a mode
- object, there are CodeMirror.getMode(options,
- parserConfig), where the first argument is a configuration
- object as passed to the mode constructor function, and the second
- argument is a mode specification as in
- the mode option. To copy a
- state object, call CodeMirror.copyState(mode, state),
- where mode is the mode that created the given
- state.
-
- In a nested mode, it is recommended to add an
- extra methods, innerMode which, given a state object,
- returns a {state, mode} object with the inner mode
- and its state for the current position. These are used by utility
- scripts such as the tag closer to
- get context information. Use the CodeMirror.innerMode
- helper function to, starting from a mode and a state, recursively
- walk down to the innermost mode and state.
-
- To make indentation work properly in a nested parser, it is
- advisable to give the startState method of modes that
- are intended to be nested an optional argument that provides the
- base indentation for the block of code. The JavaScript and CSS
- parser do this, for example, to allow JavaScript and CSS code
- inside the mixed-mode HTML mode to be properly indented.
-
- It is possible, and encouraged, to associate your mode, or a
- certain configuration of your mode, with
- a MIME type. For
- example, the JavaScript mode associates itself
- with text/javascript, and its JSON variant
- with application/json. To do this,
- call CodeMirror.defineMIME(mime, modeSpec),
- where modeSpec can be a string or object specifying a
- mode, as in the mode
- option.
-
- Sometimes, it is useful to add or override mode
- object properties from external code.
- The CodeMirror.extendMode can be used to add
- properties to mode objects produced for a specific mode. Its first
- argument is the name of the mode, its second an object that
- specifies the properties that should be added. This is mostly
- useful to add utilities that can later be looked
- up through getMode .
-
-
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/modes.html b/gulliver/js/codemirror/doc/modes.html
deleted file mode 100644
index f8080a46e..000000000
--- a/gulliver/js/codemirror/doc/modes.html
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
- CodeMirror: Mode list
-
-
-
-
-
-
-
-
-
-
-/* Full list of
- modes */
-
-
-
-Every mode in the distribution. The list on the front-page leaves
-out some of the more obscure ones.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/oldrelease.html b/gulliver/js/codemirror/doc/oldrelease.html
deleted file mode 100644
index f97a65a8c..000000000
--- a/gulliver/js/codemirror/doc/oldrelease.html
+++ /dev/null
@@ -1,492 +0,0 @@
-
-
-
-
- CodeMirror
-
-
-
-
-
-
-
-
-
-
-
-/* Old release
- history */
-
-
-
- 22-10-2012: Version 3.0, beta 2 :
-
-
- Fix page-based coordinate computation.
- Fix firing of gutterClick event.
- Add cursorHeight option.
- Fix bi-directional text regression.
- Add viewportMargin option.
- Directly handle mousewheel events (again, hopefully better).
- Make vertical cursor movement more robust (through widgets, big line gaps).
- Add flattenSpans option.
- Many optimizations. Poor responsiveness should be fixed.
- Initialization in hidden state works again.
- Full list of patches .
-
-
- 19-09-2012: Version 2.34 :
-
-
- New mode: Common Lisp .
- Fix right-click select-all on most browsers.
- Change the way highlighting happens: Saves memory and CPU cycles. compareStates is no longer needed. onHighlightComplete no longer works.
- Integrate mode (Markdown, XQuery, CSS, sTex) tests in central testsuite.
- Add a CodeMirror.version property.
- More robust handling of nested modes in formatting and closetag plug-ins.
- Un/redo now preserves marked text and bookmarks.
- Full list of patches.
-
-
- 19-09-2012: Version 3.0, beta 1 :
-
-
- Bi-directional text support.
- More powerful gutter model.
- Support for arbitrary text/widget height.
- In-line widgets.
- Generalized event handling.
-
-
- 23-08-2012: Version 2.33 :
-
-
- New mode: Sieve .
- New getViewPort and onViewportChange API.
- Configurable cursor blink rate.
- Make binding a key to false disabling handling (again).
- Show non-printing characters as red dots.
- More tweaks to the scrolling model.
- Expanded testsuite. Basic linter added.
- Remove most uses of innerHTML. Remove CodeMirror.htmlEscape.
- Full list of patches.
-
-
- 23-07-2012: Version 2.32 :
-
- Emergency fix for a bug where an editor with
- line wrapping on IE will break when there is no
- scrollbar.
-
- 20-07-2012: Version 2.31 :
-
-
-
- 22-06-2012: Version 2.3 :
-
-
- New scrollbar implementation . Should flicker less. Changes DOM structure of the editor.
- New theme: vibrant-ink .
- Many extensions to the VIM keymap (including text objects).
- Add mode-multiplexing utility script.
- Fix bug where right-click paste works in read-only mode.
- Add a getScrollInfo method.
- Lots of other fixes .
-
-
- 23-05-2012: Version 2.25 :
-
-
- New mode: Erlang .
- Remove xmlpure mode (use xml.js ).
- Fix line-wrapping in Opera.
- Fix X Windows middle-click paste in Chrome.
- Fix bug that broke pasting of huge documents.
- Fix backspace and tab key repeat in Opera.
-
-
- 23-04-2012: Version 2.24 :
-
-
- Drop support for Internet Explorer 6 .
- New
- modes: Shell , Tiki
- wiki , Pig Latin .
- New themes: Ambiance , Blackboard .
- More control over drag/drop
- with dragDrop
- and onDragEvent
- options.
- Make HTML mode a bit less pedantic.
- Add compoundChange API method.
- Several fixes in undo history and line hiding.
- Remove (broken) support for catchall in key maps,
- add nofallthrough boolean field instead.
-
-
- 26-03-2012: Version 2.23 :
-
-
- Change default binding for tab [more]
-
- Starting in 2.23, these bindings are default:
-
Tab: Insert tab character
- Shift-tab: Reset line indentation to default
- Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)
- Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)
-
-
-
- New modes: XQuery and VBScript .
- Two new themes: lesser-dark and xq-dark .
- Differentiate between background and text styles in setLineClass .
- Fix drag-and-drop in IE9+.
- Extend charCoords
- and cursorCoords with a mode argument.
- Add autofocus option.
- Add findMarksAt method.
-
-
- 27-02-2012: Version 2.22 :
-
-
-
- 27-01-2012: Version 2.21 :
-
-
- Added LESS , MySQL ,
- Go , and Verilog modes.
- Add smartIndent
- option.
- Support a cursor in readOnly -mode.
- Support assigning multiple styles to a token.
- Use a new approach to drawing the selection.
- Add scrollTo method.
- Allow undo/redo events to span non-adjacent lines.
- Lots and lots of bugfixes.
-
-
- 20-12-2011: Version 2.2 :
-
-
-
- 21-11-2011: Version 2.18 :
- Fixes TextMarker.clear, which is broken in 2.17.
-
- 21-11-2011: Version 2.17 :
-
- Add support for line
- wrapping and code
- folding .
- Add Github-style Markdown mode.
- Add Monokai
- and Rubyblue themes.
- Add setBookmark method.
- Move some of the demo code into reusable components
- under lib/util .
- Make screen-coord-finding code faster and more reliable.
- Fix drag-and-drop in Firefox.
- Improve support for IME.
- Speed up content rendering.
- Fix browser's built-in search in Webkit.
- Make double- and triple-click work in IE.
- Various fixes to modes.
-
-
- 27-10-2011: Version 2.16 :
-
- Add Perl , Rust , TiddlyWiki , and Groovy modes.
- Dragging text inside the editor now moves, rather than copies.
- Add a coordsFromIndex method.
- API change : setValue now no longer clears history. Use clearHistory for that.
- API change : markText now
- returns an object with clear and find
- methods. Marked text is now more robust when edited.
- Fix editing code with tabs in Internet Explorer.
-
-
- 26-09-2011: Version 2.15 :
- Fix bug that snuck into 2.14: Clicking the
- character that currently has the cursor didn't re-focus the
- editor.
-
- 26-09-2011: Version 2.14 :
-
-
-
- 23-08-2011: Version 2.13 :
-
-
- 25-07-2011: Version 2.12 :
-
- Add a SPARQL mode.
- Fix bug with cursor jumping around in an unfocused editor in IE.
- Allow key and mouse events to bubble out of the editor. Ignore widget clicks.
- Solve cursor flakiness after undo/redo.
- Fix block-reindent ignoring the last few lines.
- Fix parsing of multi-line attrs in XML mode.
- Use innerHTML for HTML-escaping.
- Some fixes to indentation in C-like mode.
- Shrink horiz scrollbars when long lines removed.
- Fix width feedback loop bug that caused the width of an inner DIV to shrink.
-
-
- 04-07-2011: Version 2.11 :
-
- Add a Scheme mode .
- Add a replace method to search cursors, for cursor-preserving replacements.
- Make the C-like mode mode more customizable.
- Update XML mode to spot mismatched tags.
- Add getStateAfter API and compareState mode API methods for finer-grained mode magic.
- Add a getScrollerElement API method to manipulate the scrolling DIV.
- Fix drag-and-drop for Firefox.
- Add a C# configuration for the C-like mode .
- Add full-screen editing and mode-changing demos.
-
-
- 07-06-2011: Version 2.1 :
- Add
- a theme system
- (demo ). Note that this is not
- backwards-compatible—you'll have to update your styles and
- modes!
-
- 07-06-2011: Version 2.02 :
-
- Add a Lua mode .
- Fix reverse-searching for a regexp.
- Empty lines can no longer break highlighting.
- Rework scrolling model (the outer wrapper no longer does the scrolling).
- Solve horizontal jittering on long lines.
- Add runmode.js .
- Immediately re-highlight text when typing.
- Fix problem with 'sticking' horizontal scrollbar.
-
-
- 26-05-2011: Version 2.01 :
-
- Add a Smalltalk mode .
- Add a reStructuredText mode .
- Add a Python mode .
- Add a PL/SQL mode .
- coordsChar now works
- Fix a problem where onCursorActivity interfered with onChange.
- Fix a number of scrolling and mouse-click-position glitches.
- Pass information about the changed lines to onChange.
- Support cmd-up/down on OS X.
- Add triple-click line selection.
- Don't handle shift when changing the selection through the API.
- Support "nocursor" mode for readOnly option.
- Add an onHighlightComplete option.
- Fix the context menu for Firefox.
-
-
- 28-03-2011: Version 2.0 :
- CodeMirror 2 is a complete rewrite that's
- faster, smaller, simpler to use, and less dependent on browser
- quirks. See this
- and this
- for more information.
-
-
28-03-2011: Version 1.0 :
-
- Fix error when debug history overflows.
- Refine handling of C# verbatim strings.
- Fix some issues with JavaScript indentation.
-
-
- 22-02-2011: Version 2.0 beta 2 :
- Somewhat more mature API, lots of bugs shaken out.
-
-
17-02-2011: Version 0.94 :
-
- tabMode: "spaces" was modified slightly (now indents when something is selected).
- Fixes a bug that would cause the selection code to break on some IE versions.
- Disabling spell-check on WebKit browsers now works.
-
-
- 08-02-2011: Version 2.0 beta 1 :
- CodeMirror 2 is a complete rewrite of
- CodeMirror, no longer depending on an editable frame.
-
- 19-01-2011: Version 0.93 :
-
- Added a Regular Expression parser.
- Fixes to the PHP parser.
- Support for regular expression in search/replace.
- Add save method to instances created with fromTextArea.
- Add support for MS T-SQL in the SQL parser.
- Support use of CSS classes for highlighting brackets.
- Fix yet another hang with line-numbering in hidden editors.
-
-
- 17-12-2010: Version 0.92 :
-
- Make CodeMirror work in XHTML documents.
- Fix bug in handling of backslashes in Python strings.
- The styleNumbers option is now officially
- supported and documented.
- onLineNumberClick option added.
- More consistent names onLoad and
- onCursorActivity callbacks. Old names still work, but
- are deprecated.
- Add a Freemarker mode.
-
-
- 11-11-2010: Version 0.91 :
-
- Adds support for Java .
- Small additions to the PHP and SQL parsers.
- Work around various Webkit issues .
- Fix toTextArea to update the code in the textarea.
- Add a noScriptCaching option (hack to ease development).
- Make sub-modes of HTML mixed mode configurable.
-
-
- 02-10-2010: Version 0.9 :
-
- Add support for searching backwards.
- There are now parsers for Scheme , XQuery , and OmetaJS .
- Makes height: "dynamic" more robust.
- Fixes bug where paste did not work on OS X.
- Add a enterMode and electricChars options to make indentation even more customizable.
- Add firstLineNumber option.
- Fix bad handling of @media rules by the CSS parser.
- Take a new, more robust approach to working around the invisible-last-line bug in WebKit.
-
-
- 22-07-2010: Version 0.8 :
-
- Add a cursorCoords method to find the screen
- coordinates of the cursor.
- A number of fixes and support for more syntax in the PHP parser.
- Fix indentation problem with JSON-mode JS parser in Webkit.
- Add a minification UI.
- Support a height: dynamic mode, where the editor's
- height will adjust to the size of its content.
- Better support for IME input mode.
- Fix JavaScript parser getting confused when seeing a no-argument
- function call.
- Have CSS parser see the difference between selectors and other
- identifiers.
- Fix scrolling bug when pasting in a horizontally-scrolled
- editor.
- Support toTextArea method in instances created with
- fromTextArea.
- Work around new Opera cursor bug that causes the cursor to jump
- when pressing backspace at the end of a line.
-
-
- 27-04-2010: Version
- 0.67 :
- More consistent page-up/page-down behaviour
- across browsers. Fix some issues with hidden editors looping forever
- when line-numbers were enabled. Make PHP parser parse
- "\\" correctly. Have jumpToLine work on
- line handles, and add cursorLine function to fetch the
- line handle where the cursor currently is. Add new
- setStylesheet function to switch style-sheets in a
- running editor.
-
- 01-03-2010: Version
- 0.66 :
- Adds removeLine method to API.
- Introduces the PLSQL parser .
- Marks XML errors by adding (rather than replacing) a CSS class, so
- that they can be disabled by modifying their style. Fixes several
- selection bugs, and a number of small glitches.
-
- 12-11-2009: Version
- 0.65 :
- Add support for having both line-wrapping and
- line-numbers turned on, make paren-highlighting style customisable
- (markParen and unmarkParen config
- options), work around a selection bug that Opera
- re introduced in version 10.
-
- 23-10-2009: Version
- 0.64 :
- Solves some issues introduced by the
- paste-handling changes from the previous release. Adds
- setSpellcheck, setTextWrapping,
- setIndentUnit, setUndoDepth,
- setTabMode, and setLineNumbers to
- customise a running editor. Introduces an SQL parser. Fixes a few small
- problems in the Python
- parser. And, as usual, add workarounds for various newly discovered
- browser incompatibilities.
-
-31-08-2009 : Version
-0.63 :
- Overhaul of paste-handling (less fragile), fixes for several
-serious IE8 issues (cursor jumping, end-of-document bugs) and a number
-of small problems.
-
-30-05-2009 : Version
-0.62 :
-Introduces Python
-and Lua parsers. Add
-setParser (on-the-fly mode changing) and
-clearHistory methods. Make parsing passes time-based
-instead of lines-based (see the passTime option).
-
-
diff --git a/gulliver/js/codemirror/doc/realworld.html b/gulliver/js/codemirror/doc/realworld.html
deleted file mode 100644
index 4f0dec346..000000000
--- a/gulliver/js/codemirror/doc/realworld.html
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
- CodeMirror: Real-world uses
-
-
-
-
-
-
-
-
-
-
-/* Real world uses,
- full list */
-
-
-
- Contact me if you'd like
- your project to be added to this list.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/reporting.html b/gulliver/js/codemirror/doc/reporting.html
deleted file mode 100644
index a61651253..000000000
--- a/gulliver/js/codemirror/doc/reporting.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
- CodeMirror: Reporting Bugs
-
-
-
-
-
-
-
-
-
-
-
-/* Reporting bugs
- effectively */
-
-
-
-
-
-
So you found a problem in CodeMirror. By all means, report it! Bug
-reports from users are the main drive behind improvements to
-CodeMirror. But first, please read over these points:
-
-
- CodeMirror is maintained by volunteers. They don't owe you
- anything, so be polite. Reports with an indignant or belligerent
- tone tend to be moved to the bottom of the pile.
-
- Include information about the browser in which the
- problem occurred . Even if you tested several browsers, and
- the problem occurred in all of them, mention this fact in the bug
- report. Also include browser version numbers and the operating
- system that you're on.
-
- Mention which release of CodeMirror you're using. Preferably,
- try also with the current development snapshot, to ensure the
- problem has not already been fixed.
-
- Mention very precisely what went wrong. "X is broken" is not a
- good bug report. What did you expect to happen? What happened
- instead? Describe the exact steps a maintainer has to take to make
- the problem occur. We can not fix something that we can not
- observe.
-
- If the problem can not be reproduced in any of the demos
- included in the CodeMirror distribution, please provide an HTML
- document that demonstrates the problem. The best way to do this is
- to go to jsbin.com , enter
- it there, press save, and include the resulting link in your bug
- report.
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/upgrade_v2.2.html b/gulliver/js/codemirror/doc/upgrade_v2.2.html
deleted file mode 100644
index 7e4d84004..000000000
--- a/gulliver/js/codemirror/doc/upgrade_v2.2.html
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
- CodeMirror: Upgrading to v2.2
-
-
-
-
-
-
-
-
-
-
-/* Upgrading to
- v2.2 */
-
-
-
-
-
-
There are a few things in the 2.2 release that require some care
-when upgrading.
-
-
No more default.css
-
-
The default theme is now included
-in codemirror.css , so
-you do not have to included it separately anymore. (It was tiny, so
-even if you're not using it, the extra data overhead is negligible.)
-
-
Different key customization
-
-
CodeMirror has moved to a system
-where keymaps are used to
-bind behavior to keys. This means custom
-bindings are now possible.
-
-
Three options that influenced key
-behavior, tabMode, enterMode,
-and smartHome, are no longer supported. Instead, you can
-provide custom bindings to influence the way these keys act. This is
-done through the
-new extraKeys
-option, which can hold an object mapping key names to functionality. A
-simple example would be:
-
-
extraKeys: {
- "Ctrl-S": function(instance) { saveText(instance.getValue()); },
- "Ctrl-/": "undo"
- }
-
-
Keys can be mapped either to functions, which will be given the
-editor instance as argument, or to strings, which are mapped through
-functions through the CodeMirror.commands table, which
-contains all the built-in editing commands, and can be inspected and
-extended by external code.
-
-
By default, the Home key is bound to
-the "goLineStartSmart" command, which moves the cursor to
-the first non-whitespace character on the line. You can set do this to
-make it always go to the very start instead:
-
-
extraKeys: {"Home": "goLineStart"}
-
-
Similarly, Enter is bound
-to "newlineAndIndent" by default. You can bind it to
-something else to get different behavior. To disable special handling
-completely and only get a newline character inserted, you can bind it
-to false:
-
-
extraKeys: {"Enter": false}
-
-
The same works for Tab. If you don't want CodeMirror
-to handle it, bind it to false. The default behaviour is
-to indent the current line more ("indentMore" command),
-and indent it less when shift is held ("indentLess").
-There are also "indentAuto" (smart indent)
-and "insertTab" commands provided for alternate
-behaviors. Or you can write your own handler function to do something
-different altogether.
-
-
Tabs
-
-
Handling of tabs changed completely. The display width of tabs can
-now be set with the tabSize option, and tabs can
-be styled by setting CSS rules
-for the cm-tab class.
-
-
The default width for tabs is now 4, as opposed to the 8 that is
-hard-wired into browsers. If you are relying on 8-space tabs, make
-sure you explicitly set tabSize: 8 in your options.
-
-
-
-
-
diff --git a/gulliver/js/codemirror/doc/upgrade_v3.html b/gulliver/js/codemirror/doc/upgrade_v3.html
deleted file mode 100644
index 7e8a6b61a..000000000
--- a/gulliver/js/codemirror/doc/upgrade_v3.html
+++ /dev/null
@@ -1,227 +0,0 @@
-
-
-
-
- CodeMirror: Upgrading to v3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/* Upgrading to
- version 3 */
-
-
-
-
-
-
Version 3 does not depart too much from 2.x API, and sites that use
-CodeMirror in a very simple way might be able to upgrade without
-trouble. But it does introduce a number of incompatibilities. Please
-at least skim this text before upgrading.
-
-
Note that version 3 drops full support for Internet
-Explorer 7 . The editor will mostly work on that browser, but
-it'll be significantly glitchy.
-
-
DOM structure
-
-
This one is the most likely to cause problems. The internal
-structure of the editor has changed quite a lot, mostly to implement a
-new scrolling model.
-
-
Editor height is now set on the outer wrapper element (CSS
-class CodeMirror), not on the scroller element
-(CodeMirror-scroll).
-
-
Other nodes were moved, dropped, and added. If you have any code
-that makes assumptions about the internal DOM structure of the editor,
-you'll have to re-test it and probably update it to work with v3.
-
-
See the styling section of the
-manual for more information.
-
-
Gutter model
-
-
In CodeMirror 2.x, there was a single gutter, and line markers
-created with setMarker would have to somehow coexist with
-the line numbers (if present). Version 3 allows you to specify an
-array of gutters, by class
-name ,
-use setGutterMarker
-to add or remove markers in individual gutters, and clear whole
-gutters
-with clearGutter .
-Gutter markers are now specified as DOM nodes, rather than HTML
-snippets.
-
-
The gutters no longer horizontally scrolls along with the content.
-The fixedGutter option was removed (since it is now the
-only behavior).
-
-
-<style>
- /* Define a gutter style */
- .note-gutter { width: 3em; background: cyan; }
-</style>
-<script>
- // Create an instance with two gutters -- line numbers and notes
- var cm = new CodeMirror(document.body, {
- gutters: ["note-gutter", "CodeMirror-linenumbers"],
- lineNumbers: true
- });
- // Add a note to line 0
- cm.setGutterMarker(0, "note-gutter", document.createTextNode("hi"));
-</script>
-
-
-
Event handling
-
-
Most of the onXYZ options have been removed. The same
-effect is now obtained by calling
-the on method with a string
-identifying the event type. Multiple handlers can now be registered
-(and individually unregistered) for an event, and objects such as line
-handlers now also expose events. See the
-full list here .
-
-
(The onKeyEvent and onDragEvent options,
-which act more as hooks than as event handlers, are still there in
-their old form.)
-
-
-cm.on("change", function(cm, change) {
- console.log("something changed! (" + change.origin + ")");
-});
-
-
-
markText method arguments
-
-
The markText method
-(which has gained some interesting new features, such as creating
-atomic and read-only spans, or replacing spans with widgets) no longer
-takes the CSS class name as a separate argument, but makes it an
-optional field in the options object instead.
-
-
-// Style first ten lines, and forbid the cursor from entering them
-cm.markText({line: 0, ch: 0}, {line: 10, ch: 0}, {
- className: "magic-text",
- inclusiveLeft: true,
- atomic: true
-});
-
-
-
Line folding
-
-
The interface for hiding lines has been
-removed. markText can
-now be used to do the same in a more flexible and powerful way.
-
-
The folding script has been
-updated to use the new interface, and should now be more robust.
-
-
-// Fold a range, replacing it with the text "??"
-var range = cm.markText({line: 4, ch: 2}, {line: 8, ch: 1}, {
- replacedWith: document.createTextNode("??"),
- // Auto-unfold when cursor moves into the range
- clearOnEnter: true
-});
-// Get notified when auto-unfolding
-CodeMirror.on(range, "clear", function() {
- console.log("boom");
-});
-
-
-
Line CSS classes
-
-
The setLineClass method has been replaced
-by addLineClass
-and removeLineClass ,
-which allow more modular control over the classes attached to a line.
-
-
-var marked = cm.addLineClass(10, "background", "highlighted-line");
-setTimeout(function() {
- cm.removeLineClass(marked, "background", "highlighted-line");
-});
-
-
-
Position properties
-
-
All methods that take or return objects that represent screen
-positions now use {left, top, bottom, right} properties
-(not always all of them) instead of the {x, y, yBot} used
-by some methods in v2.x.
-
-
Affected methods
-are cursorCoords , charCoords , coordsChar ,
-and getScrollInfo .
-
-
Bracket matching no longer in core
-
-
The matchBrackets
-option is no longer defined in the core editor.
-Load addon/edit/matchbrackets.js to enable it.
-
-
Mode management
-
-
The CodeMirror.listModes
-and CodeMirror.listMIMEs functions, used for listing
-defined modes, are gone. You are now encouraged to simply
-inspect CodeMirror.modes (mapping mode names to mode
-constructors) and CodeMirror.mimeModes (mapping MIME
-strings to mode specs).
-
-
New features
-
-
Some more reasons to upgrade to version 3.
-
-
- Bi-directional text support. CodeMirror will now mostly do the
- right thing when editing Arabic or Hebrew text.
- Arbitrary line heights. Using fonts with different heights
- inside the editor (whether off by one pixel or fifty) is now
- supported and handled gracefully.
- In-line widgets. See the demo
- and the docs .
- Defining custom options
- with CodeMirror.defineOption .
-
-
-
-
-
-
-
diff --git a/gulliver/js/codemirror/index.html b/gulliver/js/codemirror/index.html
index 9b250b63d..7097608d8 100644
--- a/gulliver/js/codemirror/index.html
+++ b/gulliver/js/codemirror/index.html
@@ -1,472 +1,192 @@
-
-
-
- CodeMirror
-
-
-
-
-
-
+CodeMirror
+
-
-
-
-/* In-browser code editing
- made bearable */
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
- CodeMirror is a JavaScript component that
- provides a code editor in the browser. When a mode is available for
- the language you are coding in, it will color your code, and
- optionally help with indentation.
+
+ CodeMirror is a versatile text editor
+ implemented in JavaScript for the browser. It is specialized for
+ editing code, and comes with a number of language modes and addons
+ that implement more advanced editing functionaly.
- A rich programming API and a CSS
- theming system are available for customizing CodeMirror to fit your
- application, and extending it with new functionality.
+ A rich programming API and a
+ CSS theming system are
+ available for customizing CodeMirror to fit your application, and
+ extending it with new functionality.
+
-
+
+ This is CodeMirror
+
+
+
+
+
+
+ Other demos...
+ Autocompletion
+ Code folding
+ Themes
+ Mixed language modes
+ Bi-directional text
+ Variable font sizes
+ Search interface
+ Vim bindings
+ Emacs bindings
+ Tern integration
+ Merge/diff interface
+ Full-screen editor
+
+
+
+
DOWNLOAD LATEST RELEASE
+
+
+
+
DONATE WITH PAYPAL
+
+ or
Bank ,
+
Gittip ,
+
Flattr
+
+ ×
+ Bank: Rabobank
+ Country: Netherlands
+ SWIFT: RABONL2U
+ Account: 147850770
+ Name: Marijn Haverbeke
+ IBAN: NL26 RABO 0147 8507 70
+
+
+
+
+
+
+
+
+
+
-
Supported modes:
+
-
+
-
- Getting the code
-
- All of CodeMirror is released under a MIT-style license. To get it, you can download
- the latest
- release or the current development
- snapshot as zip files. To create a custom minified script file,
- you can use the compression API .
-
- We use git for version control.
- The main repository can be fetched in this way:
-
- git clone http://marijnhaverbeke.nl/git/codemirror
-
- CodeMirror can also be found on GitHub at marijnh/CodeMirror .
- If you plan to hack on the code and contribute patches, the best way
- to do it is to create a GitHub fork, and send pull requests.
-
- Documentation
-
- The manual is your first stop for
- learning how to use this library. It starts with a quick explanation
- of how to use the editor, and then describes the API in detail.
-
- For those who want to learn more about the code, there is
- a series of
- posts on CodeMirror on my blog, and the
- old overview of the editor
- internals .
- The source code
- itself is, for the most part, also very readable.
-
- Support and bug reports
-
- Community discussion, questions, and informal bug reporting is
- done on
- the CodeMirror
- Google group . There is a separate
- group, CodeMirror-announce ,
- which is lower-volume, and is only used for major announcements—new
- versions and such. These will be cross-posted to both groups, so you
- don't need to subscribe to both.
-
- Though bug reports through e-mail are responded to, the preferred
- way to report bugs is to use
- the GitHub
- issue tracker . Before reporting a
- bug, read these pointers . Also,
- the issue tracker is for bugs , not requests for help.
-
- When none of these seem fitting, you can
- simply e-mail the maintainer
+
Discussion around the project is done on
+ a mailing list .
+ There is also
+ the codemirror-announce
+ list, which is only used for major announcements (such as new
+ versions). If needed, you can
+ contact the maintainer
directly.
- Supported browsers
+ A list of CodeMirror-related software that is not part of the
+ main distribution is maintained
+ on our
+ wiki . Feel free to add your project.
+
- The following desktop browsers are able to run CodeMirror:
+
+ Browser support
+ The desktop versions of the following browsers,
+ in standards mode (HTML5 <!doctype html>
+ recommended) are supported:
+
+ Firefox version 3 and up
+ Chrome any version
+ Safari version 5.2 and up
+ Internet Explorer version 8 and up
+ Opera version 9 and up
+
+ Modern mobile browsers tend to partly work. Bug reports and
+ patches for mobile support are welcome, but the maintainer does not
+ have the time or budget to actually work on it himself.
+
-
- Firefox 3 or higher
- Chrome, any version
- Safari 5.2 or higher
- Opera 9 or higher (with some key-handling problems on OS X)
- Internet Explorer 8 or higher in standards mode
- (Not quirks mode. But quasi-standards mode with a
- transitional doctype is also flaky. <!doctype
- html> is recommended.)
- Internet Explorer 7 (standards mode) is usable, but buggy. It
- has a z-index
- bug that prevents CodeMirror from working properly.
-
-
- I am not actively testing against every new browser release, and
- vendors have a habit of introducing bugs all the time, so I am
- relying on the community to tell me when something breaks.
- See here for information on how to contact
- me.
-
- Mobile browsers mostly kind of work, but, because of limitations
- and their fundamentally different UI assumptions, show a lot of
- quirks that are hard to work around.
-
- Commercial support
-
- CodeMirror is developed and maintained by me, Marijn Haverbeke,
- in my own time. If your company is getting value out of CodeMirror,
- please consider purchasing a support contract.
-
-
- You'll be funding further work on CodeMirror.
- You ensure that you get a quick response when you have a
- problem, even when I am otherwise busy.
-
-
- CodeMirror support contracts exist in two
- forms—basic at €100 per month,
- and premium at €500 per
- month. Contact me for further
- information.
-
-
-
-
-
-
Download the latest release
-
-
Support CodeMirror
-
-
-
-
- Bank: Rabobank
- Country: Netherlands
- SWIFT: RABONL2U
- Account: 147850770
- Name: Marijn Haverbeke
- IBAN: NL26 RABO 0147 8507 70
-
-
-
Reading material
-
-
-
-
Releases
-
-
20-03-2013: Version 3.11 :
-
-
-
-
21-02-2013: Version 3.1 :
-
-
-
-
-
25-01-2013: Version 3.02 :
-
-
Single-bugfix release. Fixes a problem that
- prevents CodeMirror instances from being garbage-collected after
- they become unused.
-
-
21-01-2013: Version 3.01 :
-
-
-
-
21-01-2013: Version 2.38 :
-
-
Integrate some bugfixes, enhancements to the vim keymap, and new
- modes
- (D , Sass , APL )
- from the v3 branch.
-
-
20-12-2012: Version 2.37 :
-
-
- New mode: SQL (will replace plsql and mysql modes).
- Further work on the new VIM mode.
- Fix Cmd/Ctrl keys on recent Operas on OS X.
- Full list of patches .
-
-
-
10-12-2012: Version 3.0 :
-
-
New major version . Only
- partially backwards-compatible. See
- the upgrading guide for more
- information. Changes since release candidate 2:
-
-
- Rewritten VIM mode.
- Fix a few minor scrolling and sizing issues.
- Work around Safari segfault when dragging.
- Full list of patches .
-
-
-
-
20-11-2012: Version 3.0, release candidate 2 :
-
-
- New mode: HTTP .
- Improved handling of selection anchor position.
- Improve IE performance on longer lines.
- Reduce gutter glitches during horiz. scrolling.
- Add addKeyMap and removeKeyMap methods.
- Rewrite formatting and closetag add-ons.
- Full list of patches .
-
-
-
20-11-2012: Version 2.36 :
-
-
-
-
20-11-2012: Version 3.0, release candidate 1 :
-
-
-
-
22-10-2012: Version 2.35 :
-
-
- New (sub) mode: TypeScript .
- Don't overwrite (insert key) when pasting.
- Fix several bugs in markText /undo interaction.
- Better indentation of JavaScript code without semicolons.
- Add defineInitHook function.
- Full list of patches .
-
-
-
Older releases...
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/gulliver/js/codemirror/keymap/emacs.js b/gulliver/js/codemirror/keymap/emacs.js
index fab3ab9fe..592238bc9 100644
--- a/gulliver/js/codemirror/keymap/emacs.js
+++ b/gulliver/js/codemirror/keymap/emacs.js
@@ -1,30 +1,398 @@
-// TODO number prefixes
(function() {
- // Really primitive kill-ring implementation.
+ "use strict";
+
+ var Pos = CodeMirror.Pos;
+ function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
+
+ // Kill 'ring'
+
var killRing = [];
function addToRing(str) {
killRing.push(str);
if (killRing.length > 50) killRing.shift();
}
- function getFromRing() { return killRing[killRing.length - 1] || ""; }
+ function growRingTop(str) {
+ if (!killRing.length) return addToRing(str);
+ killRing[killRing.length - 1] += str;
+ }
+ function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; }
function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
- CodeMirror.keyMap.emacs = {
- "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
- "Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
- "Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
- "Alt-W": function(cm) {addToRing(cm.getSelection());},
- "Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());},
+ var lastKill = null;
+
+ function kill(cm, from, to, mayGrow, text) {
+ if (text == null) text = cm.getRange(from, to);
+
+ if (mayGrow && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen))
+ growRingTop(text);
+ else
+ addToRing(text);
+ cm.replaceRange("", from, to, "+delete");
+
+ if (mayGrow) lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()};
+ else lastKill = null;
+ }
+
+ // Boundaries of various units
+
+ function byChar(cm, pos, dir) {
+ return cm.findPosH(pos, dir, "char", true);
+ }
+
+ function byWord(cm, pos, dir) {
+ return cm.findPosH(pos, dir, "word", true);
+ }
+
+ function byLine(cm, pos, dir) {
+ return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn);
+ }
+
+ function byPage(cm, pos, dir) {
+ return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn);
+ }
+
+ function byParagraph(cm, pos, dir) {
+ var no = pos.line, line = cm.getLine(no);
+ var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch));
+ var fst = cm.firstLine(), lst = cm.lastLine();
+ for (;;) {
+ no += dir;
+ if (no < fst || no > lst)
+ return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null));
+ line = cm.getLine(no);
+ var hasText = /\S/.test(line);
+ if (hasText) sawText = true;
+ else if (sawText) return Pos(no, 0);
+ }
+ }
+
+ function bySentence(cm, pos, dir) {
+ var line = pos.line, ch = pos.ch;
+ var text = cm.getLine(pos.line), sawWord = false;
+ for (;;) {
+ var next = text.charAt(ch + (dir < 0 ? -1 : 0));
+ if (!next) { // End/beginning of line reached
+ if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch);
+ text = cm.getLine(line + dir);
+ if (!/\S/.test(text)) return Pos(line, ch);
+ line += dir;
+ ch = dir < 0 ? text.length : 0;
+ continue;
+ }
+ if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0));
+ if (!sawWord) sawWord = /\w/.test(next);
+ ch += dir;
+ }
+ }
+
+ function byExpr(cm, pos, dir) {
+ var wrap;
+ if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, true))
+ && wrap.match && (wrap.forward ? 1 : -1) == dir)
+ return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to;
+
+ for (var first = true;; first = false) {
+ var token = cm.getTokenAt(pos);
+ var after = Pos(pos.line, dir < 0 ? token.start : token.end);
+ if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) {
+ var newPos = cm.findPosH(after, dir, "char");
+ if (posEq(after, newPos)) return pos;
+ else pos = newPos;
+ } else {
+ return after;
+ }
+ }
+ }
+
+ // Prefixes (only crudely supported)
+
+ function getPrefix(cm, precise) {
+ var digits = cm.state.emacsPrefix;
+ if (!digits) return precise ? null : 1;
+ clearPrefix(cm);
+ return digits == "-" ? -1 : Number(digits);
+ }
+
+ function repeated(cmd) {
+ var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd;
+ return function(cm) {
+ var prefix = getPrefix(cm);
+ f(cm);
+ for (var i = 1; i < prefix; ++i) f(cm);
+ };
+ }
+
+ function findEnd(cm, by, dir) {
+ var pos = cm.getCursor(), prefix = getPrefix(cm);
+ if (prefix < 0) { dir = -dir; prefix = -prefix; }
+ for (var i = 0; i < prefix; ++i) {
+ var newPos = by(cm, pos, dir);
+ if (posEq(newPos, pos)) break;
+ pos = newPos;
+ }
+ return pos;
+ }
+
+ function move(by, dir) {
+ var f = function(cm) {
+ cm.extendSelection(findEnd(cm, by, dir));
+ };
+ f.motion = true;
+ return f;
+ }
+
+ function killTo(cm, by, dir) {
+ kill(cm, cm.getCursor(), findEnd(cm, by, dir), true);
+ }
+
+ function addPrefix(cm, digit) {
+ if (cm.state.emacsPrefix) {
+ if (digit != "-") cm.state.emacsPrefix += digit;
+ return;
+ }
+ // Not active yet
+ cm.state.emacsPrefix = digit;
+ cm.on("keyHandled", maybeClearPrefix);
+ cm.on("inputRead", maybeDuplicateInput);
+ }
+
+ var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true};
+
+ function maybeClearPrefix(cm, arg) {
+ if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg))
+ clearPrefix(cm);
+ }
+
+ function clearPrefix(cm) {
+ cm.state.emacsPrefix = null;
+ cm.off("keyHandled", maybeClearPrefix);
+ cm.off("inputRead", maybeDuplicateInput);
+ }
+
+ function maybeDuplicateInput(cm, event) {
+ var dup = getPrefix(cm);
+ if (dup > 1 && event.origin == "+input") {
+ var one = event.text.join("\n"), txt = "";
+ for (var i = 1; i < dup; ++i) txt += one;
+ cm.replaceSelection(txt, "end", "+input");
+ }
+ }
+
+ function addPrefixMap(cm) {
+ cm.state.emacsPrefixMap = true;
+ cm.addKeyMap(prefixMap);
+ cm.on("keyHandled", maybeRemovePrefixMap);
+ cm.on("inputRead", maybeRemovePrefixMap);
+ }
+
+ function maybeRemovePrefixMap(cm, arg) {
+ if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return;
+ cm.removeKeyMap(prefixMap);
+ cm.state.emacsPrefixMap = false;
+ cm.off("keyHandled", maybeRemovePrefixMap);
+ cm.off("inputRead", maybeRemovePrefixMap);
+ }
+
+ // Utilities
+
+ function setMark(cm) {
+ cm.setCursor(cm.getCursor());
+ cm.setExtending(true);
+ cm.on("change", function() { cm.setExtending(false); });
+ }
+
+ function clearMark(cm) {
+ cm.setExtending(false);
+ cm.setCursor(cm.getCursor());
+ }
+
+ function getInput(cm, msg, f) {
+ if (cm.openDialog)
+ cm.openDialog(msg + ":
", f, {bottom: true});
+ else
+ f(prompt(msg, ""));
+ }
+
+ function operateOnWord(cm, op) {
+ var start = cm.getCursor(), end = cm.findPosH(start, 1, "word");
+ cm.replaceRange(op(cm.getRange(start, end)), start, end);
+ cm.setCursor(end);
+ }
+
+ function toEnclosingExpr(cm) {
+ var pos = cm.getCursor(), line = pos.line, ch = pos.ch;
+ var stack = [];
+ while (line >= cm.firstLine()) {
+ var text = cm.getLine(line);
+ for (var i = ch == null ? text.length : ch; i > 0;) {
+ var ch = text.charAt(--i);
+ if (ch == ")")
+ stack.push("(");
+ else if (ch == "]")
+ stack.push("[");
+ else if (ch == "}")
+ stack.push("{");
+ else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch))
+ return cm.extendSelection(Pos(line, i));
+ }
+ --line; ch = null;
+ }
+ }
+
+ function quit(cm) {
+ cm.execCommand("clearSearch");
+ clearMark(cm);
+ }
+
+ // Actual keymap
+
+ var keyMap = CodeMirror.keyMap.emacs = {
+ "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"));},
+ "Ctrl-K": repeated(function(cm) {
+ var start = cm.getCursor(), end = cm.clipPos(Pos(start.line));
+ var text = cm.getRange(start, end);
+ if (!/\S/.test(text)) {
+ text += "\n";
+ end = Pos(start.line + 1, 0);
+ }
+ kill(cm, start, end, true, text);
+ }),
+ "Alt-W": function(cm) {
+ addToRing(cm.getSelection());
+ clearMark(cm);
+ },
+ "Ctrl-Y": function(cm) {
+ var start = cm.getCursor();
+ cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste");
+ cm.setSelection(start, cm.getCursor());
+ },
"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", "Alt-/": "autocomplete", "Alt-V": "goPageUp",
+
+ "Ctrl-Space": setMark, "Ctrl-Shift-2": setMark,
+
+ "Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
+ "Right": move(byChar, 1), "Left": move(byChar, -1),
+ "Ctrl-D": function(cm) { killTo(cm, byChar, 1); },
+ "Delete": function(cm) { killTo(cm, byChar, 1); },
+ "Ctrl-H": function(cm) { killTo(cm, byChar, -1); },
+ "Backspace": function(cm) { killTo(cm, byChar, -1); },
+
+ "Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1),
+ "Alt-D": function(cm) { killTo(cm, byWord, 1); },
+ "Alt-Backspace": function(cm) { killTo(cm, byWord, -1); },
+
+ "Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1),
+ "Down": move(byLine, 1), "Up": move(byLine, -1),
+ "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
+ "End": "goLineEnd", "Home": "goLineStart",
+
+ "Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1),
+ "PageUp": move(byPage, -1), "PageDown": move(byPage, 1),
+
+ "Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1),
+
+ "Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1),
+ "Alt-K": function(cm) { killTo(cm, bySentence, 1); },
+
+ "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1); },
+ "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1); },
+ "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1),
+
+ "Shift-Ctrl-Alt-2": function(cm) {
+ cm.setSelection(findEnd(cm, byExpr, 1), cm.getCursor());
+ },
+ "Ctrl-Alt-T": function(cm) {
+ var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
+ var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1);
+ cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) +
+ cm.getRange(leftStart, leftEnd), leftStart, rightEnd);
+ },
+ "Ctrl-Alt-U": repeated(toEnclosingExpr),
+
+ "Alt-Space": function(cm) {
+ var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line);
+ while (from && /\s/.test(text.charAt(from - 1))) --from;
+ while (to < text.length && /\s/.test(text.charAt(to))) ++to;
+ cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to));
+ },
+ "Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }),
+ "Ctrl-T": repeated(function(cm) {
+ var pos = cm.getCursor();
+ if (pos.ch < cm.getLine(pos.line).length) pos = Pos(pos.line, pos.ch + 1);
+ var from = cm.findPosH(pos, -2, "char");
+ var range = cm.getRange(from, pos);
+ if (range.length != 2) return;
+ cm.setSelection(from, pos);
+ cm.replaceSelection(range.charAt(1) + range.charAt(0), "end");
+ }),
+
+ "Alt-C": repeated(function(cm) {
+ operateOnWord(cm, function(w) {
+ var letter = w.search(/\w/);
+ if (letter == -1) return w;
+ return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase();
+ });
+ }),
+ "Alt-U": repeated(function(cm) {
+ operateOnWord(cm, function(w) { return w.toUpperCase(); });
+ }),
+ "Alt-L": repeated(function(cm) {
+ operateOnWord(cm, function(w) { return w.toLowerCase(); });
+ }),
+
+ "Alt-;": "toggleComment",
+
+ "Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"),
+ "Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"),
+ "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
+ "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace",
+ "Alt-/": "autocomplete",
"Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
- fallthrough: ["basic", "emacsy"]
+
+ "Alt-G": function(cm) {cm.setOption("keyMap", "emacs-Alt-G");},
+ "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
+ "Ctrl-Q": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-Q");},
+ "Ctrl-U": addPrefixMap
};
CodeMirror.keyMap["emacs-Ctrl-X"] = {
- "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
+ "Tab": function(cm) {
+ cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit"));
+ },
+ "Ctrl-X": function(cm) {
+ cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor"));
+ },
+
+ "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": repeated("undo"), "K": "close",
+ "Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); },
+ auto: "emacs", nofallthrough: true, disableInput: true
+ };
+
+ CodeMirror.keyMap["emacs-Alt-G"] = {
+ "G": function(cm) {
+ var prefix = getPrefix(cm, true);
+ if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1);
+
+ getInput(cm, "Goto line", function(str) {
+ var num;
+ if (str && !isNaN(num = Number(str)) && num == num|0 && num > 0)
+ cm.setCursor(num - 1);
+ });
+ },
+ auto: "emacs", nofallthrough: true, disableInput: true
+ };
+
+ CodeMirror.keyMap["emacs-Ctrl-Q"] = {
+ "Tab": repeated("insertTab"),
auto: "emacs", nofallthrough: true
};
+
+ var prefixMap = {"Ctrl-G": clearPrefix};
+ function regPrefix(d) {
+ prefixMap[d] = function(cm) { addPrefix(cm, d); };
+ keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); };
+ prefixPreservingKeys["Ctrl-" + d] = true;
+ }
+ for (var i = 0; i < 10; ++i) regPrefix(String(i));
+ regPrefix("-");
})();
diff --git a/gulliver/js/codemirror/keymap/extra.js b/gulliver/js/codemirror/keymap/extra.js
new file mode 100644
index 000000000..18dd5a979
--- /dev/null
+++ b/gulliver/js/codemirror/keymap/extra.js
@@ -0,0 +1,43 @@
+// A number of additional default bindings that are too obscure to
+// include in the core codemirror.js file.
+
+(function() {
+ "use strict";
+
+ var Pos = CodeMirror.Pos;
+
+ function moveLines(cm, start, end, dist) {
+ if (!dist || start > end) return 0;
+
+ var from = cm.clipPos(Pos(start, 0)), to = cm.clipPos(Pos(end));
+ var text = cm.getRange(from, to);
+
+ if (start <= cm.firstLine())
+ cm.replaceRange("", from, Pos(to.line + 1, 0));
+ else
+ cm.replaceRange("", Pos(from.line - 1), to);
+ var target = from.line + dist;
+ if (target <= cm.firstLine()) {
+ cm.replaceRange(text + "\n", Pos(target, 0));
+ return cm.firstLine() - from.line;
+ } else {
+ var targetPos = cm.clipPos(Pos(target - 1));
+ cm.replaceRange("\n" + text, targetPos);
+ return targetPos.line + 1 - from.line;
+ }
+ }
+
+ function moveSelectedLines(cm, dist) {
+ var head = cm.getCursor("head"), anchor = cm.getCursor("anchor");
+ cm.operation(function() {
+ var moved = moveLines(cm, Math.min(head.line, anchor.line), Math.max(head.line, anchor.line), dist);
+ cm.setSelection(Pos(anchor.line + moved, anchor.ch), Pos(head.line + moved, head.ch));
+ });
+ }
+
+ CodeMirror.commands.moveLinesUp = function(cm) { moveSelectedLines(cm, -1); };
+ CodeMirror.commands.moveLinesDown = function(cm) { moveSelectedLines(cm, 1); };
+
+ CodeMirror.keyMap["default"]["Alt-Up"] = "moveLinesUp";
+ CodeMirror.keyMap["default"]["Alt-Down"] = "moveLinesDown";
+})();
diff --git a/gulliver/js/codemirror/keymap/vim.js b/gulliver/js/codemirror/keymap/vim.js
index 77b696d93..75b4e454d 100644
--- a/gulliver/js/codemirror/keymap/vim.js
+++ b/gulliver/js/codemirror/keymap/vim.js
@@ -40,6 +40,10 @@
* TODO: Implement the remaining special marks. They have more complex
* behavior.
*
+ * Events:
+ * 'vim-mode-change' - raised on the editor anytime the current mode changes,
+ * Event object: {mode: "visual", subMode: "linewise"}
+ *
* Code structure:
* 1. Default keymap
* 2. Variable declarations and short basic helpers
@@ -58,27 +62,39 @@
var defaultKeymap = [
// Key to key mapping. This goes first to make it possible to override
// existing mappings.
- { keys: ['Left'], type: 'keyToKey', toKeys: ['h'] },
- { keys: ['Right'], type: 'keyToKey', toKeys: ['l'] },
- { keys: ['Up'], type: 'keyToKey', toKeys: ['k'] },
- { keys: ['Down'], type: 'keyToKey', toKeys: ['j'] },
- { keys: ['Space'], type: 'keyToKey', toKeys: ['l'] },
- { keys: ['Backspace'], type: 'keyToKey', toKeys: ['h'] },
- { keys: ['Ctrl-Space'], type: 'keyToKey', toKeys: ['W'] },
- { keys: ['Ctrl-Backspace'], type: 'keyToKey', toKeys: ['B'] },
- { keys: ['Shift-Space'], type: 'keyToKey', toKeys: ['w'] },
- { keys: ['Shift-Backspace'], type: 'keyToKey', toKeys: ['b'] },
- { keys: ['Ctrl-n'], type: 'keyToKey', toKeys: ['j'] },
- { keys: ['Ctrl-p'], type: 'keyToKey', toKeys: ['k'] },
- { keys: ['Ctrl-['], type: 'keyToKey', toKeys: ['Esc'] },
- { keys: ['Ctrl-c'], type: 'keyToKey', toKeys: ['Esc'] },
- { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] },
- { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] },
- { keys: ['Home'], type: 'keyToKey', toKeys: ['0'] },
- { keys: ['End'], type: 'keyToKey', toKeys: ['$'] },
- { keys: ['PageUp'], type: 'keyToKey', toKeys: ['Ctrl-b'] },
- { keys: ['PageDown'], type: 'keyToKey', toKeys: ['Ctrl-f'] },
+ { keys: ['
'], type: 'keyToKey', toKeys: ['h'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['l'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['k'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['j'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['l'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['h'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['W'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['B'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['w'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['b'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['j'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['k'] },
+ { keys: ['C-['], type: 'keyToKey', toKeys: [''] },
+ { keys: [''], type: 'keyToKey', toKeys: [''] },
+ { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'], context: 'normal' },
+ { keys: ['s'], type: 'keyToKey', toKeys: ['x', 'i'], context: 'visual'},
+ { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'], context: 'normal' },
+ { keys: ['S'], type: 'keyToKey', toKeys: ['d', 'c', 'c'], context: 'visual' },
+ { keys: [''], type: 'keyToKey', toKeys: ['0'] },
+ { keys: [''], type: 'keyToKey', toKeys: ['$'] },
+ { keys: [''], type: 'keyToKey', toKeys: [''] },
+ { keys: [''], type: 'keyToKey', toKeys: [''] },
+ { keys: [''], type: 'keyToKey', toKeys: ['j', '^'], context: 'normal' },
// Motions
+ { keys: ['H'], type: 'motion',
+ motion: 'moveToTopLine',
+ motionArgs: { linewise: true, toJumplist: true }},
+ { keys: ['M'], type: 'motion',
+ motion: 'moveToMiddleLine',
+ motionArgs: { linewise: true, toJumplist: true }},
+ { keys: ['L'], type: 'motion',
+ motion: 'moveToBottomLine',
+ motionArgs: { linewise: true, toJumplist: true }},
{ keys: ['h'], type: 'motion',
motion: 'moveByCharacters',
motionArgs: { forward: false }},
@@ -124,19 +140,25 @@
motionArgs: { forward: false, wordEnd: true, bigWord: true,
inclusive: true }},
{ keys: ['{'], type: 'motion', motion: 'moveByParagraph',
- motionArgs: { forward: false }},
+ motionArgs: { forward: false, toJumplist: true }},
{ keys: ['}'], type: 'motion', motion: 'moveByParagraph',
- motionArgs: { forward: true }},
- { keys: ['Ctrl-f'], type: 'motion',
+ motionArgs: { forward: true, toJumplist: true }},
+ { keys: [''], type: 'motion',
motion: 'moveByPage', motionArgs: { forward: true }},
- { keys: ['Ctrl-b'], type: 'motion',
+ { keys: [''], type: 'motion',
motion: 'moveByPage', motionArgs: { forward: false }},
+ { keys: [''], type: 'motion',
+ motion: 'moveByScroll',
+ motionArgs: { forward: true, explicitRepeat: true }},
+ { keys: [''], type: 'motion',
+ motion: 'moveByScroll',
+ motionArgs: { forward: false, explicitRepeat: true }},
{ keys: ['g', 'g'], type: 'motion',
motion: 'moveToLineOrEdgeOfDocument',
- motionArgs: { forward: false, explicitRepeat: true, linewise: true }},
+ motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},
{ keys: ['G'], type: 'motion',
motion: 'moveToLineOrEdgeOfDocument',
- motionArgs: { forward: true, explicitRepeat: true, linewise: true }},
+ motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},
{ keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' },
{ keys: ['^'], type: 'motion',
motion: 'moveToFirstNonWhiteSpaceCharacter' },
@@ -154,7 +176,7 @@
motionArgs: { inclusive: true }},
{ keys: ['%'], type: 'motion',
motion: 'moveToMatchedSymbol',
- motionArgs: { inclusive: true }},
+ motionArgs: { inclusive: true, toJumplist: true }},
{ keys: ['f', 'character'], type: 'motion',
motion: 'moveToCharacter',
motionArgs: { forward: true , inclusive: true }},
@@ -167,29 +189,40 @@
{ keys: ['T', 'character'], type: 'motion',
motion: 'moveTillCharacter',
motionArgs: { forward: false }},
- { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' },
- { keys: ['`', 'character'], type: 'motion', motion: 'goToMark' },
- { keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
- { keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
+ { keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch',
+ motionArgs: { forward: true }},
+ { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch',
+ motionArgs: { forward: false }},
+ { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark',
+ motionArgs: {toJumplist: true}},
+ { keys: ['`', 'character'], type: 'motion', motion: 'goToMark',
+ motionArgs: {toJumplist: true}},
+ { keys: [']', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },
+ { keys: ['[', '`'], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },
{ keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },
{ keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },
+ { keys: [']', 'character'], type: 'motion',
+ motion: 'moveToSymbol',
+ motionArgs: { forward: true, toJumplist: true}},
+ { keys: ['[', 'character'], type: 'motion',
+ motion: 'moveToSymbol',
+ motionArgs: { forward: false, toJumplist: true}},
{ keys: ['|'], type: 'motion',
motion: 'moveToColumn',
motionArgs: { }},
// Operators
{ keys: ['d'], type: 'operator', operator: 'delete' },
{ keys: ['y'], type: 'operator', operator: 'yank' },
- { keys: ['c'], type: 'operator', operator: 'change',
- operatorArgs: { enterInsertMode: true } },
+ { keys: ['c'], type: 'operator', operator: 'change' },
{ keys: ['>'], type: 'operator', operator: 'indent',
operatorArgs: { indentRight: true }},
{ keys: ['<'], type: 'operator', operator: 'indent',
operatorArgs: { indentRight: false }},
{ keys: ['g', '~'], type: 'operator', operator: 'swapcase' },
{ keys: ['n'], type: 'motion', motion: 'findNext',
- motionArgs: { forward: true }},
+ motionArgs: { forward: true, toJumplist: true }},
{ keys: ['N'], type: 'motion', motion: 'findNext',
- motionArgs: { forward: false }},
+ motionArgs: { forward: false, toJumplist: true }},
// Operator-Motion dual commands
{ keys: ['x'], type: 'operatorMotion', operator: 'delete',
motion: 'moveByCharacters', motionArgs: { forward: true },
@@ -204,36 +237,55 @@
motion: 'moveToEol', motionArgs: { inclusive: true },
operatorMotionArgs: { visualLine: true }},
{ keys: ['C'], type: 'operatorMotion',
- operator: 'change', operatorArgs: { enterInsertMode: true },
+ operator: 'change',
motion: 'moveToEol', motionArgs: { inclusive: true },
operatorMotionArgs: { visualLine: true }},
- { keys: ['~'], type: 'operatorMotion', operator: 'swapcase',
+ { keys: ['~'], type: 'operatorMotion',
+ operator: 'swapcase', operatorArgs: { shouldMoveCursor: true },
motion: 'moveByCharacters', motionArgs: { forward: true }},
// Actions
- { keys: ['a'], type: 'action', action: 'enterInsertMode',
+ { keys: [''], type: 'action', action: 'jumpListWalk',
+ actionArgs: { forward: true }},
+ { keys: [''], type: 'action', action: 'jumpListWalk',
+ actionArgs: { forward: false }},
+ { keys: [''], type: 'action',
+ action: 'scroll',
+ actionArgs: { forward: true, linewise: true }},
+ { keys: [''], type: 'action',
+ action: 'scroll',
+ actionArgs: { forward: false, linewise: true }},
+ { keys: ['a'], type: 'action', action: 'enterInsertMode', isEdit: true,
actionArgs: { insertAt: 'charAfter' }},
- { keys: ['A'], type: 'action', action: 'enterInsertMode',
+ { keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true,
actionArgs: { insertAt: 'eol' }},
- { keys: ['i'], type: 'action', action: 'enterInsertMode' },
- { keys: ['I'], type: 'action', action: 'enterInsertMode',
- motion: 'moveToFirstNonWhiteSpaceCharacter' },
+ { keys: ['i'], type: 'action', action: 'enterInsertMode', isEdit: true,
+ actionArgs: { insertAt: 'inplace' }},
+ { keys: ['I'], type: 'action', action: 'enterInsertMode', isEdit: true,
+ actionArgs: { insertAt: 'firstNonBlank' }},
{ keys: ['o'], type: 'action', action: 'newLineAndEnterInsertMode',
+ isEdit: true, interlaceInsertRepeat: true,
actionArgs: { after: true }},
{ keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode',
+ isEdit: true, interlaceInsertRepeat: true,
actionArgs: { after: false }},
{ keys: ['v'], type: 'action', action: 'toggleVisualMode' },
{ keys: ['V'], type: 'action', action: 'toggleVisualMode',
actionArgs: { linewise: true }},
- { keys: ['J'], type: 'action', action: 'joinLines' },
- { keys: ['p'], type: 'action', action: 'paste',
- actionArgs: { after: true }},
- { keys: ['P'], type: 'action', action: 'paste',
- actionArgs: { after: false }},
- { keys: ['r', 'character'], type: 'action', action: 'replace' },
+ { keys: ['J'], type: 'action', action: 'joinLines', isEdit: true },
+ { keys: ['p'], type: 'action', action: 'paste', isEdit: true,
+ actionArgs: { after: true, isEdit: true }},
+ { keys: ['P'], type: 'action', action: 'paste', isEdit: true,
+ actionArgs: { after: false, isEdit: true }},
+ { keys: ['r', 'character'], type: 'action', action: 'replace', isEdit: true },
+ { keys: ['@', 'character'], type: 'action', action: 'replayMacro' },
+ { keys: ['q', 'character'], type: 'action', action: 'enterMacroRecordMode' },
+ // Handle Replace-mode as a special case of insert mode.
+ { keys: ['R'], type: 'action', action: 'enterInsertMode', isEdit: true,
+ actionArgs: { replace: true }},
{ keys: ['u'], type: 'action', action: 'undo' },
- { keys: ['Ctrl-r'], type: 'action', action: 'redo' },
+ { keys: [''], type: 'action', action: 'redo' },
{ keys: ['m', 'character'], type: 'action', action: 'setMark' },
- { keys: ['\"', 'character'], type: 'action', action: 'setRegister' },
+ { keys: ['"', 'character'], type: 'action', action: 'setRegister' },
{ keys: ['z', 'z'], type: 'action', action: 'scrollToCursor',
actionArgs: { position: 'center' }},
{ keys: ['z', '.'], type: 'action', action: 'scrollToCursor',
@@ -241,7 +293,7 @@
motion: 'moveToFirstNonWhiteSpaceCharacter' },
{ keys: ['z', 't'], type: 'action', action: 'scrollToCursor',
actionArgs: { position: 'top' }},
- { keys: ['z', 'Enter'], type: 'action', action: 'scrollToCursor',
+ { keys: ['z', ''], type: 'action', action: 'scrollToCursor',
actionArgs: { position: 'top' },
motion: 'moveToFirstNonWhiteSpaceCharacter' },
{ keys: ['z', '-'], type: 'action', action: 'scrollToCursor',
@@ -250,6 +302,12 @@
actionArgs: { position: 'bottom' },
motion: 'moveToFirstNonWhiteSpaceCharacter' },
{ keys: ['.'], type: 'action', action: 'repeatLastEdit' },
+ { keys: [''], type: 'action', action: 'incrementNumberToken',
+ isEdit: true,
+ actionArgs: {increase: true, backtrack: false}},
+ { keys: [''], type: 'action', action: 'incrementNumberToken',
+ isEdit: true,
+ actionArgs: {increase: false, backtrack: false}},
// Text object motions
{ keys: ['a', 'character'], type: 'motion',
motion: 'textObjectManipulation' },
@@ -258,21 +316,57 @@
motionArgs: { textObjectInner: true }},
// Search
{ keys: ['/'], type: 'search',
- searchArgs: { forward: true, querySrc: 'prompt' }},
+ searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }},
{ keys: ['?'], type: 'search',
- searchArgs: { forward: false, querySrc: 'prompt' }},
+ searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }},
{ keys: ['*'], type: 'search',
- searchArgs: { forward: true, querySrc: 'wordUnderCursor' }},
+ searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},
{ keys: ['#'], type: 'search',
- searchArgs: { forward: false, querySrc: 'wordUnderCursor' }},
+ searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},
// Ex command
{ keys: [':'], type: 'ex' }
];
var Vim = function() {
- var alphabetRegex = /[A-Za-z]/;
+ CodeMirror.defineOption('vimMode', false, function(cm, val) {
+ if (val) {
+ cm.setOption('keyMap', 'vim');
+ cm.setOption('disableInput', true);
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
+ cm.on('beforeSelectionChange', beforeSelectionChange);
+ maybeInitVimState(cm);
+ CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
+ } else if (cm.state.vim) {
+ cm.setOption('keyMap', 'default');
+ cm.setOption('disableInput', false);
+ cm.off('beforeSelectionChange', beforeSelectionChange);
+ CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
+ cm.state.vim = null;
+ }
+ });
+ function beforeSelectionChange(cm, cur) {
+ var vim = cm.state.vim;
+ if (vim.insertMode || vim.exMode) return;
+
+ var head = cur.head;
+ if (head.ch && head.ch == cm.doc.getLine(head.line).length) {
+ head.ch--;
+ }
+ }
+ function getOnPasteFn(cm) {
+ var vim = cm.state.vim;
+ if (!vim.onPasteFn) {
+ vim.onPasteFn = function() {
+ if (!vim.insertMode) {
+ cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
+ actions.enterInsertMode(cm, {}, vim);
+ }
+ };
+ }
+ return vim.onPasteFn;
+ }
+
var numberRegex = /[\d]/;
- var whiteSpaceRegex = /\s/;
var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
function makeKeyRange(start, size) {
var keys = [];
@@ -284,18 +378,12 @@
var upperCaseAlphabet = makeKeyRange(65, 26);
var lowerCaseAlphabet = makeKeyRange(97, 26);
var numbers = makeKeyRange(48, 10);
- var SPECIAL_SYMBOLS = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'';
- var specialSymbols = SPECIAL_SYMBOLS.split('');
+ var specialSymbols = '~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;"\''.split('');
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
'Esc', 'Home', 'End', 'PageUp', 'PageDown', 'Enter'];
- var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
- numbers).concat(['<', '>']);
- var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
- numbers).concat('-\"'.split(''));
+ var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']);
+ var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"']);
- function isAlphabet(k) {
- return alphabetRegex.test(k);
- }
function isLine(cm, line) {
return line >= cm.firstLine() && line <= cm.lastLine();
}
@@ -311,18 +399,9 @@
function isUpperCase(k) {
return (/^[A-Z]$/).test(k);
}
- function isAlphanumeric(k) {
- return (/^[\w]$/).test(k);
- }
- function isWhiteSpace(k) {
- return whiteSpaceRegex.test(k);
- }
function isWhiteSpaceString(k) {
return (/^\s*$/).test(k);
}
- function inRangeInclusive(x, start, end) {
- return x >= start && x <= end;
- }
function inArray(val, arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == val) {
@@ -332,25 +411,108 @@
return false;
}
- // Global Vim state. Call getVimGlobalState to get and initialize.
- var vimGlobalState;
- function getVimGlobalState() {
- if (!vimGlobalState) {
- vimGlobalState = {
- // The current search query.
- searchQuery: null,
- // Whether we are searching backwards.
- searchIsReversed: false,
- registerController: new RegisterController({})
- };
+ var createCircularJumpList = function() {
+ var size = 100;
+ var pointer = -1;
+ var head = 0;
+ var tail = 0;
+ var buffer = new Array(size);
+ function add(cm, oldCur, newCur) {
+ var current = pointer % size;
+ var curMark = buffer[current];
+ function useNextSlot(cursor) {
+ var next = ++pointer % size;
+ var trashMark = buffer[next];
+ if (trashMark) {
+ trashMark.clear();
+ }
+ buffer[next] = cm.setBookmark(cursor);
+ }
+ if (curMark) {
+ var markPos = curMark.find();
+ // avoid recording redundant cursor position
+ if (markPos && !cursorEqual(markPos, oldCur)) {
+ useNextSlot(oldCur);
+ }
+ } else {
+ useNextSlot(oldCur);
+ }
+ useNextSlot(newCur);
+ head = pointer;
+ tail = pointer - size + 1;
+ if (tail < 0) {
+ tail = 0;
+ }
}
- return vimGlobalState;
- }
- function getVimState(cm) {
- if (!cm.vimState) {
+ function move(cm, offset) {
+ pointer += offset;
+ if (pointer > head) {
+ pointer = head;
+ } else if (pointer < tail) {
+ pointer = tail;
+ }
+ var mark = buffer[(size + pointer) % size];
+ // skip marks that are temporarily removed from text buffer
+ if (mark && !mark.find()) {
+ var inc = offset > 0 ? 1 : -1;
+ var newCur;
+ var oldCur = cm.getCursor();
+ do {
+ pointer += inc;
+ mark = buffer[(size + pointer) % size];
+ // skip marks that are the same as current position
+ if (mark &&
+ (newCur = mark.find()) &&
+ !cursorEqual(oldCur, newCur)) {
+ break;
+ }
+ } while (pointer < head && pointer > tail);
+ }
+ return mark;
+ }
+ return {
+ cachedCursor: undefined, //used for # and * jumps
+ add: add,
+ move: move
+ };
+ };
+
+ var createMacroState = function() {
+ return {
+ macroKeyBuffer: [],
+ latestRegister: undefined,
+ inReplay: false,
+ lastInsertModeChanges: {
+ changes: [], // Change list
+ expectCursorActivityForChange: false // Set to true on change, false on cursorActivity.
+ },
+ enteredMacroMode: undefined,
+ isMacroPlaying: false,
+ toggle: function(cm, registerName) {
+ if (this.enteredMacroMode) { //onExit
+ this.enteredMacroMode(); // close dialog
+ this.enteredMacroMode = undefined;
+ } else { //onEnter
+ this.latestRegister = registerName;
+ this.enteredMacroMode = cm.openDialog(
+ '(recording)['+registerName+']', null, {bottom:true});
+ }
+ }
+ };
+ };
+
+
+ function maybeInitVimState(cm) {
+ if (!cm.state.vim) {
// Store instance state in the CodeMirror object.
- cm.vimState = {
+ cm.state.vim = {
inputState: new InputState(),
+ // Vim's input state that triggered the last edit, used to repeat
+ // motions and operators with '.'.
+ lastEditInputState: undefined,
+ // Vim's action command before the last edit, used to repeat actions
+ // with '.' and insert mode repeat.
+ lastEditActionCommand: undefined,
// When using jk for navigation, if you move from a longer line to a
// shorter line, the cursor may clip to the end of the shorter line.
// If j is pressed again and cursor goes to the next line, the
@@ -363,12 +525,30 @@
// executed in between.
lastMotion: null,
marks: {},
+ insertMode: false,
+ // Repeat count for changes made in insert mode, triggered by key
+ // sequences like 3,i. Only exists when insertMode is true.
+ insertModeRepeat: undefined,
visualMode: false,
// If we are in visual line mode. No effect if visualMode is false.
visualLine: false
};
}
- return cm.vimState;
+ return cm.state.vim;
+ }
+ var vimGlobalState;
+ function resetVimGlobalState() {
+ vimGlobalState = {
+ // The current search query.
+ searchQuery: null,
+ // Whether we are searching backwards.
+ searchIsReversed: false,
+ jumpList: createCircularJumpList(),
+ macroModeState: createMacroState(),
+ // Recording latest f, t, F or T motion command.
+ lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
+ registerController: new RegisterController({})
+ };
}
var vimApi= {
@@ -378,49 +558,59 @@
// Testing hook, though it might be useful to expose the register
// controller anyways.
getRegisterController: function() {
- return getVimGlobalState().registerController;
+ return vimGlobalState.registerController;
},
// Testing hook.
- clearVimGlobalState_: function() {
- vimGlobalState = null;
+ resetVimGlobalState_: resetVimGlobalState,
+
+ // Testing hook.
+ getVimGlobalState_: function() {
+ return vimGlobalState;
},
- map: function(lhs, rhs) {
+
+ // Testing hook.
+ maybeInitVimState_: maybeInitVimState,
+
+ InsertModeKey: InsertModeKey,
+ map: function(lhs, rhs, ctx) {
// Add user defined key bindings.
- exCommandDispatcher.map(lhs, rhs);
+ exCommandDispatcher.map(lhs, rhs, ctx);
},
defineEx: function(name, prefix, func){
- if (name.indexOf(prefix) === 0) {
- exCommands[name]=func;
- exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
- }else throw new Error("(Vim.defineEx) \""+prefix+"\" is not a prefix of \""+name+"\", command not registered");
- },
- // Initializes vim state variable on the CodeMirror object. Should only be
- // called lazily by handleKey or for testing.
- maybeInitState: function(cm) {
- getVimState(cm);
+ if (name.indexOf(prefix) !== 0) {
+ throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered');
+ }
+ exCommands[name]=func;
+ exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
},
// This is the outermost function called by CodeMirror, after keys have
// been mapped to their Vim equivalents.
handleKey: function(cm, key) {
var command;
- var vim = getVimState(cm);
- if (key == 'Esc') {
+ var vim = maybeInitVimState(cm);
+ var macroModeState = vimGlobalState.macroModeState;
+ if (macroModeState.enteredMacroMode) {
+ if (key == 'q') {
+ actions.exitMacroRecordMode();
+ vim.inputState = new InputState();
+ return;
+ }
+ }
+ if (key == '') {
// Clear input state and get back to normal mode.
vim.inputState = new InputState();
if (vim.visualMode) {
- exitVisualMode(cm, vim);
+ exitVisualMode(cm);
}
return;
}
- if (vim.visualMode &&
- cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
- // The selection was cleared. Exit visual mode.
- exitVisualMode(cm, vim);
- }
+ // Enter visual mode when the mouse selects text.
if (!vim.visualMode &&
!cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
vim.visualMode = true;
vim.visualLine = false;
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
+ cm.on('mousedown', exitVisualMode);
}
if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) {
// Have to special case 0 since it's both a motion and a number.
@@ -439,8 +629,14 @@
this.handleKey(cm, command.toKeys[i]);
}
} else {
+ if (macroModeState.enteredMacroMode) {
+ logKey(macroModeState, key);
+ }
commandDispatcher.processCommand(cm, vim, command);
}
+ },
+ handleEx: function(cm, input) {
+ exCommandDispatcher.processCommand(cm, input);
}
};
@@ -520,10 +716,16 @@
*/
function RegisterController(registers) {
this.registers = registers;
- this.unamedRegister = registers['\"'] = new Register();
+ this.unamedRegister = registers['"'] = new Register();
}
RegisterController.prototype = {
pushText: function(registerName, operator, text, linewise) {
+ if (linewise && text.charAt(0) == '\n') {
+ text = text.slice(1) + '\n';
+ }
+ if(linewise && text.charAt(text.length - 1) !== '\n'){
+ text += '\n';
+ }
// Lowercase and uppercase registers refer to the same register.
// Uppercase just means append.
var register = this.isValidRegister(registerName) ?
@@ -566,6 +768,9 @@
this.unamedRegister.set(text, linewise);
}
},
+ setRegisterText: function(name, text, linewise) {
+ this.getRegister(name).set(text, linewise);
+ },
// Gets the register named @name. If one of @name doesn't already exist,
// create it. If @name is invalid, return the unamedRegister.
getRegister: function(name) {
@@ -592,45 +797,80 @@
matchCommand: function(key, keyMap, vim) {
var inputState = vim.inputState;
var keys = inputState.keyBuffer.concat(key);
+ var matchedCommands = [];
+ var selectedCharacter;
for (var i = 0; i < keyMap.length; i++) {
var command = keyMap[i];
if (matchKeysPartial(keys, command.keys)) {
- if (keys.length < command.keys.length) {
- // Matches part of a multi-key command. Buffer and wait for next
- // stroke.
- inputState.keyBuffer.push(key);
- return null;
- } else {
- if (inputState.operator && command.type == 'action') {
- // Ignore matched action commands after an operator. Operators
- // only operate on motions. This check is really for text
- // objects since aW, a[ etcs conflicts with a.
- continue;
- }
- // Matches whole comand. Return the command.
- if (command.keys[keys.length - 1] == 'character') {
- inputState.selectedCharacter = keys[keys.length - 1];
- if(inputState.selectedCharacter.length>1){
- switch(inputState.selectedCharacter){
- case "Enter":
- inputState.selectedCharacter='\n';
- break;
- case "Space":
- inputState.selectedCharacter=' ';
- break;
- default:
- continue;
- }
+ if (inputState.operator && command.type == 'action') {
+ // Ignore matched action commands after an operator. Operators
+ // only operate on motions. This check is really for text
+ // objects since aW, a[ etcs conflicts with a.
+ continue;
+ }
+ // Match commands that take as an argument.
+ if (command.keys[keys.length - 1] == 'character') {
+ selectedCharacter = keys[keys.length - 1];
+ if(selectedCharacter.length>1){
+ switch(selectedCharacter){
+ case '':
+ selectedCharacter='\n';
+ break;
+ case '':
+ selectedCharacter=' ';
+ break;
+ default:
+ continue;
}
}
- inputState.keyBuffer = [];
- return command;
}
+ // Add the command to the list of matched commands. Choose the best
+ // command later.
+ matchedCommands.push(command);
}
}
- // Clear the buffer since there are no partial matches.
- inputState.keyBuffer = [];
- return null;
+
+ // Returns the command if it is a full match, or null if not.
+ function getFullyMatchedCommandOrNull(command) {
+ if (keys.length < command.keys.length) {
+ // Matches part of a multi-key command. Buffer and wait for next
+ // stroke.
+ inputState.keyBuffer.push(key);
+ return null;
+ } else {
+ if (command.keys[keys.length - 1] == 'character') {
+ inputState.selectedCharacter = selectedCharacter;
+ }
+ // Clear the buffer since a full match was found.
+ inputState.keyBuffer = [];
+ return command;
+ }
+ }
+
+ if (!matchedCommands.length) {
+ // Clear the buffer since there were no matches.
+ inputState.keyBuffer = [];
+ return null;
+ } else if (matchedCommands.length == 1) {
+ return getFullyMatchedCommandOrNull(matchedCommands[0]);
+ } else {
+ // Find the best match in the list of matchedCommands.
+ var context = vim.visualMode ? 'visual' : 'normal';
+ var bestMatch; // Default to first in the list.
+ for (var i = 0; i < matchedCommands.length; i++) {
+ var current = matchedCommands[i];
+ if (current.context == context) {
+ bestMatch = current;
+ break;
+ } else if (!bestMatch && !current.context) {
+ // Only set an imperfect match to best match if no best match is
+ // set and the imperfect match is not restricted to another
+ // context.
+ bestMatch = current;
+ }
+ }
+ return getFullyMatchedCommandOrNull(bestMatch);
+ }
},
processCommand: function(cm, vim, command) {
vim.inputState.repeatOverride = command.repeatOverride;
@@ -721,7 +961,10 @@
actionArgs.repeatIsExplicit = repeatIsExplicit;
actionArgs.registerName = inputState.registerName;
vim.inputState = new InputState();
- vim.lastMotion = null,
+ vim.lastMotion = null;
+ if (command.isEdit) {
+ this.recordLastEdit(vim, inputState, command);
+ }
actions[command.action](cm, actionArgs, vim);
},
processSearch: function(cm, vim, command) {
@@ -738,24 +981,24 @@
try {
updateSearchQuery(cm, query, ignoreCase, smartCase);
} catch (e) {
- showConfirm(cm, 'Invalid regex: ' + regexPart);
+ showConfirm(cm, 'Invalid regex: ' + query);
return;
}
commandDispatcher.processMotion(cm, vim, {
type: 'motion',
motion: 'findNext',
- motionArgs: { forward: true }
+ motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist }
});
}
function onPromptClose(query) {
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
handleQuery(query, true /** ignoreCase */, true /** smartCase */);
}
- function onPromptKeyUp(e, query) {
+ function onPromptKeyUp(_e, query) {
var parsedQuery;
try {
parsedQuery = updateSearchQuery(cm, query,
- true /** ignoreCase */, true /** smartCase */)
+ true /** ignoreCase */, true /** smartCase */);
} catch (e) {
// Swallow bad regexes for incremental search.
}
@@ -766,7 +1009,7 @@
cm.scrollTo(originalScrollPos.left, originalScrollPos.top);
}
}
- function onPromptKeyDown(e, query, close) {
+ function onPromptKeyDown(e, _query, close) {
var keyName = CodeMirror.keyName(e);
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
updateSearchQuery(cm, originalQuery);
@@ -803,22 +1046,30 @@
return;
}
var query = cm.getLine(word.start.line).substring(word.start.ch,
- word.end.ch + 1);
+ word.end.ch);
if (isKeyword) {
query = '\\b' + query + '\\b';
} else {
query = escapeRegex(query);
}
+
+ // cachedCursor is used to save the old position of the cursor
+ // when * or # causes vim to seek for the nearest word and shift
+ // the cursor before entering the motion.
+ vimGlobalState.jumpList.cachedCursor = cm.getCursor();
cm.setCursor(word.start);
+
handleQuery(query, true /** ignoreCase */, false /** smartCase */);
break;
}
},
processEx: function(cm, vim, command) {
function onPromptClose(input) {
+ // Give the prompt some time to close so that if processCommand shows
+ // an error, the elements don't overlap.
exCommandDispatcher.processCommand(cm, input);
}
- function onPromptKeyDown(e, input, close) {
+ function onPromptKeyDown(e, _input, close) {
var keyName = CodeMirror.keyName(e);
if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') {
CodeMirror.e_stop(e);
@@ -857,7 +1108,7 @@
var curEnd;
var repeat;
if (operator) {
- this.recordLastEdit(cm, vim, inputState);
+ this.recordLastEdit(vim, inputState);
}
if (inputState.repeatOverride !== undefined) {
// If repeatOverride is specified, that takes precedence over the
@@ -886,6 +1137,17 @@
if (!motionResult) {
return;
}
+ if (motionArgs.toJumplist) {
+ var jumpList = vimGlobalState.jumpList;
+ // if the current motion is # or *, use cachedCursor
+ var cachedCursor = jumpList.cachedCursor;
+ if (cachedCursor) {
+ recordJumpPosition(cm, cachedCursor, motionResult);
+ delete jumpList.cachedCursor;
+ } else {
+ recordJumpPosition(cm, curOriginal, motionResult);
+ }
+ }
if (motionResult instanceof Array) {
curStart = motionResult[0];
curEnd = motionResult[1];
@@ -915,6 +1177,11 @@
if (vim.visualLine) {
if (cursorIsBefore(selectionStart, selectionEnd)) {
selectionStart.ch = 0;
+
+ var lastLine = cm.lastLine();
+ if (selectionEnd.line > lastLine) {
+ selectionEnd.line = lastLine;
+ }
selectionEnd.ch = lineLength(cm, selectionEnd.line);
} else {
selectionEnd.ch = 0;
@@ -961,7 +1228,7 @@
// Expand selection to entire line.
expandSelectionToLine(cm, curStart, curEnd);
} else if (motionArgs.forward) {
- // Clip to trailing newlines only if we the motion goes forward.
+ // Clip to trailing newlines only if the motion goes forward.
clipToLine(cm, curStart, curEnd);
}
operatorArgs.registerName = registerName;
@@ -970,15 +1237,17 @@
operators[operator](cm, operatorArgs, vim, curStart,
curEnd, curOriginal);
if (vim.visualMode) {
- exitVisualMode(cm, vim);
- }
- if (operatorArgs.enterInsertMode) {
- actions.enterInsertMode(cm);
+ exitVisualMode(cm);
}
}
},
- recordLastEdit: function(cm, vim, inputState) {
- vim.lastEdit = inputState;
+ recordLastEdit: function(vim, inputState, actionCommand) {
+ var macroModeState = vimGlobalState.macroModeState;
+ if (macroModeState.inReplay) { return; }
+ vim.lastEditInputState = inputState;
+ vim.lastEditActionCommand = actionCommand;
+ macroModeState.lastInsertModeChanges.changes = [];
+ macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false;
}
};
@@ -988,13 +1257,26 @@
*/
// All of the functions below return Cursor objects.
var motions = {
+ moveToTopLine: function(cm, motionArgs) {
+ var line = getUserVisibleLines(cm).top + motionArgs.repeat -1;
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
+ },
+ moveToMiddleLine: function(cm) {
+ var range = getUserVisibleLines(cm);
+ var line = Math.floor((range.top + range.bottom) * 0.5);
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
+ },
+ moveToBottomLine: function(cm, motionArgs) {
+ var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1;
+ return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) };
+ },
expandToLine: function(cm, motionArgs) {
// Expands forward to end of line, and then to next line if repeat is
// >1. Does not handle backward motion!
var cur = cm.getCursor();
return { line: cur.line + motionArgs.repeat - 1, ch: Infinity };
},
- findNext: function(cm, motionArgs, vim) {
+ findNext: function(cm, motionArgs) {
var state = getSearchState(cm);
var query = state.getQuery();
if (!query) {
@@ -1006,7 +1288,7 @@
highlightSearchMatches(cm, query);
return findNext(cm, prev/** prev */, query, motionArgs.repeat);
},
- goToMark: function(cm, motionArgs, vim) {
+ goToMark: function(_cm, motionArgs, vim) {
var mark = vim.marks[motionArgs.selectedCharacter];
if (mark) {
return mark.find();
@@ -1014,7 +1296,7 @@
return null;
},
jumpToMark: function(cm, motionArgs, vim) {
- var best = cm.getCursor();
+ var best = cm.getCursor();
for (var i = 0; i < motionArgs.repeat; i++) {
var cursor = best;
for (var key in vim.marks) {
@@ -1023,7 +1305,7 @@
}
var mark = vim.marks[key].find();
var isWrongDirection = (motionArgs.forward) ?
- cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark)
+ cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark);
if (isWrongDirection) {
continue;
@@ -1033,7 +1315,7 @@
}
var equal = cursorEqual(cursor, best);
- var between = (motionArgs.forward) ?
+ var between = (motionArgs.forward) ?
cusrorIsBetween(cursor, mark, best) :
cusrorIsBetween(best, mark, cursor);
@@ -1068,6 +1350,7 @@
switch (vim.lastMotion) {
case this.moveByLines:
case this.moveByDisplayLines:
+ case this.moveByScroll:
case this.moveToColumn:
case this.moveToEol:
endCh = vim.lastHPos;
@@ -1077,30 +1360,46 @@
}
var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
- if (line < cm.firstLine() || line > cm.lastLine() ) {
- return null;
+ var first = cm.firstLine();
+ var last = cm.lastLine();
+ // Vim cancels linewise motions that start on an edge and move beyond
+ // that edge. It does not cancel motions that do not start on an edge.
+ if ((line < first && cur.line == first) ||
+ (line > last && cur.line == last)) {
+ return;
}
if(motionArgs.toFirstChar){
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
vim.lastHPos = endCh;
}
- vim.lastHSPos = cm.charCoords({line:line, ch:endCh},"div").left;
+ vim.lastHSPos = cm.charCoords({line:line, ch:endCh},'div').left;
return { line: line, ch: endCh };
},
moveByDisplayLines: function(cm, motionArgs, vim) {
var cur = cm.getCursor();
switch (vim.lastMotion) {
case this.moveByDisplayLines:
+ case this.moveByScroll:
case this.moveByLines:
case this.moveToColumn:
case this.moveToEol:
break;
default:
- vim.lastHSPos = cm.charCoords(cur,"div").left;
+ vim.lastHSPos = cm.charCoords(cur,'div').left;
}
var repeat = motionArgs.repeat;
- var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),"line",vim.lastHSPos);
- if(res.hitSide)return null;
+ var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos);
+ if (res.hitSide) {
+ if (motionArgs.forward) {
+ var lastCharCoords = cm.charCoords(res, 'div');
+ var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos };
+ var res = cm.coordsChar(goalCoords, 'div');
+ } else {
+ var resCoords = cm.charCoords({ line: cm.firstLine(), ch: 0}, 'div');
+ resCoords.left = vim.lastHSPos;
+ res = cm.coordsChar(resCoords, 'div');
+ }
+ }
vim.lastHPos = res.ch;
return res;
},
@@ -1131,6 +1430,23 @@
}
return { line: line, ch: 0 };
},
+ moveByScroll: function(cm, motionArgs, vim) {
+ var scrollbox = cm.getScrollInfo();
+ var curEnd = null;
+ var repeat = motionArgs.repeat;
+ if (!repeat) {
+ repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight());
+ }
+ var orig = cm.charCoords(cm.getCursor(), 'local');
+ motionArgs.repeat = repeat;
+ var curEnd = motions.moveByDisplayLines(cm, motionArgs, vim);
+ if (!curEnd) {
+ return null;
+ }
+ var dest = cm.charCoords(curEnd, 'local');
+ cm.scrollTo(null, scrollbox.top + dest.top - orig.top);
+ return curEnd;
+ },
moveByWords: function(cm, motionArgs) {
return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
!!motionArgs.wordEnd, !!motionArgs.bigWord);
@@ -1139,30 +1455,37 @@
var repeat = motionArgs.repeat;
var curEnd = moveToCharacter(cm, repeat, motionArgs.forward,
motionArgs.selectedCharacter);
- if(!curEnd)return cm.getCursor();
var increment = motionArgs.forward ? -1 : 1;
+ recordLastCharacterSearch(increment, motionArgs);
+ if(!curEnd)return cm.getCursor();
curEnd.ch += increment;
return curEnd;
},
moveToCharacter: function(cm, motionArgs) {
var repeat = motionArgs.repeat;
+ recordLastCharacterSearch(0, motionArgs);
return moveToCharacter(cm, repeat, motionArgs.forward,
motionArgs.selectedCharacter) || cm.getCursor();
},
+ moveToSymbol: function(cm, motionArgs) {
+ var repeat = motionArgs.repeat;
+ return findSymbol(cm, repeat, motionArgs.forward,
+ motionArgs.selectedCharacter) || cm.getCursor();
+ },
moveToColumn: function(cm, motionArgs, vim) {
var repeat = motionArgs.repeat;
// repeat is equivalent to which column we want to move to!
vim.lastHPos = repeat - 1;
- vim.lastHSPos = cm.charCoords(cm.getCursor(),"div").left;
+ vim.lastHSPos = cm.charCoords(cm.getCursor(),'div').left;
return moveToColumn(cm, repeat);
},
moveToEol: function(cm, motionArgs, vim) {
var cur = cm.getCursor();
vim.lastHPos = Infinity;
- var retval={ line: cur.line + motionArgs.repeat - 1, ch: Infinity }
+ var retval={ line: cur.line + motionArgs.repeat - 1, ch: Infinity };
var end=cm.clipPos(retval);
end.ch--;
- vim.lastHSPos = cm.charCoords(end,"div").left;
+ vim.lastHSPos = cm.charCoords(end,'div').left;
return retval;
},
moveToFirstNonWhiteSpaceCharacter: function(cm) {
@@ -1172,11 +1495,26 @@
return { line: cursor.line,
ch: findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)) };
},
- moveToMatchedSymbol: function(cm, motionArgs) {
+ moveToMatchedSymbol: function(cm) {
var cursor = cm.getCursor();
- var symbol = cm.getLine(cursor.line).charAt(cursor.ch);
- if (isMatchableSymbol(symbol)) {
- return findMatchedSymbol(cm, cm.getCursor(), motionArgs.symbol);
+ var line = cursor.line;
+ var ch = cursor.ch;
+ var lineText = cm.getLine(line);
+ var symbol;
+ var startContext = cm.getTokenAt(cursor).type;
+ var startCtxLevel = getContextLevel(startContext);
+ do {
+ symbol = lineText.charAt(ch++);
+ if (symbol && isMatchableSymbol(symbol)) {
+ var endContext = cm.getTokenAt({line:line, ch:ch}).type;
+ var endCtxLevel = getContextLevel(endContext);
+ if (startCtxLevel >= endCtxLevel) {
+ break;
+ }
+ }
+ } while (symbol);
+ if (symbol) {
+ return findMatchedSymbol(cm, {line:line, ch:ch-1}, symbol);
} else {
return cursor;
}
@@ -1209,35 +1547,60 @@
var start = tmp.start;
var end = tmp.end;
return [start, end];
+ },
+ repeatLastCharacterSearch: function(cm, motionArgs) {
+ var lastSearch = vimGlobalState.lastChararacterSearch;
+ var repeat = motionArgs.repeat;
+ var forward = motionArgs.forward === lastSearch.forward;
+ var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
+ cm.moveH(-increment, 'char');
+ motionArgs.inclusive = forward ? true : false;
+ var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter);
+ if (!curEnd) {
+ cm.moveH(increment, 'char');
+ return cm.getCursor();
+ }
+ curEnd.ch += increment;
+ return curEnd;
}
};
var operators = {
- change: function(cm, operatorArgs, vim, curStart, curEnd) {
- getVimGlobalState().registerController.pushText(
+ change: function(cm, operatorArgs, _vim, curStart, curEnd) {
+ vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd),
operatorArgs.linewise);
if (operatorArgs.linewise) {
- // Delete starting at the first nonwhitespace character of the first
- // line, instead of from the start of the first line. This way we get
- // an indent when we get into insert mode. This behavior isn't quite
- // correct because we should treat this as a completely new line, and
- // indent should be whatever codemirror thinks is the right indent.
- // But cm.indentLine doesn't seem work on empty lines.
- // TODO: Fix the above.
- curStart.ch =
- findFirstNonWhiteSpaceCharacter(cm.getLine(curStart.line));
- // Insert an additional newline so that insert mode can start there.
- // curEnd should be on the first character of the new line.
- cm.replaceRange('\n', curStart, curEnd);
+ // Push the next line back down, if there is a next line.
+ var replacement = curEnd.line > cm.lastLine() ? '' : '\n';
+ cm.replaceRange(replacement, curStart, curEnd);
+ cm.indentLine(curStart.line, 'smart');
+ // null ch so setCursor moves to end of line.
+ curStart.ch = null;
} else {
+ // Exclude trailing whitespace if the range is not all whitespace.
+ var text = cm.getRange(curStart, curEnd);
+ if (!isWhiteSpaceString(text)) {
+ var match = (/\s+$/).exec(text);
+ if (match) {
+ curEnd = offsetCursor(curEnd, 0, - match[0].length);
+ }
+ }
cm.replaceRange('', curStart, curEnd);
}
+ actions.enterInsertMode(cm, {}, cm.state.vim);
cm.setCursor(curStart);
},
// delete is a javascript keyword.
- 'delete': function(cm, operatorArgs, vim, curStart, curEnd) {
- getVimGlobalState().registerController.pushText(
+ 'delete': function(cm, operatorArgs, _vim, curStart, curEnd) {
+ // If the ending line is past the last line, inclusive, instead of
+ // including the trailing \n, include the \n before the starting line
+ if (operatorArgs.linewise &&
+ curEnd.line > cm.lastLine() && curStart.line > cm.firstLine()) {
+ curStart.line--;
+ curStart.ch = lineLength(cm, curStart.line);
+ }
+ vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd),
operatorArgs.linewise);
cm.replaceRange('', curStart, curEnd);
@@ -1267,7 +1630,7 @@
cm.setCursor(curStart);
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
},
- swapcase: function(cm, operatorArgs, vim, curStart, curEnd, curOriginal) {
+ swapcase: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
var toSwap = cm.getRange(curStart, curEnd);
var swapped = '';
for (var i = 0; i < toSwap.length; i++) {
@@ -1276,10 +1639,12 @@
character.toUpperCase();
}
cm.replaceRange(swapped, curStart, curEnd);
- cm.setCursor(curOriginal);
+ if (!operatorArgs.shouldMoveCursor) {
+ cm.setCursor(curOriginal);
+ }
},
- yank: function(cm, operatorArgs, vim, curStart, curEnd, curOriginal) {
- getVimGlobalState().registerController.pushText(
+ yank: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
+ vimGlobalState.registerController.pushText(
operatorArgs.registerName, 'yank',
cm.getRange(curStart, curEnd), operatorArgs.linewise);
cm.setCursor(curOriginal);
@@ -1287,26 +1652,100 @@
};
var actions = {
+ jumpListWalk: function(cm, actionArgs, vim) {
+ if (vim.visualMode) {
+ return;
+ }
+ var repeat = actionArgs.repeat;
+ var forward = actionArgs.forward;
+ var jumpList = vimGlobalState.jumpList;
+
+ var mark = jumpList.move(cm, forward ? repeat : -repeat);
+ var markPos = mark ? mark.find() : undefined;
+ markPos = markPos ? markPos : cm.getCursor();
+ cm.setCursor(markPos);
+ },
+ scroll: function(cm, actionArgs, vim) {
+ if (vim.visualMode) {
+ return;
+ }
+ var repeat = actionArgs.repeat || 1;
+ var lineHeight = cm.defaultTextHeight();
+ var top = cm.getScrollInfo().top;
+ var delta = lineHeight * repeat;
+ var newPos = actionArgs.forward ? top + delta : top - delta;
+ var cursor = cm.getCursor();
+ var cursorCoords = cm.charCoords(cursor, 'local');
+ if (actionArgs.forward) {
+ if (newPos > cursorCoords.top) {
+ cursor.line += (newPos - cursorCoords.top) / lineHeight;
+ cursor.line = Math.ceil(cursor.line);
+ cm.setCursor(cursor);
+ cursorCoords = cm.charCoords(cursor, 'local');
+ cm.scrollTo(null, cursorCoords.top);
+ } else {
+ // Cursor stays within bounds. Just reposition the scroll window.
+ cm.scrollTo(null, newPos);
+ }
+ } else {
+ var newBottom = newPos + cm.getScrollInfo().clientHeight;
+ if (newBottom < cursorCoords.bottom) {
+ cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight;
+ cursor.line = Math.floor(cursor.line);
+ cm.setCursor(cursor);
+ cursorCoords = cm.charCoords(cursor, 'local');
+ cm.scrollTo(
+ null, cursorCoords.bottom - cm.getScrollInfo().clientHeight);
+ } else {
+ // Cursor stays within bounds. Just reposition the scroll window.
+ cm.scrollTo(null, newPos);
+ }
+ }
+ },
scrollToCursor: function(cm, actionArgs) {
var lineNum = cm.getCursor().line;
- var heightProp = window.getComputedStyle(cm.getScrollerElement()).
- getPropertyValue('height');
- var height = parseInt(heightProp);
- var y = cm.charCoords({line: lineNum, ch: 0}, "local").top;
- var halfHeight = parseInt(height) / 2;
+ var charCoords = cm.charCoords({line: lineNum, ch: 0}, 'local');
+ var height = cm.getScrollInfo().clientHeight;
+ var y = charCoords.top;
+ var lineHeight = charCoords.bottom - y;
switch (actionArgs.position) {
- case 'center': y = y - (height / 2) + 10;
- break;
- case 'bottom': y = y - height;
- break;
- case 'top': break;
+ case 'center': y = y - (height / 2) + lineHeight;
+ break;
+ case 'bottom': y = y - height + lineHeight*1.4;
+ break;
+ case 'top': y = y + lineHeight*0.4;
+ break;
}
cm.scrollTo(null, y);
- // The calculations are slightly off, use scrollIntoView to nudge the
- // view into the right place.
- cm.scrollIntoView();
},
- enterInsertMode: function(cm, actionArgs) {
+ replayMacro: function(cm, actionArgs) {
+ var registerName = actionArgs.selectedCharacter;
+ var repeat = actionArgs.repeat;
+ var macroModeState = vimGlobalState.macroModeState;
+ if (registerName == '@') {
+ registerName = macroModeState.latestRegister;
+ }
+ var keyBuffer = parseRegisterToKeyBuffer(macroModeState, registerName);
+ while(repeat--){
+ executeMacroKeyBuffer(cm, macroModeState, keyBuffer);
+ }
+ },
+ exitMacroRecordMode: function() {
+ var macroModeState = vimGlobalState.macroModeState;
+ macroModeState.toggle();
+ parseKeyBufferToRegister(macroModeState.latestRegister,
+ macroModeState.macroKeyBuffer);
+ },
+ enterMacroRecordMode: function(cm, actionArgs) {
+ var macroModeState = vimGlobalState.macroModeState;
+ var registerName = actionArgs.selectedCharacter;
+ macroModeState.toggle(cm, registerName);
+ emptyMacroKeyBuffer(macroModeState);
+ },
+ enterInsertMode: function(cm, actionArgs, vim) {
+ if (cm.getOption('readOnly')) { return; }
+ vim.insertMode = true;
+ vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
if (insertAt == 'eol') {
var cursor = cm.getCursor();
@@ -1314,8 +1753,26 @@
cm.setCursor(cursor);
} else if (insertAt == 'charAfter') {
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
+ } else if (insertAt == 'firstNonBlank') {
+ cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
}
cm.setOption('keyMap', 'vim-insert');
+ cm.setOption('disableInput', false);
+ if (actionArgs && actionArgs.replace) {
+ // Handle Replace-mode as a special case of insert mode.
+ cm.toggleOverwrite(true);
+ cm.setOption('keyMap', 'vim-replace');
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"});
+ } else {
+ cm.setOption('keyMap', 'vim-insert');
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"});
+ }
+ if (!vimGlobalState.macroModeState.inReplay) {
+ // Only record if not replaying.
+ cm.on('change', onChange);
+ cm.on('cursorActivity', onCursorActivity);
+ CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
+ }
},
toggleVisualMode: function(cm, actionArgs, vim) {
var repeat = actionArgs.repeat;
@@ -1325,6 +1782,7 @@
// equal to the repeat times the size of the previous visual
// operation.
if (!vim.visualMode) {
+ cm.on('mousedown', exitVisualMode);
vim.visualMode = true;
vim.visualLine = !!actionArgs.linewise;
if (vim.visualLine) {
@@ -1349,6 +1807,7 @@
} else {
cm.setSelection(curStart, curEnd);
}
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : ""});
} else {
curStart = cm.getCursor('anchor');
curEnd = cm.getCursor('head');
@@ -1361,12 +1820,14 @@
curEnd.ch = cursorIsBefore(curStart, curEnd) ?
lineLength(cm, curEnd.line) : 0;
cm.setSelection(curStart, curEnd);
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: "linewise"});
} else if (vim.visualLine && !actionArgs.linewise) {
// v pressed in linewise visual mode. Switch to characterwise visual
// mode instead of exiting visual mode.
vim.visualLine = false;
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"});
} else {
- exitVisualMode(cm, vim);
+ exitVisualMode(cm);
}
}
updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
@@ -1401,7 +1862,8 @@
cm.setCursor(curFinalPos);
});
},
- newLineAndEnterInsertMode: function(cm, actionArgs) {
+ newLineAndEnterInsertMode: function(cm, actionArgs, vim) {
+ vim.insertMode = true;
var insertAt = cm.getCursor();
if (insertAt.line === cm.firstLine() && !actionArgs.after) {
// Special case for inserting newline before start of document.
@@ -1416,11 +1878,11 @@
CodeMirror.commands.newlineAndIndent;
newlineFn(cm);
}
- this.enterInsertMode(cm);
+ this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim);
},
- paste: function(cm, actionArgs, vim) {
+ paste: function(cm, actionArgs) {
var cur = cm.getCursor();
- var register = getVimGlobalState().registerController.getRegister(
+ var register = vimGlobalState.registerController.getRegister(
actionArgs.registerName);
if (!register.text) {
return;
@@ -1461,12 +1923,15 @@
cm.setCursor(curPosFinal);
},
undo: function(cm, actionArgs) {
- repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)();
+ cm.operation(function() {
+ repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)();
+ cm.setCursor(cm.getCursor('anchor'));
+ });
},
redo: function(cm, actionArgs) {
repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)();
},
- setRegister: function(cm, actionArgs, vim) {
+ setRegister: function(_cm, actionArgs, vim) {
vim.inputState.registerName = actionArgs.selectedCharacter;
},
setMark: function(cm, actionArgs, vim) {
@@ -1503,24 +1968,50 @@
cm.replaceRange(replaceWithStr, curStart, curEnd);
if(vim.visualMode){
cm.setCursor(curStart);
- exitVisualMode(cm,vim);
+ exitVisualMode(cm);
}else{
cm.setCursor(offsetCursor(curEnd, 0, -1));
}
}
},
- repeatLastEdit: function(cm, actionArgs, vim) {
- // TODO: Make this repeat insert mode changes.
- var lastEdit = vim.lastEdit;
- if (lastEdit) {
- if (actionArgs.repeat && actionArgs.repeatIsExplicit) {
- vim.lastEdit.repeatOverride = actionArgs.repeat;
- }
- var currentInputState = vim.inputState;
- vim.inputState = vim.lastEdit;
- commandDispatcher.evalInput(cm, vim);
- vim.inputState = currentInputState;
+ incrementNumberToken: function(cm, actionArgs) {
+ var cur = cm.getCursor();
+ var lineStr = cm.getLine(cur.line);
+ var re = /-?\d+/g;
+ var match;
+ var start;
+ var end;
+ var numberStr;
+ var token;
+ while ((match = re.exec(lineStr)) !== null) {
+ token = match[0];
+ start = match.index;
+ end = start + token.length;
+ if(cur.ch < end)break;
}
+ if(!actionArgs.backtrack && (end <= cur.ch))return;
+ if (token) {
+ var increment = actionArgs.increase ? 1 : -1;
+ var number = parseInt(token) + (increment * actionArgs.repeat);
+ var from = {ch:start, line:cur.line};
+ var to = {ch:end, line:cur.line};
+ numberStr = number.toString();
+ cm.replaceRange(numberStr, from, to);
+ } else {
+ return;
+ }
+ cm.setCursor({line: cur.line, ch: start + numberStr.length - 1});
+ },
+ repeatLastEdit: function(cm, actionArgs, vim) {
+ var lastEditInputState = vim.lastEditInputState;
+ if (!lastEditInputState) { return; }
+ var repeat = actionArgs.repeat;
+ if (repeat && actionArgs.repeatIsExplicit) {
+ vim.lastEditInputState.repeatOverride = repeat;
+ } else {
+ repeat = vim.lastEditInputState.repeatOverride || repeat;
+ }
+ repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */);
}
};
@@ -1549,7 +2040,7 @@
'\'': function(cm, inclusive) {
return findBeginningAndEnd(cm, "'", inclusive);
},
- '\"': function(cm, inclusive) {
+ '"': function(cm, inclusive) {
return findBeginningAndEnd(cm, '"', inclusive);
}
};
@@ -1569,14 +2060,6 @@
var ch = Math.min(Math.max(0, cur.ch), maxCh);
return { line: line, ch: ch };
}
- // Merge arguments in place, for overriding arguments.
- function mergeArgs(to, from) {
- for (var prop in from) {
- if (from.hasOwnProperty(prop)) {
- to[prop] = from[prop];
- }
- }
- }
function copyArgs(args) {
var ret = {};
for (var prop in args) {
@@ -1589,17 +2072,6 @@
function offsetCursor(cur, offsetLine, offsetCh) {
return { line: cur.line + offsetLine, ch: cur.ch + offsetCh };
}
- function arrayEq(a1, a2) {
- if (a1.length != a2.length) {
- return false;
- }
- for (var i = 0; i < a1.length; i++) {
- if (a1[i] != a2[i]) {
- return false;
- }
- }
- return true;
- }
function matchKeysPartial(pressed, mapped) {
for (var i = 0; i < pressed.length; i++) {
// 'character' means any character. For mark, register commads, etc.
@@ -1609,14 +2081,6 @@
}
return true;
}
- function arrayIsSubsetFromBeginning(small, big) {
- for (var i = 0; i < small.length; i++) {
- if (small[i] != big[i]) {
- return false;
- }
- }
- return true;
- }
function repeatFn(cm, fn, repeat) {
return function() {
for (var i = 0; i < repeat; i++) {
@@ -1633,7 +2097,8 @@
function cursorIsBefore(cur1, cur2) {
if (cur1.line < cur2.line) {
return true;
- } else if (cur1.line == cur2.line && cur1.ch < cur2.ch) {
+ }
+ if (cur1.line == cur2.line && cur1.ch < cur2.ch) {
return true;
}
return false;
@@ -1648,20 +2113,21 @@
return cm.getLine(lineNum).length;
}
function reverse(s){
- return s.split("").reverse().join("");
+ return s.split('').reverse().join('');
}
function trim(s) {
if (s.trim) {
return s.trim();
- } else {
- return s.replace(/^\s+|\s+$/g, '');
}
+ return s.replace(/^\s+|\s+$/g, '');
}
function escapeRegex(s) {
- return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, "\\$1");
+ return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
}
- function exitVisualMode(cm, vim) {
+ function exitVisualMode(cm) {
+ cm.off('mousedown', exitVisualMode);
+ var vim = cm.state.vim;
vim.visualMode = false;
vim.visualLine = false;
var selectionStart = cm.getCursor('anchor');
@@ -1672,6 +2138,7 @@
// it's not supposed to be.
cm.setCursor(clipCursorToContent(cm, selectionEnd));
}
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
}
// Remove any trailing newlines from the selection. For
@@ -1680,15 +2147,34 @@
// caret to the first character of the next line.
function clipToLine(cm, curStart, curEnd) {
var selection = cm.getRange(curStart, curEnd);
- var lines = selection.split('\n');
- if (lines.length > 1 && isWhiteSpaceString(lines.pop())) {
- curEnd.line--;
- curEnd.ch = lineLength(cm, curEnd.line);
+ // Only clip if the selection ends with trailing newline + whitespace
+ if (/\n\s*$/.test(selection)) {
+ var lines = selection.split('\n');
+ // We know this is all whitepsace.
+ lines.pop();
+
+ // Cases:
+ // 1. Last word is an empty line - do not clip the trailing '\n'
+ // 2. Last word is not an empty line - clip the trailing '\n'
+ var line;
+ // Find the line containing the last word, and clip all whitespace up
+ // to it.
+ for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) {
+ curEnd.line--;
+ curEnd.ch = 0;
+ }
+ // If the last word is not an empty line, clip an additional newline
+ if (line) {
+ curEnd.line--;
+ curEnd.ch = lineLength(cm, curEnd.line);
+ } else {
+ curEnd.ch = 0;
+ }
}
}
// Expand the selection to line ends.
- function expandSelectionToLine(cm, curStart, curEnd) {
+ function expandSelectionToLine(_cm, curStart, curEnd) {
curStart.ch = 0;
curEnd.ch = 0;
curEnd.line++;
@@ -1702,7 +2188,7 @@
return firstNonWS == -1 ? text.length : firstNonWS;
}
- function expandWordUnderCursor(cm, inclusive, forward, bigWord, noSymbol) {
+ function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) {
var cur = cm.getCursor();
var line = cm.getLine(cur.line);
var idx = cur.ch;
@@ -1737,21 +2223,166 @@
var wordAfterRegex = matchRegex.exec(textAfterIdx);
var wordStart = idx;
- var wordEnd = idx + wordAfterRegex[0].length - 1;
+ var wordEnd = idx + wordAfterRegex[0].length;
// TODO: Find a better way to do this. It will be slow on very long lines.
- var wordBeforeRegex = matchRegex.exec(reverse(textBeforeIdx));
+ var revTextBeforeIdx = reverse(textBeforeIdx);
+ var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx);
if (wordBeforeRegex) {
wordStart -= wordBeforeRegex[0].length;
}
if (inclusive) {
- wordEnd++;
+ // If present, trim all whitespace after word.
+ // Otherwise, trim all whitespace before word.
+ var textAfterWordEnd = line.substring(wordEnd);
+ var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length;
+ if (whitespacesAfterWord > 0) {
+ wordEnd += whitespacesAfterWord;
+ } else {
+ var revTrim = revTextBeforeIdx.length - wordStart;
+ var textBeforeWordStart = revTextBeforeIdx.substring(revTrim);
+ var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length;
+ wordStart -= whitespacesBeforeWord;
+ }
}
return { start: { line: cur.line, ch: wordStart },
end: { line: cur.line, ch: wordEnd }};
}
+ function recordJumpPosition(cm, oldCur, newCur) {
+ if(!cursorEqual(oldCur, newCur)) {
+ vimGlobalState.jumpList.add(cm, oldCur, newCur);
+ }
+ }
+
+ function recordLastCharacterSearch(increment, args) {
+ vimGlobalState.lastChararacterSearch.increment = increment;
+ vimGlobalState.lastChararacterSearch.forward = args.forward;
+ vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter;
+ }
+
+ var symbolToMode = {
+ '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket',
+ '[': 'section', ']': 'section',
+ '*': 'comment', '/': 'comment',
+ 'm': 'method', 'M': 'method',
+ '#': 'preprocess'
+ };
+ var findSymbolModes = {
+ bracket: {
+ isComplete: function(state) {
+ if (state.nextCh === state.symb) {
+ state.depth++;
+ if(state.depth >= 1)return true;
+ } else if (state.nextCh === state.reverseSymb) {
+ state.depth--;
+ }
+ return false;
+ }
+ },
+ section: {
+ init: function(state) {
+ state.curMoveThrough = true;
+ state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}';
+ },
+ isComplete: function(state) {
+ return state.index === 0 && state.nextCh === state.symb;
+ }
+ },
+ comment: {
+ isComplete: function(state) {
+ var found = state.lastCh === '*' && state.nextCh === '/';
+ state.lastCh = state.nextCh;
+ return found;
+ }
+ },
+ // TODO: The original Vim implementation only operates on level 1 and 2.
+ // The current implementation doesn't check for code block level and
+ // therefore it operates on any levels.
+ method: {
+ init: function(state) {
+ state.symb = (state.symb === 'm' ? '{' : '}');
+ state.reverseSymb = state.symb === '{' ? '}' : '{';
+ },
+ isComplete: function(state) {
+ if(state.nextCh === state.symb)return true;
+ return false;
+ }
+ },
+ preprocess: {
+ init: function(state) {
+ state.index = 0;
+ },
+ isComplete: function(state) {
+ if (state.nextCh === '#') {
+ var token = state.lineText.match(/#(\w+)/)[1];
+ if (token === 'endif') {
+ if (state.forward && state.depth === 0) {
+ return true;
+ }
+ state.depth++;
+ } else if (token === 'if') {
+ if (!state.forward && state.depth === 0) {
+ return true;
+ }
+ state.depth--;
+ }
+ if(token === 'else' && state.depth === 0)return true;
+ }
+ return false;
+ }
+ }
+ };
+ function findSymbol(cm, repeat, forward, symb) {
+ var cur = cm.getCursor();
+ var increment = forward ? 1 : -1;
+ var endLine = forward ? cm.lineCount() : -1;
+ var curCh = cur.ch;
+ var line = cur.line;
+ var lineText = cm.getLine(line);
+ var state = {
+ lineText: lineText,
+ nextCh: lineText.charAt(curCh),
+ lastCh: null,
+ index: curCh,
+ symb: symb,
+ reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb],
+ forward: forward,
+ depth: 0,
+ curMoveThrough: false
+ };
+ var mode = symbolToMode[symb];
+ if(!mode)return cur;
+ var init = findSymbolModes[mode].init;
+ var isComplete = findSymbolModes[mode].isComplete;
+ if(init)init(state);
+ while (line !== endLine && repeat) {
+ state.index += increment;
+ state.nextCh = state.lineText.charAt(state.index);
+ if (!state.nextCh) {
+ line += increment;
+ state.lineText = cm.getLine(line) || '';
+ if (increment > 0) {
+ state.index = 0;
+ } else {
+ var lineLen = state.lineText.length;
+ state.index = (lineLen > 0) ? (lineLen-1) : 0;
+ }
+ state.nextCh = state.lineText.charAt(state.index);
+ }
+ if (isComplete(state)) {
+ cur.line = line;
+ cur.ch = state.index;
+ repeat--;
+ }
+ }
+ if (state.nextCh || state.curMoveThrough) {
+ return { line: line, ch: state.index };
+ }
+ return cur;
+ }
+
/*
* Returns the boundaries of the next word. If the cursor in the middle of
* the word, then returns the boundaries of the current word, starting at
@@ -1764,18 +2395,31 @@
* backward.
* @param {boolean} bigWord True if punctuation count as part of the word.
* False if only [a-zA-Z0-9] characters count as part of the word.
+ * @param {boolean} emptyLineIsWord True if empty lines should be treated
+ * as words.
* @return {Object{from:number, to:number, line: number}} The boundaries of
* the word, or null if there are no more words.
*/
- // TODO: Treat empty lines (with no whitespace) as words.
- function findWord(cm, cur, forward, bigWord) {
+ function findWord(cm, cur, forward, bigWord, emptyLineIsWord) {
var lineNum = cur.line;
var pos = cur.ch;
var line = cm.getLine(lineNum);
var dir = forward ? 1 : -1;
var regexps = bigWord ? bigWordRegexp : wordRegexp;
+ if (emptyLineIsWord && line == '') {
+ lineNum += dir;
+ line = cm.getLine(lineNum);
+ if (!isLine(cm, lineNum)) {
+ return null;
+ }
+ pos = (forward) ? 0 : line.length;
+ }
+
while (true) {
+ if (emptyLineIsWord && line == '') {
+ return { from: 0, to: 0, line: lineNum };
+ }
var stop = (dir > 0) ? line.length : -1;
var wordStart = stop, wordEnd = stop;
// Find bounds of next word.
@@ -1815,7 +2459,7 @@
pos = (dir > 0) ? 0 : line.length;
}
// Should never get here.
- throw 'The impossible happened.';
+ throw new Error('The impossible happened.');
}
/**
@@ -1831,56 +2475,48 @@
*/
function moveToWord(cm, repeat, forward, wordEnd, bigWord) {
var cur = cm.getCursor();
- for (var i = 0; i < repeat; i++) {
- var startCh = cur.ch, startLine = cur.line, word;
- var movedToNextWord = false;
- while (!movedToNextWord) {
- // Search and advance.
- word = findWord(cm, cur, forward, bigWord);
- movedToNextWord = true;
- if (word) {
- // Move to the word we just found. If by moving to the word we end
- // up in the same spot, then move an extra character and search
- // again.
- cur.line = word.line;
- if (forward && wordEnd) {
- // 'e'
- cur.ch = word.to - 1;
- } else if (forward && !wordEnd) {
- // 'w'
- if (inRangeInclusive(cur.ch, word.from, word.to) &&
- word.line == startLine) {
- // Still on the same word. Go to the next one.
- movedToNextWord = false;
- cur.ch = word.to - 1;
- } else {
- cur.ch = word.from;
- }
- } else if (!forward && wordEnd) {
- // 'ge'
- if (inRangeInclusive(cur.ch, word.from, word.to) &&
- word.line == startLine) {
- // still on the same word. Go to the next one.
- movedToNextWord = false;
- cur.ch = word.from;
- } else {
- cur.ch = word.to;
- }
- } else if (!forward && !wordEnd) {
- // 'b'
- cur.ch = word.from;
- }
- } else {
- // No more words to be found. Move to the end.
- if (forward) {
- return { line: cur.line, ch: lineLength(cm, cur.line) };
- } else {
- return { line: cur.line, ch: 0 };
- }
- }
- }
+ var curStart = copyCursor(cur);
+ var words = [];
+ if (forward && !wordEnd || !forward && wordEnd) {
+ repeat++;
+ }
+ // For 'e', empty lines are not considered words, go figure.
+ var emptyLineIsWord = !(forward && wordEnd);
+ for (var i = 0; i < repeat; i++) {
+ var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord);
+ if (!word) {
+ var eodCh = lineLength(cm, cm.lastLine());
+ words.push(forward
+ ? {line: cm.lastLine(), from: eodCh, to: eodCh}
+ : {line: 0, from: 0, to: 0});
+ break;
+ }
+ words.push(word);
+ cur = {line: word.line, ch: forward ? (word.to - 1) : word.from};
+ }
+ var shortCircuit = words.length != repeat;
+ var firstWord = words[0];
+ var lastWord = words.pop();
+ if (forward && !wordEnd) {
+ // w
+ if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) {
+ // We did not start in the middle of a word. Discard the extra word at the end.
+ lastWord = words.pop();
+ }
+ return {line: lastWord.line, ch: lastWord.from};
+ } else if (forward && wordEnd) {
+ return {line: lastWord.line, ch: lastWord.to - 1};
+ } else if (!forward && wordEnd) {
+ // ge
+ if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) {
+ // We did not start in the middle of a word. Discard the extra word at the end.
+ lastWord = words.pop();
+ }
+ return {line: lastWord.line, ch: lastWord.to};
+ } else {
+ // b
+ return {line: lastWord.line, ch: lastWord.from};
}
- return cur;
}
function moveToCharacter(cm, repeat, forward, character) {
@@ -1936,12 +2572,17 @@
return idx;
}
+ function getContextLevel(ctx) {
+ return (ctx === 'string' || ctx === 'comment') ? 1 : 0;
+ }
+
function findMatchedSymbol(cm, cur, symb) {
var line = cur.line;
- symb = symb ? symb : cm.getLine(line).charAt(cur.ch);
+ var ch = cur.ch;
+ symb = symb ? symb : cm.getLine(line).charAt(ch);
- // Are we at the opening or closing char
- var forwards = inArray(symb, ['(', '[', '{']);
+ var symbContext = cm.getTokenAt({line:line, ch:ch+1}).type;
+ var symbCtxLevel = getContextLevel(symbContext);
var reverseSymb = ({
'(': ')', ')': '(',
@@ -1956,12 +2597,13 @@
// set our increment to move forward (+1) or backwards (-1)
// depending on which bracket we're matching
var increment = ({'(': 1, '{': 1, '[': 1})[symb] || -1;
- var depth = 1, nextCh = symb, index = cur.ch, lineText = cm.getLine(line);
+ var endLine = increment === 1 ? cm.lineCount() : -1;
+ var depth = 1, nextCh = symb, index = ch, lineText = cm.getLine(line);
// Simple search for closing paren--just count openings and closings till
// we find our match
// TODO: use info from CodeMirror to ignore closing brackets in comments
// and quotes, etc.
- while (nextCh && depth > 0) {
+ while (line !== endLine && depth > 0) {
index += increment;
nextCh = lineText.charAt(index);
if (!nextCh) {
@@ -1975,10 +2617,14 @@
}
nextCh = lineText.charAt(index);
}
- if (nextCh === symb) {
- depth++;
- } else if (nextCh === reverseSymb) {
- depth--;
+ var revSymbContext = cm.getTokenAt({line:line, ch:index+1}).type;
+ var revSymbCtxLevel = getContextLevel(revSymbContext);
+ if (symbCtxLevel >= revSymbCtxLevel) {
+ if (nextCh === symb) {
+ depth++;
+ } else if (nextCh === reverseSymb) {
+ depth--;
+ }
}
}
@@ -1999,16 +2645,6 @@
return { start: start, end: end };
}
- function regexLastIndexOf(string, pattern, startIndex) {
- for (var i = !startIndex ? string.length : startIndex;
- i >= 0; --i) {
- if (pattern.test(string.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
// Takes in a symbol and a cursor and tries to simulate text objects that
// have identical opening and closing symbols
// TODO support across multiple lines
@@ -2074,10 +2710,10 @@
function SearchState() {}
SearchState.prototype = {
getQuery: function() {
- return getVimGlobalState().query;
+ return vimGlobalState.query;
},
setQuery: function(query) {
- getVimGlobalState().query = query;
+ vimGlobalState.query = query;
},
getOverlay: function() {
return this.searchOverlay;
@@ -2086,14 +2722,14 @@
this.searchOverlay = overlay;
},
isReversed: function() {
- return getVimGlobalState().isReversed;
+ return vimGlobalState.isReversed;
},
setReversed: function(reversed) {
- getVimGlobalState().isReversed = reversed;
+ vimGlobalState.isReversed = reversed;
}
};
function getSearchState(cm) {
- var vim = getVimState(cm);
+ var vim = cm.state.vim;
return vim.searchState_ || (vim.searchState_ = new SearchState());
}
function dialog(cm, template, shortText, onClose, options) {
@@ -2102,9 +2738,10 @@
onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp });
}
else {
- callback(prompt(shortText, ""));
+ onClose(prompt(shortText, ''));
}
}
+
function findUnescapedSlashes(str) {
var escapeNextChar = false;
var slashes = [];
@@ -2127,7 +2764,7 @@
* then both ignoreCase and smartCase are ignored, and 'i' will be passed
* through to the Regex object.
*/
- function parseQuery(cm, query, ignoreCase, smartCase) {
+ function parseQuery(query, ignoreCase, smartCase) {
// Check if the query is already a regex.
if (query instanceof RegExp) { return query; }
// First try to extract regex + flags from the input. If no flags found,
@@ -2156,10 +2793,9 @@
return regexp;
}
function showConfirm(cm, text) {
- if (cm.openConfirm) {
- cm.openConfirm('' + text +
- ' OK ', function() {},
- {bottom: true});
+ if (cm.openNotification) {
+ cm.openNotification('' + text + ' ',
+ {bottom: true, duration: 5000});
} else {
alert(text);
}
@@ -2186,16 +2822,16 @@
}
function regexEqual(r1, r2) {
if (r1 instanceof RegExp && r2 instanceof RegExp) {
- var props = ["global", "multiline", "ignoreCase", "source"];
+ var props = ['global', 'multiline', 'ignoreCase', 'source'];
for (var i = 0; i < props.length; i++) {
var prop = props[i];
if (r1[prop] !== r2[prop]) {
- return(false);
+ return false;
}
}
- return(true);
+ return true;
}
- return(false);
+ return false;
}
// Returns true if the query is valid.
function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) {
@@ -2203,7 +2839,7 @@
return;
}
var state = getSearchState(cm);
- var query = parseQuery(cm, rawQuery, !!ignoreCase, !!smartCase);
+ var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase);
if (!query) {
return;
}
@@ -2229,7 +2865,7 @@
if (match[0].length == 0) {
// Matched empty string, skip to next.
stream.next();
- return;
+ return 'searching';
}
if (!stream.sol()) {
// Backtrack 1 to match \b
@@ -2240,7 +2876,7 @@
}
}
stream.match(query);
- return "searching";
+ return 'searching';
}
while (!stream.eol()) {
stream.next();
@@ -2265,12 +2901,11 @@
if (repeat === undefined) { repeat = 1; }
return cm.operation(function() {
var pos = cm.getCursor();
- if (!prev) {
- pos.ch += 1;
- }
var cursor = cm.getSearchCursor(query, pos);
for (var i = 0; i < repeat; i++) {
- if (!cursor.find(prev)) {
+ var found = cursor.find(prev);
+ if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); }
+ if (!found) {
// SearchCursor may have returned null because it hit EOF, wrap
// around and try again.
cursor = cm.getSearchCursor(query,
@@ -2281,7 +2916,8 @@
}
}
return cursor.from();
- });}
+ });
+ }
function clearSearchHighlight(cm) {
cm.removeOverlay(getSearchState(cm).getOverlay());
getSearchState(cm).setOverlay(null);
@@ -2312,25 +2948,41 @@
}
}
}
+ function getUserVisibleLines(cm) {
+ var scrollInfo = cm.getScrollInfo();
+ var occludeToleranceTop = 6;
+ var occludeToleranceBottom = 10;
+ var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local');
+ var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top;
+ var to = cm.coordsChar({left:0, top: bottomY}, 'local');
+ return {top: from.line, bottom: to.line};
+ }
// Ex command handling
// Care must be taken when adding to the default Ex command map. For any
// pair of commands that have a shared prefix, at least one of their
// shortNames must not match the prefix of the other command.
var defaultExCommandMap = [
- { name: 'map', type: 'builtIn' },
- { name: 'write', shortName: 'w', type: 'builtIn' },
- { name: 'undo', shortName: 'u', type: 'builtIn' },
- { name: 'redo', shortName: 'red', type: 'builtIn' },
- { name: 'substitute', shortName: 's', type: 'builtIn'},
- { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'},
- { name: 'delmarks', shortName: 'delm', type: 'builtin'}
+ { name: 'map' },
+ { name: 'nmap', shortName: 'nm' },
+ { name: 'vmap', shortName: 'vm' },
+ { name: 'write', shortName: 'w' },
+ { name: 'undo', shortName: 'u' },
+ { name: 'redo', shortName: 'red' },
+ { name: 'sort', shortName: 'sor' },
+ { name: 'substitute', shortName: 's' },
+ { name: 'nohlsearch', shortName: 'noh' },
+ { name: 'delmarks', shortName: 'delm' }
];
Vim.ExCommandDispatcher = function() {
this.buildCommandMap_();
};
Vim.ExCommandDispatcher.prototype = {
processCommand: function(cm, input) {
+ var vim = cm.state.vim;
+ if (vim.visualMode) {
+ exitVisualMode(cm);
+ }
var inputStream = new CodeMirror.StringStream(input);
var params = {};
params.input = input;
@@ -2354,7 +3006,7 @@
if (command.type == 'exToKey') {
// Handle Ex to Key mapping.
for (var i = 0; i < command.toKeys.length; i++) {
- vim.handleKey(cm, command.toKeys[i]);
+ CodeMirror.Vim.handleKey(cm, command.toKeys[i]);
}
return;
} else if (command.type == 'exToEx') {
@@ -2368,7 +3020,12 @@
showConfirm(cm, 'Not an editor command ":' + input + '"');
return;
}
- exCommands[commandName](cm, params);
+ try {
+ exCommands[commandName](cm, params);
+ } catch(e) {
+ showConfirm(cm, e);
+ throw e;
+ }
},
parseInput_: function(cm, inputStream, result) {
inputStream.eatWhile(':');
@@ -2404,16 +3061,14 @@
case '$':
return cm.lastLine();
case '\'':
- var mark = getVimState(cm).marks[inputStream.next()];
+ var mark = cm.state.vim.marks[inputStream.next()];
if (mark && mark.find()) {
return mark.find().line;
- } else {
- throw "Mark not set";
}
- break;
+ throw new Error('Mark not set');
default:
inputStream.backUp(1);
- return cm.getCursor().line;
+ return undefined;
}
},
parseCommandArgs_: function(inputStream, params, command) {
@@ -2452,8 +3107,9 @@
this.commandMap_[key] = command;
}
},
- map: function(lhs, rhs) {
+ map: function(lhs, rhs, ctx) {
if (lhs != ':' && lhs.charAt(0) == ':') {
+ if (ctx) { throw Error('Mode not supported for ex mappings'); }
var commandName = lhs.substring(1);
if (rhs != ':' && rhs.charAt(0) == ':') {
// Ex to Ex mapping
@@ -2473,17 +3129,21 @@
} else {
if (rhs != ':' && rhs.charAt(0) == ':') {
// Key to Ex mapping.
- defaultKeymap.unshift({
+ var mapping = {
keys: parseKeyString(lhs),
type: 'keyToEx',
- exArgs: { input: rhs.substring(1) }});
+ exArgs: { input: rhs.substring(1) }};
+ if (ctx) { mapping.context = ctx; }
+ defaultKeymap.unshift(mapping);
} else {
// Key to key mapping
- defaultKeymap.unshift({
+ var mapping = {
keys: parseKeyString(lhs),
type: 'keyToKey',
toKeys: parseKeyString(rhs)
- });
+ };
+ if (ctx) { mapping.context = ctx; }
+ defaultKeymap.unshift(mapping);
}
}
}
@@ -2492,47 +3152,20 @@
// Converts a key string sequence of the form abd into Vim's
// keymap representation.
function parseKeyString(str) {
- var idx = 0;
+ var key, match;
var keys = [];
- while (idx < str.length) {
- if (str.charAt(idx) != '<') {
- keys.push(str.charAt(idx));
- idx++;
- continue;
- }
- // Vim key notation here means desktop Vim key-notation.
- // See :help key-notation in desktop Vim.
- var vimKeyNotationStart = ++idx;
- while (str.charAt(idx++) != '>') {}
- var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1);
- var mod='';
- var match = (/^C-(.+)$/).exec(vimKeyNotation);
- if (match) {
- mod='Ctrl-';
- vimKeyNotation=match[1];
- }
- var key;
- switch (vimKeyNotation) {
- case 'BS':
- key = 'Backspace';
- break;
- case 'CR':
- key = 'Enter';
- break;
- case 'Del':
- key = 'Delete';
- break;
- default:
- key = vimKeyNotation;
- break;
- }
- keys.push(mod + key);
+ while (str) {
+ match = (/<\w+-.+?>|<\w+>|./).exec(str);
+ if(match === null)break;
+ key = match[0];
+ str = str.substring(match.index + key.length);
+ keys.push(key);
}
return keys;
}
var exCommands = {
- map: function(cm, params) {
+ map: function(cm, params, ctx) {
var mapArgs = params.args;
if (!mapArgs || mapArgs.length < 2) {
if (cm) {
@@ -2540,17 +3173,98 @@
}
return;
}
- exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
+ exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);
},
+ nmap: function(cm, params) { this.map(cm, params, 'normal'); },
+ vmap: function(cm, params) { this.map(cm, params, 'visual'); },
move: function(cm, params) {
- commandDispatcher.processCommand(cm, getVimState(cm), {
+ commandDispatcher.processCommand(cm, cm.state.vim, {
type: 'motion',
motion: 'moveToLineOrEdgeOfDocument',
motionArgs: { forward: false, explicitRepeat: true,
linewise: true },
repeatOverride: params.line+1});
},
+ sort: function(cm, params) {
+ var reverse, ignoreCase, unique, number;
+ function parseArgs() {
+ if (params.argString) {
+ var args = new CodeMirror.StringStream(params.argString);
+ if (args.eat('!')) { reverse = true; }
+ if (args.eol()) { return; }
+ if (!args.eatSpace()) { return 'Invalid arguments'; }
+ var opts = args.match(/[a-z]+/);
+ if (opts) {
+ opts = opts[0];
+ ignoreCase = opts.indexOf('i') != -1;
+ unique = opts.indexOf('u') != -1;
+ var decimal = opts.indexOf('d') != -1 && 1;
+ var hex = opts.indexOf('x') != -1 && 1;
+ var octal = opts.indexOf('o') != -1 && 1;
+ if (decimal + hex + octal > 1) { return 'Invalid arguments'; }
+ number = decimal && 'decimal' || hex && 'hex' || octal && 'octal';
+ }
+ if (args.eatSpace() && args.match(/\/.*\//)) { 'patterns not supported'; }
+ }
+ }
+ var err = parseArgs();
+ if (err) {
+ showConfirm(cm, err + ': ' + params.argString);
+ return;
+ }
+ var lineStart = params.line || cm.firstLine();
+ var lineEnd = params.lineEnd || params.line || cm.lastLine();
+ if (lineStart == lineEnd) { return; }
+ var curStart = { line: lineStart, ch: 0 };
+ var curEnd = { line: lineEnd, ch: lineLength(cm, lineEnd) };
+ var text = cm.getRange(curStart, curEnd).split('\n');
+ var numberRegex = (number == 'decimal') ? /(-?)([\d]+)/ :
+ (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i :
+ (number == 'octal') ? /([0-7]+)/ : null;
+ var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null;
+ var numPart = [], textPart = [];
+ if (number) {
+ for (var i = 0; i < text.length; i++) {
+ if (numberRegex.exec(text[i])) {
+ numPart.push(text[i]);
+ } else {
+ textPart.push(text[i]);
+ }
+ }
+ } else {
+ textPart = text;
+ }
+ function compareFn(a, b) {
+ if (reverse) { var tmp; tmp = a; a = b; b = tmp; }
+ if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); }
+ var anum = number && numberRegex.exec(a);
+ var bnum = number && numberRegex.exec(b);
+ if (!anum) { return a < b ? -1 : 1; }
+ anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix);
+ bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix);
+ return anum - bnum;
+ }
+ numPart.sort(compareFn);
+ textPart.sort(compareFn);
+ text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart);
+ if (unique) { // Remove duplicate lines
+ var textOld = text;
+ var lastLine;
+ text = [];
+ for (var i = 0; i < textOld.length; i++) {
+ if (textOld[i] != lastLine) {
+ text.push(textOld[i]);
+ }
+ lastLine = textOld[i];
+ }
+ }
+ cm.replaceRange(text.join('\n'), curStart, curEnd);
+ },
substitute: function(cm, params) {
+ if (!cm.getSearchCursor) {
+ throw new Error('Search feature not available. Requires searchcursor.js or ' +
+ 'any other getSearchCursor implementation.');
+ }
var argString = params.argString;
var slashes = findUnescapedSlashes(argString);
if (slashes[0] !== 0) {
@@ -2562,6 +3276,7 @@
var replacePart = '';
var flagsPart;
var count;
+ var confirm = false; // Whether to confirm each replace.
if (slashes[1]) {
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
}
@@ -2573,6 +3288,10 @@
count = parseInt(trailing[1]);
}
if (flagsPart) {
+ if (flagsPart.indexOf('c') != -1) {
+ confirm = true;
+ flagsPart.replace('c', '');
+ }
regexPart = regexPart + '/' + flagsPart;
}
if (regexPart) {
@@ -2588,27 +3307,15 @@
}
var state = getSearchState(cm);
var query = state.getQuery();
- var lineStart = params.line || cm.firstLine();
+ var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line;
var lineEnd = params.lineEnd || lineStart;
if (count) {
lineStart = lineEnd;
lineEnd = lineStart + count - 1;
}
var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
- function doReplace() {
- for (var cursor = cm.getSearchCursor(query, startPos);
- cursor.findNext() &&
- isInRange(cursor.from(), lineStart, lineEnd);) {
- var text = cm.getRange(cursor.from(), cursor.to());
- var newText = text.replace(query, replacePart);
- cursor.replace(newText);
- }
- var vim = getVimState(cm);
- if (vim.visualMode) {
- exitVisualMode(cm, vim);
- }
- }
- cm.operation(doReplace);
+ var cursor = cm.getSearchCursor(query, startPos);
+ doReplace(cm, confirm, lineStart, lineEnd, cursor, query, replacePart);
},
redo: CodeMirror.commands.redo,
undo: CodeMirror.commands.undo,
@@ -2625,13 +3332,13 @@
clearSearchHighlight(cm);
},
delmarks: function(cm, params) {
- if (!params.argString || !params.argString.trim()) {
+ if (!params.argString || !trim(params.argString)) {
showConfirm(cm, 'Argument required');
return;
}
- var state = getVimState(cm);
- var stream = new CodeMirror.StringStream(params.argString.trim());
+ var state = cm.state.vim;
+ var stream = new CodeMirror.StringStream(trim(params.argString));
while (!stream.eol()) {
stream.eatSpace();
@@ -2676,7 +3383,7 @@
delete state.marks[mark];
}
} else {
- showConfirm(cm, 'Invalid argument: ' + startMark + "-");
+ showConfirm(cm, 'Invalid argument: ' + startMark + '-');
return;
}
} else {
@@ -2689,6 +3396,98 @@
var exCommandDispatcher = new Vim.ExCommandDispatcher();
+ /**
+ * @param {CodeMirror} cm CodeMirror instance we are in.
+ * @param {boolean} confirm Whether to confirm each replace.
+ * @param {Cursor} lineStart Line to start replacing from.
+ * @param {Cursor} lineEnd Line to stop replacing at.
+ * @param {RegExp} query Query for performing matches with.
+ * @param {string} replaceWith Text to replace matches with. May contain $1,
+ * $2, etc for replacing captured groups using Javascript replace.
+ */
+ function doReplace(cm, confirm, lineStart, lineEnd, searchCursor, query,
+ replaceWith) {
+ // Set up all the functions.
+ cm.state.vim.exMode = true;
+ var done = false;
+ var lastPos = searchCursor.from();
+ function replaceAll() {
+ cm.operation(function() {
+ while (!done) {
+ replace();
+ next();
+ }
+ stop();
+ });
+ }
+ function replace() {
+ var text = cm.getRange(searchCursor.from(), searchCursor.to());
+ var newText = text.replace(query, replaceWith);
+ searchCursor.replace(newText);
+ }
+ function next() {
+ var found = searchCursor.findNext();
+ if (!found) {
+ done = true;
+ } else if (isInRange(searchCursor.from(), lineStart, lineEnd)) {
+ cm.scrollIntoView(searchCursor.from(), 30);
+ cm.setSelection(searchCursor.from(), searchCursor.to());
+ lastPos = searchCursor.from();
+ done = false;
+ } else {
+ done = true;
+ }
+ }
+ function stop(close) {
+ if (close) { close(); }
+ cm.focus();
+ if (lastPos) {
+ cm.setCursor(lastPos);
+ var vim = cm.state.vim;
+ vim.exMode = false;
+ vim.lastHPos = vim.lastHSPos = lastPos.ch;
+ }
+ }
+ function onPromptKeyDown(e, _value, close) {
+ // Swallow all keys.
+ CodeMirror.e_stop(e);
+ var keyName = CodeMirror.keyName(e);
+ switch (keyName) {
+ case 'Y':
+ replace(); next(); break;
+ case 'N':
+ next(); break;
+ case 'A':
+ cm.operation(replaceAll); break;
+ case 'L':
+ replace();
+ // fall through and exit.
+ case 'Q':
+ case 'Esc':
+ case 'Ctrl-C':
+ case 'Ctrl-[':
+ stop(close);
+ break;
+ }
+ if (done) { stop(close); }
+ }
+
+ // Actually do replace.
+ next();
+ if (done) {
+ showConfirm(cm, 'No matches for ' + query.source);
+ return;
+ }
+ if (!confirm) {
+ replaceAll();
+ return;
+ }
+ showPrompt(cm, {
+ prefix: 'replace with ' + replaceWith + ' (y/n/a/q/l)',
+ onKeyDown: onPromptKeyDown
+ });
+ }
+
// Register Vim with CodeMirror
function buildVimKeyMap() {
/**
@@ -2697,33 +3496,36 @@
* modifers.
*/
// TODO: Figure out a way to catch capslock.
- function handleKeyEvent_(cm, key, modifier) {
- if (isUpperCase(key)) {
+ function cmKeyToVimKey(key, modifier) {
+ var vimKey = key;
+ if (isUpperCase(vimKey)) {
// Convert to lower case if shift is not the modifier since the key
// we get from CodeMirror is always upper case.
if (modifier == 'Shift') {
modifier = null;
}
else {
- key = key.toLowerCase();
+ vimKey = vimKey.toLowerCase();
}
}
if (modifier) {
// Vim will parse modifier+key combination as a single key.
- key = modifier + '-' + key;
+ vimKey = modifier.charAt(0) + '-' + vimKey;
}
- vim.handleKey(cm, key);
+ var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[vimKey];
+ vimKey = specialKey ? specialKey : vimKey;
+ vimKey = vimKey.length > 1 ? '<'+ vimKey + '>' : vimKey;
+ return vimKey;
}
// Closure to bind CodeMirror, key, modifier.
- function keyMapper(key, modifier) {
+ function keyMapper(vimKey) {
return function(cm) {
- handleKeyEvent_(cm, key, modifier);
+ CodeMirror.Vim.handleKey(cm, vimKey);
};
}
- var modifiers = ['Shift', 'Ctrl'];
- var keyMap = {
+ var cmToVimKeymap = {
'nofallthrough': true,
'style': 'fat-cursor'
};
@@ -2735,11 +3537,9 @@
// them.
key = "'" + key + "'";
}
- if (modifier) {
- keyMap[modifier + '-' + key] = keyMapper(keys[i], modifier);
- } else {
- keyMap[key] = keyMapper(keys[i]);
- }
+ var vimKey = cmKeyToVimKey(keys[i], modifier);
+ var cmKey = modifier ? modifier + '-' + key : key;
+ cmToVimKeymap[cmKey] = keyMapper(vimKey);
}
}
bindKeys(upperCaseAlphabet);
@@ -2751,13 +3551,31 @@
bindKeys(numbers, 'Ctrl');
bindKeys(specialKeys);
bindKeys(specialKeys, 'Ctrl');
- return keyMap;
+ return cmToVimKeymap;
}
CodeMirror.keyMap.vim = buildVimKeyMap();
function exitInsertMode(cm) {
+ var vim = cm.state.vim;
+ var inReplay = vimGlobalState.macroModeState.inReplay;
+ if (!inReplay) {
+ cm.off('change', onChange);
+ cm.off('cursorActivity', onCursorActivity);
+ CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
+ }
+ if (!inReplay && vim.insertModeRepeat > 1) {
+ // Perform insert mode repeat for commands like 3,a and 3,o.
+ repeatLastEdit(cm, vim, vim.insertModeRepeat - 1,
+ true /** repeatForInsert */);
+ vim.lastEditInputState.repeatOverride = vim.insertModeRepeat;
+ }
+ delete vim.insertModeRepeat;
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
+ vim.insertMode = false;
cm.setOption('keyMap', 'vim');
+ cm.setOption('disableInput', true);
+ cm.toggleOverwrite(false); // exit replace mode if we were in it.
+ CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
}
CodeMirror.keyMap['vim-insert'] = {
@@ -2776,10 +3594,192 @@
fallthrough: ['default']
};
+ CodeMirror.keyMap['vim-replace'] = {
+ 'Backspace': 'goCharLeft',
+ fallthrough: ['vim-insert']
+ };
+
+ function parseRegisterToKeyBuffer(macroModeState, registerName) {
+ var match, key;
+ var register = vimGlobalState.registerController.getRegister(registerName);
+ var text = register.toString();
+ var macroKeyBuffer = macroModeState.macroKeyBuffer;
+ emptyMacroKeyBuffer(macroModeState);
+ do {
+ match = (/<\w+-.+?>|<\w+>|./).exec(text);
+ if(match === null)break;
+ key = match[0];
+ text = text.substring(match.index + key.length);
+ macroKeyBuffer.push(key);
+ } while (text);
+ return macroKeyBuffer;
+ }
+
+ function parseKeyBufferToRegister(registerName, keyBuffer) {
+ var text = keyBuffer.join('');
+ vimGlobalState.registerController.setRegisterText(registerName, text);
+ }
+
+ function emptyMacroKeyBuffer(macroModeState) {
+ if(macroModeState.isMacroPlaying)return;
+ var macroKeyBuffer = macroModeState.macroKeyBuffer;
+ macroKeyBuffer.length = 0;
+ }
+
+ function executeMacroKeyBuffer(cm, macroModeState, keyBuffer) {
+ macroModeState.isMacroPlaying = true;
+ for (var i = 0, len = keyBuffer.length; i < len; i++) {
+ CodeMirror.Vim.handleKey(cm, keyBuffer[i]);
+ };
+ macroModeState.isMacroPlaying = false;
+ }
+
+ function logKey(macroModeState, key) {
+ if(macroModeState.isMacroPlaying)return;
+ var macroKeyBuffer = macroModeState.macroKeyBuffer;
+ macroKeyBuffer.push(key);
+ }
+
+ /**
+ * Listens for changes made in insert mode.
+ * Should only be active in insert mode.
+ */
+ function onChange(_cm, changeObj) {
+ var macroModeState = vimGlobalState.macroModeState;
+ var lastChange = macroModeState.lastInsertModeChanges;
+ while (changeObj) {
+ lastChange.expectCursorActivityForChange = true;
+ if (changeObj.origin == '+input' || changeObj.origin == 'paste'
+ || changeObj.origin === undefined /* only in testing */) {
+ var text = changeObj.text.join('\n');
+ lastChange.changes.push(text);
+ }
+ // Change objects may be chained with next.
+ changeObj = changeObj.next;
+ }
+ }
+
+ /**
+ * Listens for any kind of cursor activity on CodeMirror.
+ * - For tracking cursor activity in insert mode.
+ * - Should only be active in insert mode.
+ */
+ function onCursorActivity() {
+ var macroModeState = vimGlobalState.macroModeState;
+ var lastChange = macroModeState.lastInsertModeChanges;
+ if (lastChange.expectCursorActivityForChange) {
+ lastChange.expectCursorActivityForChange = false;
+ } else {
+ // Cursor moved outside the context of an edit. Reset the change.
+ lastChange.changes = [];
+ }
+ }
+
+ /** Wrapper for special keys pressed in insert mode */
+ function InsertModeKey(keyName) {
+ this.keyName = keyName;
+ }
+
+ /**
+ * Handles raw key down events from the text area.
+ * - Should only be active in insert mode.
+ * - For recording deletes in insert mode.
+ */
+ function onKeyEventTargetKeyDown(e) {
+ var macroModeState = vimGlobalState.macroModeState;
+ var lastChange = macroModeState.lastInsertModeChanges;
+ var keyName = CodeMirror.keyName(e);
+ function onKeyFound() {
+ lastChange.changes.push(new InsertModeKey(keyName));
+ return true;
+ }
+ if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) {
+ CodeMirror.lookupKey(keyName, ['vim-insert'], onKeyFound);
+ }
+ }
+
+ /**
+ * Repeats the last edit, which includes exactly 1 command and at most 1
+ * insert. Operator and motion commands are read from lastEditInputState,
+ * while action commands are read from lastEditActionCommand.
+ *
+ * If repeatForInsert is true, then the function was called by
+ * exitInsertMode to repeat the insert mode changes the user just made. The
+ * corresponding enterInsertMode call was made with a count.
+ */
+ function repeatLastEdit(cm, vim, repeat, repeatForInsert) {
+ var macroModeState = vimGlobalState.macroModeState;
+ macroModeState.inReplay = true;
+ var isAction = !!vim.lastEditActionCommand;
+ var cachedInputState = vim.inputState;
+ function repeatCommand() {
+ if (isAction) {
+ commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand);
+ } else {
+ commandDispatcher.evalInput(cm, vim);
+ }
+ }
+ function repeatInsert(repeat) {
+ if (macroModeState.lastInsertModeChanges.changes.length > 0) {
+ // For some reason, repeat cw in desktop VIM will does not repeat
+ // insert mode changes. Will conform to that behavior.
+ repeat = !vim.lastEditActionCommand ? 1 : repeat;
+ repeatLastInsertModeChanges(cm, repeat, macroModeState);
+ }
+ }
+ vim.inputState = vim.lastEditInputState;
+ if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) {
+ // o and O repeat have to be interlaced with insert repeats so that the
+ // insertions appear on separate lines instead of the last line.
+ for (var i = 0; i < repeat; i++) {
+ repeatCommand();
+ repeatInsert(1);
+ }
+ } else {
+ if (!repeatForInsert) {
+ // Hack to get the cursor to end up at the right place. If I is
+ // repeated in insert mode repeat, cursor will be 1 insert
+ // change set left of where it should be.
+ repeatCommand();
+ }
+ repeatInsert(repeat);
+ }
+ vim.inputState = cachedInputState;
+ if (vim.insertMode && !repeatForInsert) {
+ // Don't exit insert mode twice. If repeatForInsert is set, then we
+ // were called by an exitInsertMode call lower on the stack.
+ exitInsertMode(cm);
+ }
+ macroModeState.inReplay = false;
+ };
+
+ function repeatLastInsertModeChanges(cm, repeat, macroModeState) {
+ var lastChange = macroModeState.lastInsertModeChanges;
+ function keyHandler(binding) {
+ if (typeof binding == 'string') {
+ CodeMirror.commands[binding](cm);
+ } else {
+ binding(cm);
+ }
+ return true;
+ }
+ for (var i = 0; i < repeat; i++) {
+ for (var j = 0; j < lastChange.changes.length; j++) {
+ var change = lastChange.changes[j];
+ if (change instanceof InsertModeKey) {
+ CodeMirror.lookupKey(change.keyName, ['vim-insert'], keyHandler);
+ } else {
+ var cur = cm.getCursor();
+ cm.replaceRange(change, cur, cur);
+ }
+ }
+ }
+ }
+
+ resetVimGlobalState();
return vimApi;
};
// Initialize Vim and make it available as an API.
- var vim = Vim();
- CodeMirror.Vim = vim;
+ CodeMirror.Vim = Vim();
}
)();
diff --git a/gulliver/js/codemirror/lib/codemirror.css b/gulliver/js/codemirror/lib/codemirror.css
index 753a15f91..23eaf74d4 100644
--- a/gulliver/js/codemirror/lib/codemirror.css
+++ b/gulliver/js/codemirror/lib/codemirror.css
@@ -3,7 +3,7 @@
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
- height: '95%';
+ height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
@@ -19,7 +19,7 @@
padding: 0 4px; /* Horizontal padding of content */
}
-.CodeMirror-scrollbar-filler {
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
@@ -28,6 +28,7 @@
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
+ white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
@@ -73,10 +74,8 @@
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
-.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
-.cm-s-default .cm-PMbuiltin {color: white; background: #38A;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
@@ -91,10 +90,12 @@
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
+.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
@@ -111,12 +112,14 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
- /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
+ /* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
}
.CodeMirror-sizer {
position: relative;
@@ -125,7 +128,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
-.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
@@ -142,17 +145,21 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
- z-index: 6;
+}
+.CodeMirror-gutter-filler {
+ left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
- height: 100%;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
+ white-space: normal;
height: 100%;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
@@ -190,6 +197,16 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
white-space: pre-wrap;
word-break: normal;
}
+.CodeMirror-code pre {
+ border-right: 30px solid transparent;
+ width: -webkit-fit-content;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+.CodeMirror-wrap .CodeMirror-code pre {
+ border-right: none;
+ width: auto;
+}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
@@ -202,9 +219,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
overflow: auto;
}
-.CodeMirror-widget {
- display: inline-block;
-}
+.CodeMirror-widget {}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
@@ -212,7 +227,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-measure {
position: absolute;
- width: 100%; height: 0px;
+ width: 100%;
+ height: 0;
overflow: hidden;
visibility: hidden;
}
@@ -237,7 +253,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
-/*.CodeMirror span { *vertical-align: text-bottom; }*/
+.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
diff --git a/gulliver/js/codemirror/lib/codemirror.js b/gulliver/js/codemirror/lib/codemirror.js
index 120e09bbf..d82bd143c 100644
--- a/gulliver/js/codemirror/lib/codemirror.js
+++ b/gulliver/js/codemirror/lib/codemirror.js
@@ -1,4 +1,4 @@
-// CodeMirror version 3.16
+// CodeMirror version 3.21
//
// CodeMirror is the only global var we claim
window.CodeMirror = (function() {
@@ -9,9 +9,14 @@ window.CodeMirror = (function() {
// Crude, but necessary to handle a number of hard-to-feature-detect
// bugs and behavior differences.
var gecko = /gecko\/\d/i.test(navigator.userAgent);
- var ie = /MSIE \d/.test(navigator.userAgent);
- var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8);
- var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
+ // IE11 currently doesn't count as 'ie', since it has almost none of
+ // the same bugs as earlier versions. Use ie_gt10 to handle
+ // incompatibilities in that version.
+ var old_ie = /MSIE \d/.test(navigator.userAgent);
+ var ie_lt8 = old_ie && (document.documentMode == null || document.documentMode < 8);
+ var ie_lt9 = old_ie && (document.documentMode == null || document.documentMode < 9);
+ var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
+ var ie = old_ie || ie_gt10;
var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(navigator.userAgent);
@@ -33,7 +38,7 @@ window.CodeMirror = (function() {
if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11));
- var captureMiddleClick = gecko || (ie && !ie_lt9);
+ var captureMiddleClick = gecko || (old_ie && !ie_lt9);
// Optimize some code when these features are not used
var sawReadOnlySpans = false, sawCollapsedSpans = false;
@@ -59,7 +64,8 @@ window.CodeMirror = (function() {
overlays: [],
modeGen: 0,
overwrite: false, focused: false,
- suppressEdits: false, pasteIncoming: false,
+ suppressEdits: false,
+ pasteIncoming: false, cutIncoming: false,
draggingText: false,
highlight: new Delayed()};
@@ -73,7 +79,7 @@ window.CodeMirror = (function() {
// Override magic textarea content restore that IE sometimes does
// on our hidden textarea on reload
- if (ie) setTimeout(bind(resetInput, this, true), 20);
+ if (old_ie) setTimeout(bind(resetInput, this, true), 20);
registerEventHandlers(this);
// IE throws unspecified error in certain cases, when
@@ -193,6 +199,10 @@ window.CodeMirror = (function() {
function loadMode(cm) {
cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
+ resetModeState(cm);
+ }
+
+ function resetModeState(cm) {
cm.doc.iter(function(line) {
if (line.stateAfter) line.stateAfter = null;
if (line.styles) line.styles = null;
@@ -242,7 +252,6 @@ window.CodeMirror = (function() {
var map = keyMap[cm.options.keyMap], style = map.style;
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
(style ? " cm-keymap-" + style : "");
- cm.state.disableInput = map.disableInput;
}
function themeChanged(cm) {
@@ -306,15 +315,13 @@ window.CodeMirror = (function() {
// Make sure the gutters options contains the element
// "CodeMirror-linenumbers" when the lineNumbers option is true.
function setGuttersForLineNumbers(options) {
- var found = false;
- for (var i = 0; i < options.gutters.length; ++i) {
- if (options.gutters[i] == "CodeMirror-linenumbers") {
- if (options.lineNumbers) found = true;
- else options.gutters.splice(i--, 1);
- }
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers");
+ if (found == -1 && options.lineNumbers) {
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
+ } else if (found > -1 && !options.lineNumbers) {
+ options.gutters = options.gutters.slice(0);
+ options.gutters.splice(found, 1);
}
- if (!found && options.lineNumbers)
- options.gutters.push("CodeMirror-linenumbers");
}
// SCROLLBARS
@@ -357,8 +364,10 @@ window.CodeMirror = (function() {
d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
} else d.gutterFiller.style.display = "";
- if (mac_geLion && scrollbarWidth(d.measure) === 0)
+ if (mac_geLion && scrollbarWidth(d.measure) === 0) {
d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
+ d.scrollbarV.style.pointerEvents = d.scrollbarH.style.pointerEvents = "none";
+ }
}
function visibleLines(display, doc, viewPort) {
@@ -413,12 +422,18 @@ window.CodeMirror = (function() {
function updateDisplay(cm, changes, viewPort, forced) {
var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated;
var visible = visibleLines(cm.display, cm.doc, viewPort);
- for (;;) {
+ for (var first = true;; first = false) {
+ var oldWidth = cm.display.scroller.clientWidth;
if (!updateDisplayInner(cm, changes, visible, forced)) break;
- forced = false;
updated = true;
+ changes = [];
updateSelection(cm);
updateScrollbars(cm);
+ if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
+ forced = true;
+ continue;
+ }
+ forced = false;
// Clip forced viewport to actual scrollable area
if (viewPort)
@@ -427,7 +442,6 @@ window.CodeMirror = (function() {
visible = visibleLines(cm.display, cm.doc, viewPort);
if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo)
break;
- changes = [];
}
if (updated) {
@@ -443,7 +457,7 @@ window.CodeMirror = (function() {
// updates.
function updateDisplayInner(cm, changes, visible, forced) {
var display = cm.display, doc = cm.doc;
- if (!display.wrapper.clientWidth) {
+ if (!display.wrapper.offsetWidth) {
display.showingFrom = display.showingTo = doc.first;
display.viewOffset = 0;
return;
@@ -528,6 +542,7 @@ window.CodeMirror = (function() {
}
display.showingFrom = from; display.showingTo = to;
+ display.gutters.style.height = "";
updateHeightsInViewport(cm);
updateViewOffset(cm);
@@ -665,10 +680,11 @@ window.CodeMirror = (function() {
}
function buildLineElement(cm, line, lineNo, dims, reuse) {
- var lineElement = lineContent(cm, line);
+ var built = buildLineContent(cm, line), lineElement = built.pre;
var markers = line.gutterMarkers, display = cm.display, wrap;
- if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets)
+ var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : line.bgClass;
+ if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !line.widgets)
return lineElement;
// Lines with gutter elements, widgets or a background class need
@@ -706,12 +722,12 @@ window.CodeMirror = (function() {
wrap.appendChild(lineElement);
}
// Kludge to make sure the styled element lies behind the selection (by z-index)
- if (line.bgClass)
- wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackground"), wrap.firstChild);
+ if (bgClass)
+ wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground"), wrap.firstChild);
if (cm.options.lineNumbers || markers) {
- var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " +
+ var gutterWrap = wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
(cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
- wrap.firstChild);
+ lineElement);
if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push(gutterWrap);
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
wrap.lineNumber = gutterWrap.appendChild(
@@ -902,7 +918,7 @@ window.CodeMirror = (function() {
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) {
if (doc.frontier >= cm.display.showingFrom) { // Visible
var oldStyles = line.styles;
- line.styles = highlightLine(cm, line, state);
+ line.styles = highlightLine(cm, line, state, true);
var ischange = !oldStyles || oldStyles.length != line.styles.length;
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) {
@@ -911,7 +927,7 @@ window.CodeMirror = (function() {
}
line.stateAfter = copyState(doc.mode, state);
} else {
- processLine(cm, line, state);
+ processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
}
++doc.frontier;
@@ -933,8 +949,9 @@ window.CodeMirror = (function() {
// smallest indentation, which tends to need the least context to
// parse correctly.
function findStartLine(cm, n, precise) {
- var minindent, minline, doc = cm.doc, maxScan = cm.doc.mode.innerMode ? 1000 : 100;
- for (var search = n, lim = n - maxScan; search > lim; --search) {
+ var minindent, minline, doc = cm.doc;
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
+ for (var search = n; search > lim; --search) {
if (search <= doc.first) return doc.first;
var line = getLine(doc, search - 1);
if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
@@ -954,11 +971,12 @@ window.CodeMirror = (function() {
if (!state) state = startState(doc.mode);
else state = copyState(doc.mode, state);
doc.iter(pos, n, function(line) {
- processLine(cm, line, state);
+ processLine(cm, line.text, state);
var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo;
line.stateAfter = save ? copyState(doc.mode, state) : null;
++pos;
});
+ if (precise) doc.frontier = pos;
return state;
}
@@ -974,6 +992,10 @@ window.CodeMirror = (function() {
function measureChar(cm, line, ch, data, bias) {
var dir = -1;
data = data || measureLine(cm, line);
+ if (data.crude) {
+ var left = data.left + ch * data.width;
+ return {left: left, right: left + data.width, top: data.top, bottom: data.bottom};
+ }
for (var pos = ch;; pos += dir) {
var r = data[pos];
@@ -995,7 +1017,7 @@ window.CodeMirror = (function() {
var memo = cache[i];
if (memo.text == line.text && memo.markedSpans == line.markedSpans &&
cm.display.scroller.clientWidth == memo.width &&
- memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapClass)
+ memo.classes == line.textClass + "|" + line.wrapClass)
return memo;
}
}
@@ -1015,15 +1037,18 @@ window.CodeMirror = (function() {
var cache = cm.display.measureLineCache;
var memo = {text: line.text, width: cm.display.scroller.clientWidth,
markedSpans: line.markedSpans, measure: measure,
- classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass};
+ classes: line.textClass + "|" + line.wrapClass};
if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
else cache.push(memo);
return measure;
}
function measureLineInner(cm, line) {
+ if (!cm.options.lineWrapping && line.text.length >= cm.options.crudeMeasuringFrom)
+ return crudelyMeasureLine(cm, line);
+
var display = cm.display, measure = emptyArray(line.text.length);
- var pre = lineContent(cm, line, measure, true);
+ var pre = buildLineContent(cm, line, measure, true).pre;
// IE does not cache element positions of inline elements between
// calls to getBoundingClientRect. This makes the loop below,
@@ -1036,7 +1061,7 @@ window.CodeMirror = (function() {
// doesn't work when wrapping is on, but in that case the
// situation is slightly better, since IE does cache line-wrapping
// information and only recomputes per-line.
- if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
+ if (old_ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
var fragment = document.createDocumentFragment();
var chunk = 10, n = pre.childNodes.length;
for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
@@ -1096,7 +1121,7 @@ window.CodeMirror = (function() {
}
}
if (!rect) rect = data[i] = measureRect(getRect(node));
- if (cur.measureRight) rect.right = getRect(cur.measureRight).left;
+ if (cur.measureRight) rect.right = getRect(cur.measureRight).left - outer.left;
if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide));
}
removeChildren(cm.display.measure);
@@ -1108,6 +1133,15 @@ window.CodeMirror = (function() {
return data;
}
+ function crudelyMeasureLine(cm, line) {
+ var copy = new Line(line.text.slice(0, 100), null);
+ if (line.textClass) copy.textClass = line.textClass;
+ var measure = measureLineInner(cm, copy);
+ var left = measureChar(cm, copy, 0, measure, "left");
+ var right = measureChar(cm, copy, 99, measure, "right");
+ return {crude: true, top: left.top, left: left.left, bottom: left.bottom, width: (right.right - left.left) / 100};
+ }
+
function measureLineWidth(cm, line) {
var hasBadSpan = false;
if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) {
@@ -1115,9 +1149,10 @@ window.CodeMirror = (function() {
if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true;
}
var cached = !hasBadSpan && findCachedMeasurement(cm, line);
- if (cached) return measureChar(cm, line, line.text.length, cached.measure, "right").right;
+ if (cached || line.text.length >= cm.options.crudeMeasuringFrom)
+ return measureChar(cm, line, line.text.length, cached && cached.measure, "right").right;
- var pre = lineContent(cm, line, null, true);
+ var pre = buildLineContent(cm, line, null, true).pre;
var end = pre.appendChild(zeroWidthElement(cm.display.measure));
removeChildrenAndAdd(cm.display.measure, pre);
return getRect(end).right - getRect(cm.display.lineDiv).left;
@@ -1262,7 +1297,7 @@ window.CodeMirror = (function() {
if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
var ch = x < fromX || x - fromX <= toX - x ? from : to;
var xDiff = x - (ch == from ? fromX : toX);
- while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
xDiff < 0 ? -1 : xDiff ? 1 : 0);
return pos;
@@ -1360,11 +1395,14 @@ window.CodeMirror = (function() {
}
if (!updated && op.selectionChanged) updateSelection(cm);
if (op.updateScrollPos) {
- display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop;
- display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft;
+ var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, newScrollPos.scrollTop));
+ var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, newScrollPos.scrollLeft));
+ display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
+ display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
alignHorizontally(cm);
if (op.scrollToPos)
- scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos), op.scrollToPosMargin);
+ scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
+ clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin);
} else if (newScrollPos) {
scrollCursorIntoView(cm);
}
@@ -1451,7 +1489,7 @@ window.CodeMirror = (function() {
// supported or compatible enough yet to rely on.)
function readInput(cm) {
var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel;
- if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false;
+ if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
input.value = input.value.substring(0, input.value.length - 1);
cm.state.fakedLastChar = false;
@@ -1469,22 +1507,32 @@ window.CodeMirror = (function() {
var same = 0, l = Math.min(prevInput.length, text.length);
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
var from = sel.from, to = sel.to;
+ var inserted = text.slice(same);
if (same < prevInput.length)
from = Pos(from.line, from.ch - (prevInput.length - same));
else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming)
- to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same)));
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + inserted.length));
var updateInput = cm.curOp.updateInput;
- var changeEvent = {from: from, to: to, text: splitLines(text.slice(same)),
- origin: cm.state.pasteIncoming ? "paste" : "+input"};
+ var changeEvent = {from: from, to: to, text: splitLines(inserted),
+ origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
makeChange(cm.doc, changeEvent, "end");
cm.curOp.updateInput = updateInput;
signalLater(cm, "inputRead", cm, changeEvent);
+ if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
+ cm.options.smartIndent && sel.head.ch < 100) {
+ var electric = cm.getModeAt(sel.head).electricChars;
+ if (electric) for (var i = 0; i < electric.length; i++)
+ if (inserted.indexOf(electric.charAt(i)) > -1) {
+ indentLine(cm, sel.head.line, "smart");
+ break;
+ }
+ }
if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
else cm.display.prevInput = text;
if (withOp) endOperation(cm);
- cm.state.pasteIncoming = false;
+ cm.state.pasteIncoming = cm.state.cutIncoming = false;
return true;
}
@@ -1519,7 +1567,7 @@ window.CodeMirror = (function() {
function registerEventHandlers(cm) {
var d = cm.display;
on(d.scroller, "mousedown", operation(cm, onMouseDown));
- if (ie)
+ if (old_ie)
on(d.scroller, "dblclick", operation(cm, function(e) {
if (signalDOMEvent(cm, e)) return;
var pos = posFromMouse(cm, e);
@@ -1586,7 +1634,10 @@ window.CodeMirror = (function() {
if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
if (e.keyCode == 16) cm.doc.sel.shift = false;
}));
- on(d.input, "input", bind(fastPoll, cm));
+ on(d.input, "input", function() {
+ if (ie && !ie_lt9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
+ fastPoll(cm);
+ });
on(d.input, "keydown", operation(cm, onKeyDown));
on(d.input, "keypress", operation(cm, onKeyPress));
on(d.input, "focus", bind(onFocus, cm));
@@ -1622,21 +1673,22 @@ window.CodeMirror = (function() {
fastPoll(cm);
});
- function prepareCopy() {
+ function prepareCopy(e) {
if (d.inaccurateSelection) {
d.prevInput = "";
d.inaccurateSelection = false;
d.input.value = cm.getSelection();
selectInput(d.input);
}
+ if (e.type == "cut") cm.state.cutIncoming = true;
}
on(d.input, "cut", prepareCopy);
on(d.input, "copy", prepareCopy);
// Needed to handle Tab key in KHTML
if (khtml) on(d.sizer, "mouseup", function() {
- if (document.activeElement == d.input) d.input.blur();
- focusInput(cm);
+ if (document.activeElement == d.input) d.input.blur();
+ focusInput(cm);
});
}
@@ -1720,6 +1772,9 @@ window.CodeMirror = (function() {
e_preventDefault(e2);
extendSelection(cm.doc, start);
focusInput(cm);
+ // Work around unexplainable focus problem in IE9 (#2127)
+ if (old_ie && !ie_lt9)
+ setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
}
});
// Let the drag handler handle this.
@@ -1794,7 +1849,7 @@ window.CodeMirror = (function() {
}
var move = operation(cm, function(e) {
- if (!ie && !e_button(e)) done(e);
+ if (!old_ie && !e_button(e)) done(e);
else extend(e);
});
var up = operation(cm, done);
@@ -1802,17 +1857,16 @@ window.CodeMirror = (function() {
on(document, "mouseup", up);
}
- function clickInGutter(cm, e) {
- var display = cm.display;
+ function gutterEvent(cm, e, type, prevent, signalfn) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
+ if (mX >= Math.floor(getRect(cm.display.gutters).right)) return false;
+ if (prevent) e_preventDefault(e);
- if (mX >= Math.floor(getRect(display.gutters).right)) return false;
- e_preventDefault(e);
- if (!hasHandler(cm, "gutterClick")) return true;
-
+ var display = cm.display;
var lineBox = getRect(display.lineDiv);
- if (mY > lineBox.bottom) return true;
+
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
mY -= lineBox.top - display.viewOffset;
for (var i = 0; i < cm.options.gutters.length; ++i) {
@@ -1820,11 +1874,19 @@ window.CodeMirror = (function() {
if (g && getRect(g).right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
- signalLater(cm, "gutterClick", cm, line, gutter, e);
- break;
+ signalfn(cm, type, cm, line, gutter, e);
+ return e_defaultPrevented(e);
}
}
- return true;
+ }
+
+ function contextMenuInGutter(cm, e) {
+ if (!hasHandler(cm, "gutterContextMenu")) return false;
+ return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+ }
+
+ function clickInGutter(cm, e) {
+ return gutterEvent(cm, e, "gutterClick", true, signalLater);
}
// Kludge to work around strange IE behavior where it'll sometimes
@@ -1869,7 +1931,6 @@ window.CodeMirror = (function() {
if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste");
cm.replaceSelection(text, null, "paste");
focusInput(cm);
- onFocus(cm);
}
}
catch(e){}
@@ -1887,6 +1948,7 @@ window.CodeMirror = (function() {
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
if (e.dataTransfer.setDragImage && !safari) {
var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
if (opera) {
img.width = img.height = 1;
cm.display.wrapper.appendChild(img);
@@ -1932,7 +1994,7 @@ window.CodeMirror = (function() {
// know one. These don't have to be accurate -- the result of them
// being wrong would just be a slight flicker on the first wheel
// scroll (if it is large enough).
- if (ie) wheelPixelsPerUnit = -.53;
+ if (old_ie) wheelPixelsPerUnit = -.53;
else if (gecko) wheelPixelsPerUnit = 15;
else if (chrome) wheelPixelsPerUnit = -.7;
else if (safari) wheelPixelsPerUnit = -1/3;
@@ -2086,7 +2148,7 @@ window.CodeMirror = (function() {
var cm = this;
if (!cm.state.focused) onFocus(cm);
if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
- if (ie && e.keyCode == 27) e.returnValue = false;
+ if (old_ie && e.keyCode == 27) e.returnValue = false;
var code = e.keyCode;
// IE does strange things with escape.
cm.doc.sel.shift = code == 16 || e.shiftKey;
@@ -2107,10 +2169,6 @@ window.CodeMirror = (function() {
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
- if (this.options.electricChars && this.doc.mode.electricChars &&
- this.options.smartIndent && !isReadOnly(this) &&
- this.doc.mode.electricChars.indexOf(ch) > -1)
- setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75);
if (handleCharBinding(cm, e, ch)) return;
if (ie && !ie_lt9) cm.display.inputHasSelection = null;
fastPoll(cm);
@@ -2145,17 +2203,21 @@ window.CodeMirror = (function() {
function onContextMenu(cm, e) {
if (signalDOMEvent(cm, e, "contextmenu")) return;
var display = cm.display, sel = cm.doc.sel;
- if (eventInWidget(display, e)) return;
+ if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
if (!pos || opera) return; // Opera is difficult.
- if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
+
+ // Reset the current text selection only if the click is done outside of the selection
+ // and 'resetSelectionOnContextMenu' option is true.
+ var reset = cm.options.resetSelectionOnContextMenu;
+ if (reset && (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to)))
operation(cm, setSelection)(cm.doc, pos, pos);
var oldCSS = display.input.style.cssText;
display.inputDiv.style.position = "absolute";
display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
- "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: transparent; outline: none;" +
"border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);";
focusInput(cm);
resetInput(cm, true);
@@ -2164,8 +2226,8 @@ window.CodeMirror = (function() {
function prepareSelectAllHack() {
if (display.input.selectionStart != null) {
- var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value);
- display.prevInput = " ";
+ var extval = display.input.value = "\u200b" + (posEq(sel.from, sel.to) ? "" : display.input.value);
+ display.prevInput = "\u200b";
display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
}
}
@@ -2177,10 +2239,10 @@ window.CodeMirror = (function() {
// Try to detect the user choosing select-all
if (display.input.selectionStart != null) {
- if (!ie || ie_lt9) prepareSelectAllHack();
+ if (!old_ie || ie_lt9) prepareSelectAllHack();
clearTimeout(detectingSelectAll);
var i = 0, poll = function(){
- if (display.prevInput == " " && display.input.selectionStart == 0)
+ if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
operation(cm, commands.selectAll)(cm);
else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
else resetInput(cm);
@@ -2189,7 +2251,7 @@ window.CodeMirror = (function() {
}
}
- if (ie && !ie_lt9) prepareSelectAllHack();
+ if (old_ie && !ie_lt9) prepareSelectAllHack();
if (captureMiddleClick) {
e_stop(e);
var mouseup = function() {
@@ -2299,6 +2361,7 @@ window.CodeMirror = (function() {
}
function makeChangeNoReadonly(doc, change, selUpdate) {
+ if (change.text.length == 1 && change.text[0] == "" && posEq(change.from, change.to)) return;
var selAfter = computeSelAfterChange(doc, change, selUpdate);
addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
@@ -2461,6 +2524,7 @@ window.CodeMirror = (function() {
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
+ function cmp(a, b) {return a.line - b.line || a.ch - b.ch;}
function copyPos(x) {return Pos(x.line, x.ch);}
// SELECTION
@@ -2521,6 +2585,7 @@ window.CodeMirror = (function() {
var sel = doc.sel;
sel.goalColumn = null;
+ if (bias == null) bias = posLess(head, sel.head) ? -1 : 1;
// Skip over atomic spans.
if (checkAtomic || !posEq(anchor, sel.anchor))
anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push");
@@ -2598,28 +2663,31 @@ window.CodeMirror = (function() {
// SCROLLING
function scrollCursorIntoView(cm) {
- var coords = scrollPosIntoView(cm, cm.doc.sel.head, cm.options.cursorScrollMargin);
+ var coords = scrollPosIntoView(cm, cm.doc.sel.head, null, cm.options.cursorScrollMargin);
if (!cm.state.focused) return;
var display = cm.display, box = getRect(display.sizer), doScroll = null;
if (coords.top + box.top < 0) doScroll = true;
else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
if (doScroll != null && !phantom) {
- var hidden = display.cursor.style.display == "none";
- if (hidden) {
- display.cursor.style.display = "";
- display.cursor.style.left = coords.left + "px";
- display.cursor.style.top = (coords.top - display.viewOffset) + "px";
- }
- display.cursor.scrollIntoView(doScroll);
- if (hidden) display.cursor.style.display = "none";
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
+ (coords.top - display.viewOffset) + "px; height: " +
+ (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
+ coords.left + "px; width: 2px;");
+ cm.display.lineSpace.appendChild(scrollNode);
+ scrollNode.scrollIntoView(doScroll);
+ cm.display.lineSpace.removeChild(scrollNode);
}
}
- function scrollPosIntoView(cm, pos, margin) {
+ function scrollPosIntoView(cm, pos, end, margin) {
if (margin == null) margin = 0;
for (;;) {
var changed = false, coords = cursorCoords(cm, pos);
- var scrollPos = calculateScrollPos(cm, coords.left, coords.top - margin, coords.left, coords.bottom + margin);
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
+ var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
+ Math.min(coords.top, endCoords.top) - margin,
+ Math.max(coords.left, endCoords.left),
+ Math.max(coords.bottom, endCoords.bottom) + margin);
var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
if (scrollPos.scrollTop != null) {
setScrollTop(cm, scrollPos.scrollTop);
@@ -2690,7 +2758,10 @@ window.CodeMirror = (function() {
var tabSize = cm.options.tabSize;
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
- if (how == "smart") {
+ if (!aggressive && !/\S/.test(line.text)) {
+ indentation = 0;
+ how = "not";
+ } else if (how == "smart") {
indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
if (indentation == Pass) {
if (!aggressive) return;
@@ -2716,6 +2787,8 @@ window.CodeMirror = (function() {
if (indentString != curSpaceString)
replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
+ else if (doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length)
+ setSelection(doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length), 1);
line.stateAfter = null;
}
@@ -2816,7 +2889,7 @@ window.CodeMirror = (function() {
CodeMirror.prototype = {
constructor: CodeMirror,
- focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);},
+ focus: function(){window.focus(); focusInput(this); fastPoll(this);},
setOption: function(option, value) {
var options = this.options, old = options[option];
@@ -2870,7 +2943,7 @@ window.CodeMirror = (function() {
}),
indentSelection: operation(null, function(how) {
var sel = this.doc.sel;
- if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
+ if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how, true);
var e = sel.to.line - (sel.to.ch ? 0 : 1);
for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
}),
@@ -2915,11 +2988,31 @@ window.CodeMirror = (function() {
},
getHelper: function(pos, type) {
- if (!helpers.hasOwnProperty(type)) return;
+ return this.getHelpers(pos, type)[0];
+ },
+
+ getHelpers: function(pos, type) {
+ var found = [];
+ if (!helpers.hasOwnProperty(type)) return helpers;
var help = helpers[type], mode = this.getModeAt(pos);
- return mode[type] && help[mode[type]] ||
- mode.helperType && help[mode.helperType] ||
- help[mode.name];
+ if (typeof mode[type] == "string") {
+ if (help[mode[type]]) found.push(help[mode[type]]);
+ } else if (mode[type]) {
+ for (var i = 0; i < mode[type].length; i++) {
+ var val = help[mode[type][i]];
+ if (val) found.push(val);
+ }
+ } else if (mode.helperType && help[mode.helperType]) {
+ found.push(help[mode.helperType]);
+ } else if (help[mode.name]) {
+ found.push(help[mode.name]);
+ }
+ for (var i = 0; i < help._global.length; i++) {
+ var cur = help._global[i];
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
+ found.push(cur.val);
+ }
+ return found;
},
getStateAfter: function(line, precise) {
@@ -3066,7 +3159,10 @@ window.CodeMirror = (function() {
triggerOnKeyDown: operation(null, onKeyDown),
- execCommand: function(cmd) {return commands[cmd](this);},
+ execCommand: function(cmd) {
+ if (commands.hasOwnProperty(cmd))
+ return commands[cmd](this);
+ },
findPosH: function(from, amount, unit, visually) {
var dir = 1;
@@ -3108,14 +3204,18 @@ window.CodeMirror = (function() {
},
moveV: operation(null, function(dir, unit) {
- var sel = this.doc.sel;
- var pos = cursorCoords(this, sel.head, "div");
- if (sel.goalColumn != null) pos.left = sel.goalColumn;
- var target = findPosV(this, pos, dir, unit);
-
- if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
+ var sel = this.doc.sel, target, goal;
+ if (sel.shift || sel.extend || posEq(sel.from, sel.to)) {
+ var pos = cursorCoords(this, sel.head, "div");
+ if (sel.goalColumn != null) pos.left = sel.goalColumn;
+ target = findPosV(this, pos, dir, unit);
+ if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
+ goal = pos.left;
+ } else {
+ target = dir < 0 ? sel.from : sel.to;
+ }
extendSelection(this.doc, target, target, dir);
- sel.goalColumn = pos.left;
+ if (goal != null) sel.goalColumn = goal;
}),
toggleOverwrite: function(value) {
@@ -3137,17 +3237,23 @@ window.CodeMirror = (function() {
clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
},
- scrollIntoView: operation(null, function(pos, margin) {
- if (typeof pos == "number") pos = Pos(pos, 0);
+ scrollIntoView: operation(null, function(range, margin) {
+ if (range == null) range = {from: this.doc.sel.head, to: null};
+ else if (typeof range == "number") range = {from: Pos(range, 0), to: null};
+ else if (range.from == null) range = {from: range, to: null};
+ if (!range.to) range.to = range.from;
if (!margin) margin = 0;
- var coords = pos;
- if (!pos || pos.line != null) {
- this.curOp.scrollToPos = pos ? clipPos(this.doc, pos) : this.doc.sel.head;
- this.curOp.scrollToPosMargin = margin;
- coords = cursorCoords(this, this.curOp.scrollToPos);
+ var coords = range;
+ if (range.from.line != null) {
+ this.curOp.scrollToPos = {from: range.from, to: range.to, margin: margin};
+ coords = {from: cursorCoords(this, range.from),
+ to: cursorCoords(this, range.to)};
}
- var sPos = calculateScrollPos(this, coords.left, coords.top - margin, coords.right, coords.bottom + margin);
+ var sPos = calculateScrollPos(this, Math.min(coords.from.left, coords.to.left),
+ Math.min(coords.from.top, coords.to.top) - margin,
+ Math.max(coords.from.right, coords.to.right),
+ Math.max(coords.from.bottom, coords.to.bottom) + margin);
updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop);
}),
@@ -3165,9 +3271,11 @@ window.CodeMirror = (function() {
operation: function(f){return runInOp(this, f);},
refresh: operation(null, function() {
+ var badHeight = this.display.cachedTextHeight == null;
clearCaches(this);
updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop);
regChange(this);
+ if (badHeight) estimateLineHeights(this);
}),
swapDoc: operation(null, function(doc) {
@@ -3177,6 +3285,7 @@ window.CodeMirror = (function() {
clearCaches(this);
resetInput(this, true);
updateScrollPos(this, doc.scrollLeft, doc.scrollTop);
+ signalLater(this, "swapDoc", this, old);
return old;
}),
@@ -3216,12 +3325,18 @@ window.CodeMirror = (function() {
option("indentWithTabs", false);
option("smartIndent", true);
option("tabSize", 4, function(cm) {
- loadMode(cm);
+ resetModeState(cm);
clearCaches(cm);
regChange(cm);
}, true);
+ option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
+ cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
+ cm.refresh();
+ }, true);
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
option("electricChars", true);
option("rtlMoveVisually", !windows);
+ option("wholeLineUpdateBefore", true);
option("theme", "default", function(cm) {
themeChanged(cm);
@@ -3251,10 +3366,19 @@ window.CodeMirror = (function() {
option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
option("showCursorWhenSelecting", false, updateSelection, true);
+ option("resetSelectionOnContextMenu", true);
+
option("readOnly", false, function(cm, val) {
- if (val == "nocursor") {onBlur(cm); cm.display.input.blur();}
- else if (!val) resetInput(cm, true);
+ if (val == "nocursor") {
+ onBlur(cm);
+ cm.display.input.blur();
+ cm.display.disabled = true;
+ } else {
+ cm.display.disabled = false;
+ if (!val) resetInput(cm, true);
+ }
});
+ option("disableInput", false, function(cm, val) {if (!val) resetInput(cm, true);}, true);
option("dragDrop", true);
option("cursorBlinkRate", 530);
@@ -3262,12 +3386,14 @@ window.CodeMirror = (function() {
option("cursorHeight", 1);
option("workTime", 100);
option("workDelay", 100);
- option("flattenSpans", true);
+ option("flattenSpans", true, resetModeState, true);
+ option("addModeClass", false, resetModeState, true);
option("pollInterval", 100);
option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;});
option("historyEventDelay", 500);
option("viewportMargin", 10, function(cm){cm.refresh();}, true);
- option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true);
+ option("maxHighlightLength", 10000, resetModeState, true);
+ option("crudeMeasuringFrom", 10000);
option("moveInputWithCursor", true, function(cm, val) {
if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
});
@@ -3323,6 +3449,9 @@ window.CodeMirror = (function() {
}
}
modeObj.name = spec.name;
+ if (spec.helperType) modeObj.helperType = spec.helperType;
+ if (spec.modeProps) for (var prop in spec.modeProps)
+ modeObj[prop] = spec.modeProps[prop];
return modeObj;
};
@@ -3353,9 +3482,13 @@ window.CodeMirror = (function() {
var helpers = CodeMirror.helpers = {};
CodeMirror.registerHelper = function(type, name, value) {
- if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {};
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
helpers[type][name] = value;
};
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
+ CodeMirror.registerHelper(type, name, value);
+ helpers[type]._global.push({pred: predicate, val: value});
+ };
// UTILITIES
@@ -3460,7 +3593,9 @@ window.CodeMirror = (function() {
indentAuto: function(cm) {cm.indentSelection("smart");},
indentMore: function(cm) {cm.indentSelection("add");},
indentLess: function(cm) {cm.indentSelection("subtract");},
- insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");},
+ insertTab: function(cm) {
+ cm.replaceSelection("\t", "end", "+input");
+ },
defaultTab: function(cm) {
if (cm.somethingSelected()) cm.indentSelection("add");
else cm.replaceSelection("\t", "end", "+input");
@@ -3486,7 +3621,8 @@ window.CodeMirror = (function() {
keyMap.basic = {
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
- "Delete": "delCharAfter", "Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
};
// Note that the save and find-related commands aren't defined by
@@ -3632,11 +3768,12 @@ window.CodeMirror = (function() {
this.string = string;
this.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0;
+ this.lineStart = 0;
}
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
- sol: function() {return this.pos == 0;},
+ sol: function() {return this.pos == this.lineStart;},
peek: function() {return this.string.charAt(this.pos) || undefined;},
next: function() {
if (this.pos < this.string.length)
@@ -3669,9 +3806,12 @@ window.CodeMirror = (function() {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start;
}
- return this.lastColumnValue;
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
+ },
+ indentation: function() {
+ return countColumn(this.string, null, this.tabSize) -
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
- indentation: function() {return countColumn(this.string, null, this.tabSize);},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
@@ -3687,7 +3827,12 @@ window.CodeMirror = (function() {
return match;
}
},
- current: function(){return this.string.slice(this.start, this.pos);}
+ current: function(){return this.string.slice(this.start, this.pos);},
+ hideFirstChars: function(n, inner) {
+ this.lineStart += n;
+ try { return inner(); }
+ finally { this.lineStart -= n; }
+ }
};
CodeMirror.StringStream = StringStream;
@@ -3739,7 +3884,7 @@ window.CodeMirror = (function() {
if (withOp) endOperation(cm);
};
- TextMarker.prototype.find = function() {
+ TextMarker.prototype.find = function(bothSides) {
var from, to;
for (var i = 0; i < this.lines.length; ++i) {
var line = this.lines[i];
@@ -3750,7 +3895,7 @@ window.CodeMirror = (function() {
if (span.to != null) to = Pos(found, span.to);
}
}
- if (this.type == "bookmark") return from;
+ if (this.type == "bookmark" && !bothSides) return from;
return from && {from: from, to: to};
};
@@ -3787,37 +3932,40 @@ window.CodeMirror = (function() {
}
};
+ var nextMarkerId = 0;
+
function markText(doc, from, to, options, type) {
if (options && options.shared) return markTextShared(doc, from, to, options, type);
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
var marker = new TextMarker(doc, type);
- if (type == "range" && !posLess(from, to)) return marker;
if (options) copyObj(options, marker);
+ if (posLess(to, from) || posEq(from, to) && marker.clearWhenEmpty !== false)
+ return marker;
if (marker.replacedWith) {
marker.collapsed = true;
marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true;
}
- if (marker.collapsed) sawCollapsedSpans = true;
+ if (marker.collapsed) {
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
+ sawCollapsedSpans = true;
+ }
if (marker.addToHistory)
addToHistory(doc, {from: from, to: to, origin: "markText"},
{head: doc.sel.head, anchor: doc.sel.anchor}, NaN);
- var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd, cm = doc.cm, updateMaxLine;
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
doc.iter(curLine, to.line + 1, function(line) {
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine)
updateMaxLine = true;
var span = {from: null, to: null, marker: marker};
- size += line.text.length;
- if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
- if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
- if (marker.collapsed) {
- if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
- if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
- else updateLineHeight(line, 0);
- }
+ if (curLine == from.line) span.from = from.ch;
+ if (curLine == to.line) span.to = to.ch;
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
addMarkedSpan(line, span);
++curLine;
});
@@ -3833,9 +3981,7 @@ window.CodeMirror = (function() {
doc.clearHistory();
}
if (marker.collapsed) {
- if (collapsedAtStart != collapsedAtEnd)
- throw new Error("Inserting collapsed marker overlapping an existing one");
- marker.size = size;
+ marker.id = ++nextMarkerId;
marker.atomic = true;
}
if (cm) {
@@ -3908,7 +4054,7 @@ window.CodeMirror = (function() {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
- if (startsBefore || marker.type == "bookmark" && span.from == startCh && (!isInsert || !span.marker.insertLeft)) {
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
(nw || (nw = [])).push({from: span.from,
to: endsAfter ? null : span.to,
@@ -3922,7 +4068,7 @@ window.CodeMirror = (function() {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
- if (endsAfter || marker.type == "bookmark" && span.from == endCh && (!isInsert || span.marker.insertLeft)) {
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
(nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
to: span.to == null ? null : span.to - endCh,
@@ -3972,13 +4118,9 @@ window.CodeMirror = (function() {
}
}
}
- if (sameLine && first) {
- // Make sure we didn't create any zero-length spans
- for (var i = 0; i < first.length; ++i)
- if (first[i].from != null && first[i].from == first[i].to && first[i].marker.type != "bookmark")
- first.splice(i--, 1);
- if (!first.length) first = null;
- }
+ // Make sure we didn't create any zero-length spans
+ if (first) first = clearEmptySpans(first);
+ if (last && last != first) last = clearEmptySpans(last);
var newMarkers = [first];
if (!sameLine) {
@@ -3995,6 +4137,16 @@ window.CodeMirror = (function() {
return newMarkers;
}
+ function clearEmptySpans(spans) {
+ for (var i = 0; i < spans.length; ++i) {
+ var span = spans[i];
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
+ spans.splice(i--, 1);
+ }
+ if (!spans.length) return null;
+ return spans;
+ }
+
function mergeOldSpans(doc, change) {
var old = getOldSpans(doc, change);
var stretched = stretchSpansOverChange(doc, change);
@@ -4045,20 +4197,48 @@ window.CodeMirror = (function() {
return parts;
}
- function collapsedSpanAt(line, ch) {
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
+
+ function compareCollapsedMarkers(a, b) {
+ var lenDiff = a.lines.length - b.lines.length;
+ if (lenDiff != 0) return lenDiff;
+ var aPos = a.find(), bPos = b.find();
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
+ if (fromCmp) return -fromCmp;
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
+ if (toCmp) return toCmp;
+ return b.id - a.id;
+ }
+
+ function collapsedSpanAtSide(line, start) {
var sps = sawCollapsedSpans && line.markedSpans, found;
if (sps) for (var sp, i = 0; i < sps.length; ++i) {
sp = sps[i];
- if (!sp.marker.collapsed) continue;
- if ((sp.from == null || sp.from < ch) &&
- (sp.to == null || sp.to > ch) &&
- (!found || found.width < sp.marker.width))
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
found = sp.marker;
}
return found;
}
- function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
- function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
+
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
+ var line = getLine(doc, lineNo);
+ var sps = sawCollapsedSpans && line.markedSpans;
+ if (sps) for (var i = 0; i < sps.length; ++i) {
+ var sp = sps[i];
+ if (!sp.marker.collapsed) continue;
+ var found = sp.marker.find(true);
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
+ if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
+ fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
+ return true;
+ }
+ }
function visualLine(doc, line) {
var merged;
@@ -4088,6 +4268,7 @@ window.CodeMirror = (function() {
for (var sp, i = 0; i < line.markedSpans.length; ++i) {
sp = line.markedSpans[i];
if (sp.marker.collapsed && !sp.marker.replacedWith && sp.from == span.to &&
+ (sp.to == null || sp.to != span.from) &&
(sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
lineIsHiddenInner(doc, line, sp)) return true;
}
@@ -4181,6 +4362,7 @@ window.CodeMirror = (function() {
this.height = estimateHeight ? estimateHeight(this) : 1;
};
eventMixin(Line);
+ Line.prototype.lineNo = function() { return lineNo(this); };
function updateLine(line, text, markedSpans, estimateHeight) {
line.text = text;
@@ -4201,7 +4383,7 @@ window.CodeMirror = (function() {
// Run the given mode's parser over a line, update the styles
// array, which contains alternating fragments of text and CSS
// classes.
- function runMode(cm, text, mode, state, f) {
+ function runMode(cm, text, mode, state, f, forceToEnd) {
var flattenSpans = mode.flattenSpans;
if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
var curStart = 0, curStyle = null;
@@ -4210,27 +4392,38 @@ window.CodeMirror = (function() {
while (!stream.eol()) {
if (stream.pos > cm.options.maxHighlightLength) {
flattenSpans = false;
- // Webkit seems to refuse to render text nodes longer than 57444 characters
- stream.pos = Math.min(text.length, stream.start + 50000);
+ if (forceToEnd) processLine(cm, text, state, stream.pos);
+ stream.pos = text.length;
style = null;
} else {
style = mode.token(stream, state);
}
+ if (cm.options.addModeClass) {
+ var mName = CodeMirror.innerMode(mode, state).mode.name;
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
+ }
if (!flattenSpans || curStyle != style) {
if (curStart < stream.start) f(stream.start, curStyle);
curStart = stream.start; curStyle = style;
}
stream.start = stream.pos;
}
- if (curStart < stream.pos) f(stream.pos, curStyle);
+ while (curStart < stream.pos) {
+ // Webkit seems to refuse to render text nodes longer than 57444 characters
+ var pos = Math.min(stream.pos, curStart + 50000);
+ f(pos, curStyle);
+ curStart = pos;
+ }
}
- function highlightLine(cm, line, state) {
+ function highlightLine(cm, line, state, forceToEnd) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
var st = [cm.state.modeGen];
// Compute the base array of styles
- runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end, style);});
+ runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
+ st.push(end, style);
+ }, forceToEnd);
// Run overlays, adjust style array.
for (var o = 0; o < cm.state.overlays.length; ++o) {
@@ -4269,24 +4462,36 @@ window.CodeMirror = (function() {
// Lightweight form of highlight -- proceed over this line and
// update state, but don't save a style array.
- function processLine(cm, line, state) {
+ function processLine(cm, text, state, startAt) {
var mode = cm.doc.mode;
- var stream = new StringStream(line.text, cm.options.tabSize);
- if (line.text == "" && mode.blankLine) mode.blankLine(state);
+ var stream = new StringStream(text, cm.options.tabSize);
+ stream.start = stream.pos = startAt || 0;
+ if (text == "" && mode.blankLine) mode.blankLine(state);
while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
mode.token(stream, state);
stream.start = stream.pos;
}
}
- var styleToClassCache = {};
- function styleToClass(style) {
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
+ function interpretTokenStyle(style, builder) {
if (!style) return null;
- return styleToClassCache[style] ||
- (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
+ for (;;) {
+ var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/);
+ if (!lineClass) break;
+ style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
+ var prop = lineClass[1] ? "bgClass" : "textClass";
+ if (builder[prop] == null)
+ builder[prop] = lineClass[2];
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
+ builder[prop] += " " + lineClass[2];
+ }
+ var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
+ return cache[style] ||
+ (cache[style] = "cm-" + style.replace(/ +/g, " cm-"));
}
- function lineContent(cm, realLine, measure, copyWidgets) {
+ function buildLineContent(cm, realLine, measure, copyWidgets) {
var merged, line = realLine, empty = true;
while (merged = collapsedSpanAtStart(line))
line = getLine(cm.doc, merged.find().from.line);
@@ -4294,14 +4499,13 @@ window.CodeMirror = (function() {
var builder = {pre: elt("pre"), col: 0, pos: 0,
measure: null, measuredSomething: false, cm: cm,
copyWidgets: copyWidgets};
- if (line.textClass) builder.pre.className = line.textClass;
do {
if (line.text) empty = false;
builder.measure = line == realLine && measure;
builder.pos = 0;
builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
- if ((ie || webkit) && cm.getOption("lineWrapping"))
+ if ((old_ie || webkit) && cm.getOption("lineWrapping"))
builder.addToken = buildTokenSplitSpaces(builder.addToken);
var next = insertLineContent(line, builder, getLineStyles(cm, line));
if (measure && line == realLine && !builder.measuredSomething) {
@@ -4331,21 +4535,30 @@ window.CodeMirror = (function() {
}
}
+ var textClass = builder.textClass ? builder.textClass + " " + (realLine.textClass || "") : realLine.textClass;
+ if (textClass) builder.pre.className = textClass;
+
signal(cm, "renderLine", cm, realLine, builder.pre);
- return builder.pre;
+ return builder;
+ }
+
+ function defaultSpecialCharPlaceholder(ch) {
+ var token = elt("span", "\u2022", "cm-invalidchar");
+ token.title = "\\u" + ch.charCodeAt(0).toString(16);
+ return token;
}
- var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;
function buildToken(builder, text, style, startStyle, endStyle, title) {
if (!text) return;
- if (!tokenSpecialChars.test(text)) {
+ var special = builder.cm.options.specialChars;
+ if (!special.test(text)) {
builder.col += text.length;
var content = document.createTextNode(text);
} else {
var content = document.createDocumentFragment(), pos = 0;
while (true) {
- tokenSpecialChars.lastIndex = pos;
- var m = tokenSpecialChars.exec(text);
+ special.lastIndex = pos;
+ var m = special.exec(text);
var skipped = m ? m.index - pos : text.length - pos;
if (skipped) {
content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
@@ -4358,8 +4571,7 @@ window.CodeMirror = (function() {
content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
builder.col += tabWidth;
} else {
- var token = elt("span", "\u2022", "cm-invalidchar");
- token.title = "\\u" + m[0].charCodeAt(0).toString(16);
+ var token = builder.cm.options.specialCharPlaceholder(m[0]);
content.appendChild(token);
builder.col += 1;
}
@@ -4379,13 +4591,12 @@ window.CodeMirror = (function() {
function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
var wrapping = builder.cm.options.lineWrapping;
for (var i = 0; i < text.length; ++i) {
- var ch = text.charAt(i), start = i == 0;
- if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) {
- ch = text.slice(i, i + 2);
- ++i;
- } else if (i && wrapping && spanAffectsWrapping(text, i)) {
+ var start = i == 0, to = i + 1;
+ while (to < text.length && isExtendingChar(text.charAt(to))) ++to;
+ var ch = text.slice(i, to);
+ i = to - 1;
+ if (i && wrapping && spanAffectsWrapping(text, i))
builder.pre.appendChild(elt("wbr"));
- }
var old = builder.measure[builder.pos];
var span = builder.measure[builder.pos] =
buildToken(builder, ch, style,
@@ -4394,7 +4605,7 @@ window.CodeMirror = (function() {
// In IE single-space nodes wrap differently than spaces
// embedded in larger text nodes, except when set to
// white-space: normal (issue #1268).
- if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
+ if (old_ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
i < text.length - 1 && !/\s/.test(text.charAt(i + 1)))
span.style.whiteSpace = "normal";
builder.pos += ch.length;
@@ -4410,7 +4621,7 @@ window.CodeMirror = (function() {
return out;
}
return function(builder, text, style, startStyle, endStyle, title) {
- return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle, title);
+ return inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
};
}
@@ -4443,7 +4654,7 @@ window.CodeMirror = (function() {
var spans = line.markedSpans, allText = line.text, at = 0;
if (!spans) {
for (var i = 1; i < styles.length; i+=2)
- builder.addToken(builder, allText.slice(at, at = styles[i]), styleToClass(styles[i+1]));
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
return;
}
@@ -4462,7 +4673,7 @@ window.CodeMirror = (function() {
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
if (m.title && !title) title = m.title;
- if (m.collapsed && (!collapsed || collapsed.marker.size < m.size))
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
} else if (sp.from > pos && nextChange > sp.from) {
nextChange = sp.from;
@@ -4493,7 +4704,7 @@ window.CodeMirror = (function() {
spanStartStyle = "";
}
text = allText.slice(at, at = styles[i++]);
- style = styleToClass(styles[i++]);
+ style = interpretTokenStyle(styles[i++], builder);
}
}
}
@@ -4512,7 +4723,8 @@ window.CodeMirror = (function() {
var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
// First adjust the line structure
- if (from.ch == 0 && to.ch == 0 && lastText == "") {
+ if (from.ch == 0 && to.ch == 0 && lastText == "" &&
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore)) {
// This is a whole-line replace. Treated specially to make
// sure line objects move the way they are supposed to.
for (var i = 0, e = text.length - 1, added = []; i < e; ++i)
@@ -4794,10 +5006,11 @@ window.CodeMirror = (function() {
clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);},
markClean: function() {
- this.cleanGeneration = this.changeGeneration();
+ this.cleanGeneration = this.changeGeneration(true);
},
- changeGeneration: function() {
- this.history.lastOp = this.history.lastOrigin = null;
+ changeGeneration: function(forceSplit) {
+ if (forceSplit)
+ this.history.lastOp = this.history.lastOrigin = null;
return this.history.generation;
},
isClean: function (gen) {
@@ -4819,7 +5032,8 @@ window.CodeMirror = (function() {
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
- insertLeft: options && options.insertLeft};
+ insertLeft: options && options.insertLeft,
+ clearWhenEmpty: false};
pos = clipPos(this, pos);
return markText(this, pos, pos, realOpts, "bookmark");
},
@@ -5100,10 +5314,10 @@ window.CodeMirror = (function() {
anchorBefore: doc.sel.anchor, headBefore: doc.sel.head,
anchorAfter: selAfter.anchor, headAfter: selAfter.head};
hist.done.push(cur);
- hist.generation = ++hist.maxGeneration;
while (hist.done.length > hist.undoDepth)
hist.done.shift();
}
+ hist.generation = ++hist.maxGeneration;
hist.lastTime = time;
hist.lastOp = opId;
hist.lastOrigin = change.origin;
@@ -5399,7 +5613,8 @@ window.CodeMirror = (function() {
return true;
}
- var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/;
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
// DOM UTILITIES
@@ -5461,13 +5676,18 @@ window.CodeMirror = (function() {
spanAffectsWrapping = function(str, i) {
return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1));
};
- else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent))
+ else if (webkit && /Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent))
+ spanAffectsWrapping = function(str, i) {
+ var code = str.charCodeAt(i - 1);
+ return code >= 8208 && code <= 8212;
+ };
+ else if (webkit)
spanAffectsWrapping = function(str, i) {
if (i > 1 && str.charCodeAt(i - 1) == 45) {
if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true;
if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false;
}
- return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
+ return /[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|\u2026[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
};
var knownScrollbarWidth;
@@ -5535,14 +5755,14 @@ window.CodeMirror = (function() {
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
- 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
- 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
- 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
- 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
CodeMirror.keyNames = keyNames;
(function() {
// Number keys
- for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
// Alphabetic keys
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
// Function keys
@@ -5599,29 +5819,29 @@ window.CodeMirror = (function() {
}
var bidiOther;
function getBidiPartAt(order, pos) {
+ bidiOther = null;
for (var i = 0, found; i < order.length; ++i) {
var cur = order[i];
- if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; }
- if (cur.from == pos || cur.to == pos) {
+ if (cur.from < pos && cur.to > pos) return i;
+ if ((cur.from == pos || cur.to == pos)) {
if (found == null) {
found = i;
} else if (compareBidiLevel(order, cur.level, order[found].level)) {
- bidiOther = found;
+ if (cur.from != cur.to) bidiOther = found;
return i;
} else {
- bidiOther = i;
+ if (cur.from != cur.to) bidiOther = i;
return found;
}
}
}
- bidiOther = null;
return found;
}
function moveInLine(line, pos, dir, byUnit) {
if (!byUnit) return pos + dir;
do pos += dir;
- while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
return pos;
}
@@ -5656,7 +5876,7 @@ window.CodeMirror = (function() {
function moveLogically(line, start, dir, byUnit) {
var target = start + dir;
- if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
return target < 0 || target > line.text.length ? null : target;
}
@@ -5748,7 +5968,7 @@ window.CodeMirror = (function() {
if (type == ",") types[i] = "N";
else if (type == "%") {
for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
- var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N";
+ var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
}
@@ -5773,7 +5993,7 @@ window.CodeMirror = (function() {
if (isNeutral.test(types[i])) {
for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
var before = (i ? types[i-1] : outerType) == "L";
- var after = (end < len - 1 ? types[end] : outerType) == "L";
+ var after = (end < len ? types[end] : outerType) == "L";
var replace = before || after ? "L" : "R";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
@@ -5823,7 +6043,7 @@ window.CodeMirror = (function() {
// THE END
- CodeMirror.version = "3.16.0";
+ CodeMirror.version = "3.21.0";
return CodeMirror;
})();
diff --git a/gulliver/js/codemirror/mode/apl/index.html b/gulliver/js/codemirror/mode/apl/index.html
index 119ff17f1..f8282ac42 100644
--- a/gulliver/js/codemirror/mode/apl/index.html
+++ b/gulliver/js/codemirror/mode/apl/index.html
@@ -1,20 +1,32 @@
-
-
-
- CodeMirror: APL mode
-
-
-
-
-
-
-
-
- CodeMirror: APL mode
+
+
+
+
+
+
+
+APL mode
⍝ Conway's game of life
@@ -57,5 +69,4 @@ gen ← {' #'[(life ⍣ ⍵) board]}
have popups etc.
MIME types defined: text/apl (APL code)
-
-
+
diff --git a/gulliver/js/codemirror/mode/asterisk/asterisk.js b/gulliver/js/codemirror/mode/asterisk/asterisk.js
index d491857e9..60b689d1d 100644
--- a/gulliver/js/codemirror/mode/asterisk/asterisk.js
+++ b/gulliver/js/codemirror/mode/asterisk/asterisk.js
@@ -8,7 +8,7 @@
* Created: 05/17/2012 09:20:25 PM
* Revision: none
*
- * Author: Stas Kobzar (stas@modulis.ca),
+ * Author: Stas Kobzar (stas@modulis.ca),
* Company: Modulis.ca Inc.
*
* =====================================================================================
@@ -99,9 +99,9 @@ CodeMirror.defineMode("asterisk", function() {
state.extenStart = true;
switch(cur) {
case 'same': state.extenSame = true; break;
- case 'include':
- case 'switch':
- case 'ignorepat':
+ case 'include':
+ case 'switch':
+ case 'ignorepat':
state.extenInclude = true;break;
default:break;
}
@@ -121,7 +121,7 @@ CodeMirror.defineMode("asterisk", function() {
};
},
token: function(stream, state) {
-
+
var cur = '';
var ch = '';
if(stream.eatSpace()) return null;
@@ -174,7 +174,7 @@ CodeMirror.defineMode("asterisk", function() {
} else{
return basicToken(stream,state);
}
-
+
return null;
}
};
diff --git a/gulliver/js/codemirror/mode/asterisk/index.html b/gulliver/js/codemirror/mode/asterisk/index.html
index 0a796a011..6abdecb50 100644
--- a/gulliver/js/codemirror/mode/asterisk/index.html
+++ b/gulliver/js/codemirror/mode/asterisk/index.html
@@ -1,20 +1,33 @@
-
-
-
- CodeMirror: Asterisk dialplan mode
-
-
-
-
-
-
-
- CodeMirror: Asterisk dialplan mode
-
+
+
+
+
+
+
+
+
+Asterisk dialplan mode
+
; extensions.conf - the Asterisk dial plan
;
@@ -138,5 +151,4 @@ exten => 8500,n,Goto(s,6)
MIME types defined: text/x-asterisk.
-
-
+
diff --git a/gulliver/js/codemirror/mode/clike/clike.js b/gulliver/js/codemirror/mode/clike/clike.js
index 1b350aeb8..4e4988dd8 100644
--- a/gulliver/js/codemirror/mode/clike/clike.js
+++ b/gulliver/js/codemirror/mode/clike/clike.js
@@ -150,12 +150,16 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
var closing = firstChar == ctx.type;
if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
- else if (dontAlignCalls && ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
- else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+ else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1);
+ else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
else return ctx.indented + (closing ? 0 : indentUnit);
},
- electricChars: "{}"
+ electricChars: "{}",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//",
+ fold: "brace"
};
});
@@ -199,18 +203,34 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "string";
}
- function mimes(ms, mode) {
- for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
+ function def(mimes, mode) {
+ var words = [];
+ function add(obj) {
+ if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
+ words.push(prop);
+ }
+ add(mode.keywords);
+ add(mode.builtin);
+ add(mode.atoms);
+ if (words.length) {
+ mode.helperType = mimes[0];
+ CodeMirror.registerHelper("hintWords", mimes[0], words);
+ }
+
+ for (var i = 0; i < mimes.length; ++i)
+ CodeMirror.defineMIME(mimes[i], mode);
}
- mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
+ def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
name: "clike",
keywords: words(cKeywords),
blockKeywords: words("case do else for if switch while struct"),
atoms: words("null"),
- hooks: {"#": cppHook}
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
});
- mimes(["text/x-c++src", "text/x-c++hdr"], {
+
+ def(["text/x-c++src", "text/x-c++hdr"], {
name: "clike",
keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
"static_cast typeid catch operator template typename class friend private " +
@@ -218,11 +238,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
"wchar_t"),
blockKeywords: words("catch class do else finally for if struct switch try while"),
atoms: words("true false null"),
- hooks: {"#": cppHook}
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
});
CodeMirror.defineMIME("text/x-java", {
name: "clike",
- keywords: words("abstract assert boolean break byte case catch char class const continue default " +
+ keywords: words("abstract assert boolean break byte case catch char class const continue default " +
"do double else enum extends final finally float for goto if implements import " +
"instanceof int interface long native new package private protected public " +
"return short static strictfp super switch synchronized this throw throws transient " +
@@ -234,16 +255,17 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$_]/);
return "meta";
}
- }
+ },
+ modeProps: {fold: ["brace", "import"]}
});
CodeMirror.defineMIME("text/x-csharp", {
name: "clike",
- keywords: words("abstract as base break case catch checked class const continue" +
- " default delegate do else enum event explicit extern finally fixed for" +
- " foreach goto if implicit in interface internal is lock namespace new" +
- " operator out override params private protected public readonly ref return sealed" +
- " sizeof stackalloc static struct switch this throw try typeof unchecked" +
- " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
+ keywords: words("abstract as base break case catch checked class const continue" +
+ " default delegate do else enum event explicit extern finally fixed for" +
+ " foreach goto if implicit in interface internal is lock namespace new" +
+ " operator out override params private protected public readonly ref return sealed" +
+ " sizeof stackalloc static struct switch this throw try typeof unchecked" +
+ " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
" global group into join let orderby partial remove select set value var yield"),
blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
@@ -265,30 +287,30 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
CodeMirror.defineMIME("text/x-scala", {
name: "clike",
keywords: words(
-
+
/* scala */
"abstract case catch class def do else extends false final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
"<% >: # @ " +
-
+
/* package scala */
"assert assume require print println printf readLine readBoolean readByte readShort " +
"readChar readInt readLong readFloat readDouble " +
-
+
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
-
- /* package java.lang */
+
+ /* package java.lang */
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
-
-
+
+
),
blockKeywords: words("catch class do else finally for forSome if match switch try while"),
atoms: words("true false null"),
@@ -299,4 +321,61 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
});
+ def(["x-shader/x-vertex", "x-shader/x-fragment"], {
+ name: "clike",
+ keywords: words("float int bool void " +
+ "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
+ "mat2 mat3 mat4 " +
+ "sampler1D sampler2D sampler3D samplerCube " +
+ "sampler1DShadow sampler2DShadow" +
+ "const attribute uniform varying " +
+ "break continue discard return " +
+ "for while do if else struct " +
+ "in out inout"),
+ blockKeywords: words("for while do if else struct"),
+ builtin: words("radians degrees sin cos tan asin acos atan " +
+ "pow exp log exp2 sqrt inversesqrt " +
+ "abs sign floor ceil fract mod min max clamp mix step smootstep " +
+ "length distance dot cross normalize ftransform faceforward " +
+ "reflect refract matrixCompMult " +
+ "lessThan lessThanEqual greaterThan greaterThanEqual " +
+ "equal notEqual any all not " +
+ "texture1D texture1DProj texture1DLod texture1DProjLod " +
+ "texture2D texture2DProj texture2DLod texture2DProjLod " +
+ "texture3D texture3DProj texture3DLod texture3DProjLod " +
+ "textureCube textureCubeLod " +
+ "shadow1D shadow2D shadow1DProj shadow2DProj " +
+ "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
+ "dFdx dFdy fwidth " +
+ "noise1 noise2 noise3 noise4"),
+ atoms: words("true false " +
+ "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
+ "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
+ "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
+ "gl_FogCoord " +
+ "gl_Position gl_PointSize gl_ClipVertex " +
+ "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
+ "gl_TexCoord gl_FogFragCoord " +
+ "gl_FragCoord gl_FrontFacing " +
+ "gl_FragColor gl_FragData gl_FragDepth " +
+ "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
+ "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
+ "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
+ "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
+ "gl_ProjectionMatrixInverseTranspose " +
+ "gl_ModelViewProjectionMatrixInverseTranspose " +
+ "gl_TextureMatrixInverseTranspose " +
+ "gl_NormalScale gl_DepthRange gl_ClipPlane " +
+ "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
+ "gl_FrontLightModelProduct gl_BackLightModelProduct " +
+ "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
+ "gl_FogParameters " +
+ "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
+ "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
+ "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
+ "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
+ "gl_MaxDrawBuffers"),
+ hooks: {"#": cppHook},
+ modeProps: {fold: ["brace", "include"]}
+ });
}());
diff --git a/gulliver/js/codemirror/mode/clike/index.html b/gulliver/js/codemirror/mode/clike/index.html
index 5f90394d9..93bd718a0 100644
--- a/gulliver/js/codemirror/mode/clike/index.html
+++ b/gulliver/js/codemirror/mode/clike/index.html
@@ -1,19 +1,32 @@
-
-
-
- CodeMirror: C-like mode
-
-
-
-
-
-
-
-
- CodeMirror: C-like mode
-
+CodeMirror: C-like mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+C-like mode
+
+
/* C demo code */
#include
@@ -79,14 +92,94 @@ void* zmq_thread_init(void* zmq_context, int signal_fd) {
pthread_detach(thread);
return context;
}
-
+
+
+C++ example
+
+
+#include
+#include "mystuff/util.h"
+
+namespace {
+enum Enum {
+ VAL1, VAL2, VAL3
+};
+
+int Helper(const MyType& param) {
+ return 0;
+}
+} // namespace
+
+class ForwardDec;
+
+template
+class Class : public BaseClass {
+ const MyType member_;
+
+ public:
+ const MyType& Method() const {
+ return member_;
+ }
+
+ void Method2(MyType* value);
+}
+
+template
+void Class::Method2(MyType* value) {
+ std::out << 1 >> method();
+ value->Method3(member_);
+ member_ = value;
+}
+
+
+Java example
+
+
+import com.demo.util.MyType;
+import com.demo.util.MyInterface;
+
+public enum Enum {
+ VAL1, VAL2, VAL3
+}
+
+public class Class implements MyInterface {
+ public static final MyType member;
+
+ private class InnerClass {
+ public int zero() {
+ return 0;
+ }
+ }
+
+ @Override
+ public MyType method() {
+ return member;
+ }
+
+ public void method2(MyType value) {
+ method();
+ value.method3();
+ member = value;
+ }
+}
+
Simple mode that tries to handle C-like languages as well as it
@@ -99,5 +192,4 @@ void* zmq_thread_init(void* zmq_context, int signal_fd) {
(C code), text/x-c++src (C++
code), text/x-java (Java
code), text/x-csharp (C#).
-
-
+
diff --git a/gulliver/js/codemirror/mode/clike/scala.html b/gulliver/js/codemirror/mode/clike/scala.html
index f3c7eea49..e9acc049b 100644
--- a/gulliver/js/codemirror/mode/clike/scala.html
+++ b/gulliver/js/codemirror/mode/clike/scala.html
@@ -1,29 +1,30 @@
-
-
-
- CodeMirror: C-like mode
-
-
-
-
-
-
-
-
-
+
+CodeMirror: Scala mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Scala mode
@@ -763,5 +764,4 @@
mode: "text/x-scala"
});
-
-
+
diff --git a/gulliver/js/codemirror/mode/clojure/clojure.js b/gulliver/js/codemirror/mode/clojure/clojure.js
index 658ff140e..ee22a12fe 100644
--- a/gulliver/js/codemirror/mode/clojure/clojure.js
+++ b/gulliver/js/codemirror/mode/clojure/clojure.js
@@ -14,7 +14,7 @@ CodeMirror.defineMode("clojure", function () {
}
var atoms = makeKeywords("true false nil");
-
+
var keywords = makeKeywords(
"defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
@@ -44,8 +44,7 @@ CodeMirror.defineMode("clojure", function () {
sign: /[+-]/,
exponent: /e/i,
keyword_char: /[^\s\(\[\;\)\]]/,
- basic: /[\w\$_\-]/,
- lang_keyword: /[\w*+!\-_?:\/]/
+ symbol: /[\w*+!\-\._?:\/]/
};
function stateStack(indent, type, prev) { // represents a state stack object
@@ -195,10 +194,10 @@ CodeMirror.defineMode("clojure", function () {
popStack(state);
}
} else if ( ch == ":" ) {
- stream.eatWhile(tests.lang_keyword);
+ stream.eatWhile(tests.symbol);
return ATOM;
} else {
- stream.eatWhile(tests.basic);
+ stream.eatWhile(tests.symbol);
if (keywords && keywords.propertyIsEnumerable(stream.current())) {
returnType = KEYWORD;
@@ -216,7 +215,9 @@ CodeMirror.defineMode("clojure", function () {
indent: function (state) {
if (state.indentStack == null) return state.indentation;
return state.indentStack.indent;
- }
+ },
+
+ lineComment: ";;"
};
});
diff --git a/gulliver/js/codemirror/mode/clojure/index.html b/gulliver/js/codemirror/mode/clojure/index.html
index bfe6fc955..5a50c566f 100644
--- a/gulliver/js/codemirror/mode/clojure/index.html
+++ b/gulliver/js/codemirror/mode/clojure/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Clojure mode
-
-
-
-
-
-
-
- CodeMirror: Clojure mode
-
+
+CodeMirror: Clojure mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Clojure mode
+
; Conway's Game of Life, based on the work of:
;; Laurent Petit https://gist.github.com/1200343
;; Christophe Grand http://clj-me.cgrand.net/2011/08/19/conways-game-of-life
@@ -72,5 +85,4 @@
MIME types defined: text/x-clojure.
-
-
+
diff --git a/gulliver/js/codemirror/mode/coffeescript/LICENSE b/gulliver/js/codemirror/mode/coffeescript/LICENSE
deleted file mode 100644
index 977e284e0..000000000
--- a/gulliver/js/codemirror/mode/coffeescript/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License
-
-Copyright (c) 2011 Jeff Pickhardt
-Modified from the Python CodeMirror mode, Copyright (c) 2010 Timothy Farrell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
\ No newline at end of file
diff --git a/gulliver/js/codemirror/mode/coffeescript/coffeescript.js b/gulliver/js/codemirror/mode/coffeescript/coffeescript.js
index 4d925037c..0e9e6352f 100644
--- a/gulliver/js/codemirror/mode/coffeescript/coffeescript.js
+++ b/gulliver/js/codemirror/mode/coffeescript/coffeescript.js
@@ -2,345 +2,352 @@
* Link to the project's GitHub page:
* https://github.com/pickhardt/coffeescript-codemirror-mode
*/
-CodeMirror.defineMode('coffeescript', function(conf) {
- var ERRORCLASS = 'error';
+CodeMirror.defineMode("coffeescript", function(conf) {
+ var ERRORCLASS = "error";
- function wordRegexp(words) {
- return new RegExp("^((" + words.join(")|(") + "))\\b");
+ function wordRegexp(words) {
+ return new RegExp("^((" + words.join(")|(") + "))\\b");
+ }
+
+ var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?)/;
+ var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;
+ var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;
+ var properties = /^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/;
+
+ var wordOperators = wordRegexp(["and", "or", "not",
+ "is", "isnt", "in",
+ "instanceof", "typeof"]);
+ var indentKeywords = ["for", "while", "loop", "if", "unless", "else",
+ "switch", "try", "catch", "finally", "class"];
+ var commonKeywords = ["break", "by", "continue", "debugger", "delete",
+ "do", "in", "of", "new", "return", "then",
+ "this", "throw", "when", "until"];
+
+ var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
+
+ indentKeywords = wordRegexp(indentKeywords);
+
+
+ var stringPrefixes = /^('{3}|\"{3}|['\"])/;
+ var regexPrefixes = /^(\/{3}|\/)/;
+ var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"];
+ var constants = wordRegexp(commonConstants);
+
+ // Tokenizers
+ function tokenBase(stream, state) {
+ // Handle scope changes
+ if (stream.sol()) {
+ if (state.scope.align === null) state.scope.align = false;
+ var scopeOffset = state.scope.offset;
+ if (stream.eatSpace()) {
+ var lineOffset = stream.indentation();
+ if (lineOffset > scopeOffset && state.scope.type == "coffee") {
+ return "indent";
+ } else if (lineOffset < scopeOffset) {
+ return "dedent";
+ }
+ return null;
+ } else {
+ if (scopeOffset > 0) {
+ dedent(stream, state);
+ }
+ }
+ }
+ if (stream.eatSpace()) {
+ return null;
}
- var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
- var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\},:`=;\\.]');
- var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
- var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
- var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
- var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*");
- var properties = new RegExp("^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*");
+ var ch = stream.peek();
- var wordOperators = wordRegexp(['and', 'or', 'not',
- 'is', 'isnt', 'in',
- 'instanceof', 'typeof']);
- var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else',
- 'switch', 'try', 'catch', 'finally', 'class'];
- var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete',
- 'do', 'in', 'of', 'new', 'return', 'then',
- 'this', 'throw', 'when', 'until'];
-
- var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
-
- indentKeywords = wordRegexp(indentKeywords);
-
-
- var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])");
- var regexPrefixes = new RegExp("^(/{3}|/)");
- var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no'];
- var constants = wordRegexp(commonConstants);
-
- // Tokenizers
- function tokenBase(stream, state) {
- // Handle scope changes
- if (stream.sol()) {
- var scopeOffset = state.scopes[0].offset;
- if (stream.eatSpace()) {
- var lineOffset = stream.indentation();
- if (lineOffset > scopeOffset) {
- return 'indent';
- } else if (lineOffset < scopeOffset) {
- return 'dedent';
- }
- return null;
- } else {
- if (scopeOffset > 0) {
- dedent(stream, state);
- }
- }
- }
- if (stream.eatSpace()) {
- return null;
- }
-
- var ch = stream.peek();
-
- // Handle docco title comment (single line)
- if (stream.match("####")) {
- stream.skipToEnd();
- return 'comment';
- }
-
- // Handle multi line comments
- if (stream.match("###")) {
- state.tokenize = longComment;
- return state.tokenize(stream, state);
- }
-
- // Single line comment
- if (ch === '#') {
- stream.skipToEnd();
- return 'comment';
- }
-
- // Handle number literals
- if (stream.match(/^-?[0-9\.]/, false)) {
- var floatLiteral = false;
- // Floats
- if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
- floatLiteral = true;
- }
- if (stream.match(/^-?\d+\.\d*/)) {
- floatLiteral = true;
- }
- if (stream.match(/^-?\.\d+/)) {
- floatLiteral = true;
- }
-
- if (floatLiteral) {
- // prevent from getting extra . on 1..
- if (stream.peek() == "."){
- stream.backUp(1);
- }
- return 'number';
- }
- // Integers
- var intLiteral = false;
- // Hex
- if (stream.match(/^-?0x[0-9a-f]+/i)) {
- intLiteral = true;
- }
- // Decimal
- if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
- intLiteral = true;
- }
- // Zero by itself with no other piece of number.
- if (stream.match(/^-?0(?![\dx])/i)) {
- intLiteral = true;
- }
- if (intLiteral) {
- return 'number';
- }
- }
-
- // Handle strings
- if (stream.match(stringPrefixes)) {
- state.tokenize = tokenFactory(stream.current(), 'string');
- return state.tokenize(stream, state);
- }
- // Handle regex literals
- if (stream.match(regexPrefixes)) {
- if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division
- state.tokenize = tokenFactory(stream.current(), 'string-2');
- return state.tokenize(stream, state);
- } else {
- stream.backUp(1);
- }
- }
-
- // Handle operators and delimiters
- if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
- return 'punctuation';
- }
- if (stream.match(doubleOperators)
- || stream.match(singleOperators)
- || stream.match(wordOperators)) {
- return 'operator';
- }
- if (stream.match(singleDelimiters)) {
- return 'punctuation';
- }
-
- if (stream.match(constants)) {
- return 'atom';
- }
-
- if (stream.match(keywords)) {
- return 'keyword';
- }
-
- if (stream.match(identifiers)) {
- return 'variable';
- }
-
- if (stream.match(properties)) {
- return 'property';
- }
-
- // Handle non-detected items
- stream.next();
- return ERRORCLASS;
+ // Handle docco title comment (single line)
+ if (stream.match("####")) {
+ stream.skipToEnd();
+ return "comment";
}
- function tokenFactory(delimiter, outclass) {
- var singleline = delimiter.length == 1;
- return function(stream, state) {
- while (!stream.eol()) {
- stream.eatWhile(/[^'"\/\\]/);
- if (stream.eat('\\')) {
- stream.next();
- if (singleline && stream.eol()) {
- return outclass;
- }
- } else if (stream.match(delimiter)) {
- state.tokenize = tokenBase;
- return outclass;
- } else {
- stream.eat(/['"\/]/);
- }
- }
- if (singleline) {
- if (conf.mode.singleLineStringErrors) {
- outclass = ERRORCLASS;
- } else {
- state.tokenize = tokenBase;
- }
- }
+ // Handle multi line comments
+ if (stream.match("###")) {
+ state.tokenize = longComment;
+ return state.tokenize(stream, state);
+ }
+
+ // Single line comment
+ if (ch === "#") {
+ stream.skipToEnd();
+ return "comment";
+ }
+
+ // Handle number literals
+ if (stream.match(/^-?[0-9\.]/, false)) {
+ var floatLiteral = false;
+ // Floats
+ if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
+ floatLiteral = true;
+ }
+ if (stream.match(/^-?\d+\.\d*/)) {
+ floatLiteral = true;
+ }
+ if (stream.match(/^-?\.\d+/)) {
+ floatLiteral = true;
+ }
+
+ if (floatLiteral) {
+ // prevent from getting extra . on 1..
+ if (stream.peek() == "."){
+ stream.backUp(1);
+ }
+ return "number";
+ }
+ // Integers
+ var intLiteral = false;
+ // Hex
+ if (stream.match(/^-?0x[0-9a-f]+/i)) {
+ intLiteral = true;
+ }
+ // Decimal
+ if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
+ intLiteral = true;
+ }
+ // Zero by itself with no other piece of number.
+ if (stream.match(/^-?0(?![\dx])/i)) {
+ intLiteral = true;
+ }
+ if (intLiteral) {
+ return "number";
+ }
+ }
+
+ // Handle strings
+ if (stream.match(stringPrefixes)) {
+ state.tokenize = tokenFactory(stream.current(), false, "string");
+ return state.tokenize(stream, state);
+ }
+ // Handle regex literals
+ if (stream.match(regexPrefixes)) {
+ if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division
+ state.tokenize = tokenFactory(stream.current(), true, "string-2");
+ return state.tokenize(stream, state);
+ } else {
+ stream.backUp(1);
+ }
+ }
+
+ // Handle operators and delimiters
+ if (stream.match(operators) || stream.match(wordOperators)) {
+ return "operator";
+ }
+ if (stream.match(delimiters)) {
+ return "punctuation";
+ }
+
+ if (stream.match(constants)) {
+ return "atom";
+ }
+
+ if (stream.match(keywords)) {
+ return "keyword";
+ }
+
+ if (stream.match(identifiers)) {
+ return "variable";
+ }
+
+ if (stream.match(properties)) {
+ return "property";
+ }
+
+ // Handle non-detected items
+ stream.next();
+ return ERRORCLASS;
+ }
+
+ function tokenFactory(delimiter, singleline, outclass) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^'"\/\\]/);
+ if (stream.eat("\\")) {
+ stream.next();
+ if (singleline && stream.eol()) {
return outclass;
- };
- }
-
- function longComment(stream, state) {
- while (!stream.eol()) {
- stream.eatWhile(/[^#]/);
- if (stream.match("###")) {
- state.tokenize = tokenBase;
- break;
- }
- stream.eatWhile("#");
- }
- return "comment";
- }
-
- function indent(stream, state, type) {
- type = type || 'coffee';
- var indentUnit = 0;
- if (type === 'coffee') {
- for (var i = 0; i < state.scopes.length; i++) {
- if (state.scopes[i].type === 'coffee') {
- indentUnit = state.scopes[i].offset + conf.indentUnit;
- break;
- }
- }
+ }
+ } else if (stream.match(delimiter)) {
+ state.tokenize = tokenBase;
+ return outclass;
} else {
- indentUnit = stream.column() + stream.current().length;
+ stream.eat(/['"\/]/);
}
- state.scopes.unshift({
- offset: indentUnit,
- type: type
- });
- }
-
- function dedent(stream, state) {
- if (state.scopes.length == 1) return;
- if (state.scopes[0].type === 'coffee') {
- var _indent = stream.indentation();
- var _indent_index = -1;
- for (var i = 0; i < state.scopes.length; ++i) {
- if (_indent === state.scopes[i].offset) {
- _indent_index = i;
- break;
- }
- }
- if (_indent_index === -1) {
- return true;
- }
- while (state.scopes[0].offset !== _indent) {
- state.scopes.shift();
- }
- return false;
+ }
+ if (singleline) {
+ if (conf.mode.singleLineStringErrors) {
+ outclass = ERRORCLASS;
} else {
- state.scopes.shift();
- return false;
+ state.tokenize = tokenBase;
}
- }
-
- function tokenLexer(stream, state) {
- var style = state.tokenize(stream, state);
- var current = stream.current();
-
- // Handle '.' connected identifiers
- if (current === '.') {
- style = state.tokenize(stream, state);
- current = stream.current();
- if (style === 'variable') {
- return 'variable';
- } else {
- return ERRORCLASS;
- }
- }
-
- // Handle scope changes.
- if (current === 'return') {
- state.dedent += 1;
- }
- if (((current === '->' || current === '=>') &&
- !state.lambda &&
- state.scopes[0].type == 'coffee' &&
- stream.peek() === '')
- || style === 'indent') {
- indent(stream, state);
- }
- var delimiter_index = '[({'.indexOf(current);
- if (delimiter_index !== -1) {
- indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
- }
- if (indentKeywords.exec(current)){
- indent(stream, state);
- }
- if (current == 'then'){
- dedent(stream, state);
- }
-
-
- if (style === 'dedent') {
- if (dedent(stream, state)) {
- return ERRORCLASS;
- }
- }
- delimiter_index = '])}'.indexOf(current);
- if (delimiter_index !== -1) {
- if (dedent(stream, state)) {
- return ERRORCLASS;
- }
- }
- if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
- if (state.scopes.length > 1) state.scopes.shift();
- state.dedent -= 1;
- }
-
- return style;
- }
-
- var external = {
- startState: function(basecolumn) {
- return {
- tokenize: tokenBase,
- scopes: [{offset:basecolumn || 0, type:'coffee'}],
- lastToken: null,
- lambda: false,
- dedent: 0
- };
- },
-
- token: function(stream, state) {
- var style = tokenLexer(stream, state);
-
- state.lastToken = {style:style, content: stream.current()};
-
- if (stream.eol() && stream.lambda) {
- state.lambda = false;
- }
-
- return style;
- },
-
- indent: function(state) {
- if (state.tokenize != tokenBase) {
- return 0;
- }
-
- return state.scopes[0].offset;
- }
-
+ }
+ return outclass;
};
- return external;
+ }
+
+ function longComment(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^#]/);
+ if (stream.match("###")) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ stream.eatWhile("#");
+ }
+ return "comment";
+ }
+
+ function indent(stream, state, type) {
+ type = type || "coffee";
+ var offset = 0, align = false, alignOffset = null;
+ for (var scope = state.scope; scope; scope = scope.prev) {
+ if (scope.type === "coffee") {
+ offset = scope.offset + conf.indentUnit;
+ break;
+ }
+ }
+ if (type !== "coffee") {
+ align = null;
+ alignOffset = stream.column() + stream.current().length;
+ } else if (state.scope.align) {
+ state.scope.align = false;
+ }
+ state.scope = {
+ offset: offset,
+ type: type,
+ prev: state.scope,
+ align: align,
+ alignOffset: alignOffset
+ };
+ }
+
+ function dedent(stream, state) {
+ if (!state.scope.prev) return;
+ if (state.scope.type === "coffee") {
+ var _indent = stream.indentation();
+ var matched = false;
+ for (var scope = state.scope; scope; scope = scope.prev) {
+ if (_indent === scope.offset) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ return true;
+ }
+ while (state.scope.prev && state.scope.offset !== _indent) {
+ state.scope = state.scope.prev;
+ }
+ return false;
+ } else {
+ state.scope = state.scope.prev;
+ return false;
+ }
+ }
+
+ function tokenLexer(stream, state) {
+ var style = state.tokenize(stream, state);
+ var current = stream.current();
+
+ // Handle "." connected identifiers
+ if (current === ".") {
+ style = state.tokenize(stream, state);
+ current = stream.current();
+ if (/^\.[\w$]+$/.test(current)) {
+ return "variable";
+ } else {
+ return ERRORCLASS;
+ }
+ }
+
+ // Handle scope changes.
+ if (current === "return") {
+ state.dedent += 1;
+ }
+ if (((current === "->" || current === "=>") &&
+ !state.lambda &&
+ !stream.peek())
+ || style === "indent") {
+ indent(stream, state);
+ }
+ var delimiter_index = "[({".indexOf(current);
+ if (delimiter_index !== -1) {
+ indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
+ }
+ if (indentKeywords.exec(current)){
+ indent(stream, state);
+ }
+ if (current == "then"){
+ dedent(stream, state);
+ }
+
+
+ if (style === "dedent") {
+ if (dedent(stream, state)) {
+ return ERRORCLASS;
+ }
+ }
+ delimiter_index = "])}".indexOf(current);
+ if (delimiter_index !== -1) {
+ while (state.scope.type == "coffee" && state.scope.prev)
+ state.scope = state.scope.prev;
+ if (state.scope.type == current)
+ state.scope = state.scope.prev;
+ }
+ if (state.dedent > 0 && stream.eol() && state.scope.type == "coffee") {
+ if (state.scope.prev) state.scope = state.scope.prev;
+ state.dedent -= 1;
+ }
+
+ return style;
+ }
+
+ var external = {
+ startState: function(basecolumn) {
+ return {
+ tokenize: tokenBase,
+ scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},
+ lastToken: null,
+ lambda: false,
+ dedent: 0
+ };
+ },
+
+ token: function(stream, state) {
+ var fillAlign = state.scope.align === null && state.scope;
+ if (fillAlign && stream.sol()) fillAlign.align = false;
+
+ var style = tokenLexer(stream, state);
+ if (fillAlign && style && style != "comment") fillAlign.align = true;
+
+ state.lastToken = {style:style, content: stream.current()};
+
+ if (stream.eol() && stream.lambda) {
+ state.lambda = false;
+ }
+
+ return style;
+ },
+
+ indent: function(state, text) {
+ if (state.tokenize != tokenBase) return 0;
+ var scope = state.scope;
+ var closer = text && "])}".indexOf(text.charAt(0)) > -1;
+ if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev;
+ var closes = closer && scope.type === text.charAt(0);
+ if (scope.align)
+ return scope.alignOffset - (closes ? 1 : 0);
+ else
+ return (closes ? scope.prev : scope).offset;
+ },
+
+ lineComment: "#",
+ fold: "indent"
+ };
+ return external;
});
-CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');
+CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
diff --git a/gulliver/js/codemirror/mode/coffeescript/index.html b/gulliver/js/codemirror/mode/coffeescript/index.html
index ee72b8d2f..6e6fde52e 100644
--- a/gulliver/js/codemirror/mode/coffeescript/index.html
+++ b/gulliver/js/codemirror/mode/coffeescript/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: CoffeeScript mode
-
-
-
-
-
-
-
- CodeMirror: CoffeeScript mode
-
+
+CodeMirror: CoffeeScript mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CoffeeScript mode
+
# CoffeeScript mode for CodeMirror
# Copyright (c) 2011 Jeff Pickhardt, released under
# the MIT License.
@@ -724,5 +737,4 @@ wrapper::value = -> this._wrapped
The CoffeeScript mode was written by Jeff Pickhardt (license ).
-
-
+
diff --git a/gulliver/js/codemirror/mode/commonlisp/commonlisp.js b/gulliver/js/codemirror/mode/commonlisp/commonlisp.js
index eeba75966..8fa08c8ac 100644
--- a/gulliver/js/codemirror/mode/commonlisp/commonlisp.js
+++ b/gulliver/js/codemirror/mode/commonlisp/commonlisp.js
@@ -94,7 +94,11 @@ CodeMirror.defineMode("commonlisp", function (config) {
indent: function (state, _textAfter) {
var i = state.ctx.indentTo;
return typeof i == "number" ? i : state.ctx.start + 1;
- }
+ },
+
+ lineComment: ";;",
+ blockCommentStart: "#|",
+ blockCommentEnd: "|#"
};
});
diff --git a/gulliver/js/codemirror/mode/commonlisp/index.html b/gulliver/js/codemirror/mode/commonlisp/index.html
index f9766a844..d48be8d23 100644
--- a/gulliver/js/codemirror/mode/commonlisp/index.html
+++ b/gulliver/js/codemirror/mode/commonlisp/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Common Lisp mode
-
-
-
-
-
-
-
- CodeMirror: Common Lisp mode
- (in-package :cl-postgres)
+
+CodeMirror: Common Lisp mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Common Lisp mode
+(in-package :cl-postgres)
;; These are used to synthesize reader and writer names for integer
;; reading/writing functions when the amount of bytes and the
@@ -161,5 +174,4 @@ when UTF-8 support is enabled."
MIME types defined: text/x-common-lisp.
-
-
+
diff --git a/gulliver/js/codemirror/mode/css/css.js b/gulliver/js/codemirror/mode/css/css.js
index 1ef72b517..8f6fe7df4 100644
--- a/gulliver/js/codemirror/mode/css/css.js
+++ b/gulliver/js/codemirror/mode/css/css.js
@@ -1,91 +1,82 @@
-CodeMirror.defineMode("css", function(config) {
- return CodeMirror.getMode(config, "text/css");
-});
-
-CodeMirror.defineMode("css-base", function(config, parserConfig) {
+CodeMirror.defineMode("css", function(config, parserConfig) {
"use strict";
+ if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
+
var indentUnit = config.indentUnit,
- hooks = parserConfig.hooks || {},
- atMediaTypes = parserConfig.atMediaTypes || {},
- atMediaFeatures = parserConfig.atMediaFeatures || {},
+ tokenHooks = parserConfig.tokenHooks,
+ mediaTypes = parserConfig.mediaTypes || {},
+ mediaFeatures = parserConfig.mediaFeatures || {},
propertyKeywords = parserConfig.propertyKeywords || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
- allowNested = !!parserConfig.allowNested,
- type = null;
+ fontProperties = parserConfig.fontProperties || {},
+ allowNested = parserConfig.allowNested;
+ var type, override;
function ret(style, tp) { type = tp; return style; }
+ // Tokenizers
+
function tokenBase(stream, state) {
var ch = stream.next();
- if (hooks[ch]) {
- // result[0] is style and result[1] is type
- var result = hooks[ch](stream, state);
+ if (tokenHooks[ch]) {
+ var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
- if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
- else if (ch == "=") ret(null, "compare");
- else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
- else if (ch == "\"" || ch == "'") {
+ if (ch == "@") {
+ stream.eatWhile(/[\w\\\-]/);
+ return ret("def", stream.current());
+ } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
+ return ret(null, "compare");
+ } else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
- }
- else if (ch == "#") {
+ } else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
- }
- else if (ch == "!") {
+ } else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
- }
- else if (/\d/.test(ch)) {
+ } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
- }
- else if (ch === "-") {
- if (/\d/.test(stream.peek())) {
+ } else if (ch === "-") {
+ if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^[^-]+-/)) {
return ret("meta", "meta");
}
- }
- else if (/[,+>*\/]/.test(ch)) {
+ } else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
- }
- else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
+ } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
- }
- else if (ch == ":") {
- return ret("operator", ch);
- }
- else if (/[;{}\[\]\(\)]/.test(ch)) {
+ } else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
- }
- else if (ch == "u" && stream.match("rl(")) {
+ } else if (ch == "u" && stream.match("rl(")) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
- return ret("property", "variable");
- }
- else {
+ return ret("property", "word");
+ } else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
- return ret("property", "variable");
+ return ret("property", "word");
+ } else {
+ return ret(null, null);
}
}
- function tokenString(quote, nonInclusive) {
+ function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
- if (ch == quote && !escaped)
+ if (ch == quote && !escaped) {
+ if (quote == ")") stream.backUp(1);
break;
+ }
escaped = !escaped && ch == "\\";
}
- if (!escaped) {
- if (nonInclusive) stream.backUp(1);
- state.tokenize = tokenBase;
- }
+ if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
@@ -93,197 +84,244 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\']/, false))
- state.tokenize = tokenString(")", true);
+ state.tokenize = tokenString(")");
else
- state.tokenize = tokenBase;
+ state.tokenize = null;
return ret(null, "(");
}
+ // Context management
+
+ function Context(type, indent, prev) {
+ this.type = type;
+ this.indent = indent;
+ this.prev = prev;
+ }
+
+ function pushContext(state, stream, type) {
+ state.context = new Context(type, stream.indentation() + indentUnit, state.context);
+ return type;
+ }
+
+ function popContext(state) {
+ state.context = state.context.prev;
+ return state.context.type;
+ }
+
+ function pass(type, stream, state) {
+ return states[state.context.type](type, stream, state);
+ }
+ function popAndPass(type, stream, state, n) {
+ for (var i = n || 1; i > 0; i--)
+ state.context = state.context.prev;
+ return pass(type, stream, state);
+ }
+
+ // Parser
+
+ function wordAsValue(stream) {
+ var word = stream.current().toLowerCase();
+ if (valueKeywords.hasOwnProperty(word))
+ override = "atom";
+ else if (colorKeywords.hasOwnProperty(word))
+ override = "keyword";
+ else
+ override = "variable";
+ }
+
+ var states = {};
+
+ states.top = function(type, stream, state) {
+ if (type == "{") {
+ return pushContext(state, stream, "block");
+ } else if (type == "}" && state.context.prev) {
+ return popContext(state);
+ } else if (type == "@media") {
+ return pushContext(state, stream, "media");
+ } else if (type == "@font-face") {
+ return "font_face_before";
+ } else if (type && type.charAt(0) == "@") {
+ return pushContext(state, stream, "at");
+ } else if (type == "hash") {
+ override = "builtin";
+ } else if (type == "word") {
+ override = "tag";
+ } else if (type == "variable-definition") {
+ return "maybeprop";
+ } else if (type == "interpolation") {
+ return pushContext(state, stream, "interpolation");
+ } else if (type == ":") {
+ return "pseudo";
+ } else if (allowNested && type == "(") {
+ return pushContext(state, stream, "params");
+ }
+ return state.context.type;
+ };
+
+ states.block = function(type, stream, state) {
+ if (type == "word") {
+ if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) {
+ override = "property";
+ return "maybeprop";
+ } else if (allowNested) {
+ override = stream.match(/^\s*:/, false) ? "property" : "tag";
+ return "block";
+ } else {
+ override += " error";
+ return "maybeprop";
+ }
+ } else if (type == "meta") {
+ return "block";
+ } else if (!allowNested && (type == "hash" || type == "qualifier")) {
+ override = "error";
+ return "block";
+ } else {
+ return states.top(type, stream, state);
+ }
+ };
+
+ states.maybeprop = function(type, stream, state) {
+ if (type == ":") return pushContext(state, stream, "prop");
+ return pass(type, stream, state);
+ };
+
+ states.prop = function(type, stream, state) {
+ if (type == ";") return popContext(state);
+ if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
+ if (type == "}" || type == "{") return popAndPass(type, stream, state);
+ if (type == "(") return pushContext(state, stream, "parens");
+
+ if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
+ override += " error";
+ } else if (type == "word") {
+ wordAsValue(stream);
+ } else if (type == "interpolation") {
+ return pushContext(state, stream, "interpolation");
+ }
+ return "prop";
+ };
+
+ states.propBlock = function(type, _stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "word") { override = "property"; return "maybeprop"; }
+ return state.context.type;
+ };
+
+ states.parens = function(type, stream, state) {
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == ")") return popContext(state);
+ return "parens";
+ };
+
+ states.pseudo = function(type, stream, state) {
+ if (type == "word") {
+ override = "variable-3";
+ return state.context.type;
+ }
+ return pass(type, stream, state);
+ };
+
+ states.media = function(type, stream, state) {
+ if (type == "(") return pushContext(state, stream, "media_parens");
+ if (type == "}") return popAndPass(type, stream, state);
+ if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
+
+ if (type == "word") {
+ var word = stream.current().toLowerCase();
+ if (word == "only" || word == "not" || word == "and")
+ override = "keyword";
+ else if (mediaTypes.hasOwnProperty(word))
+ override = "attribute";
+ else if (mediaFeatures.hasOwnProperty(word))
+ override = "property";
+ else
+ override = "error";
+ }
+ return state.context.type;
+ };
+
+ states.media_parens = function(type, stream, state) {
+ if (type == ")") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
+ return states.media(type, stream, state);
+ };
+
+ states.font_face_before = function(type, stream, state) {
+ if (type == "{")
+ return pushContext(state, stream, "font_face");
+ return pass(type, stream, state);
+ };
+
+ states.font_face = function(type, stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "word") {
+ if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
+ override = "error";
+ else
+ override = "property";
+ return "maybeprop";
+ }
+ return "font_face";
+ };
+
+ states.at = function(type, stream, state) {
+ if (type == ";") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == "word") override = "tag";
+ else if (type == "hash") override = "builtin";
+ return "at";
+ };
+
+ states.interpolation = function(type, stream, state) {
+ if (type == "}") return popContext(state);
+ if (type == "{" || type == ";") return popAndPass(type, stream, state);
+ if (type != "variable") override = "error";
+ return "interpolation";
+ };
+
+ states.params = function(type, stream, state) {
+ if (type == ")") return popContext(state);
+ if (type == "{" || type == "}") return popAndPass(type, stream, state);
+ if (type == "word") wordAsValue(stream);
+ return "params";
+ };
+
return {
startState: function(base) {
- return {tokenize: tokenBase,
- baseIndent: base || 0,
- stack: []};
+ return {tokenize: null,
+ state: "top",
+ context: new Context("top", base || 0, null)};
},
token: function(stream, state) {
-
- // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
- //
- // rule** or **ruleset:
- // A selector + braces combo, or an at-rule.
- //
- // declaration block:
- // A sequence of declarations.
- //
- // declaration:
- // A property + colon + value combo.
- //
- // property value:
- // The entire value of a property.
- //
- // component value:
- // A single piece of a property value. Like the 5px in
- // text-shadow: 0 0 5px blue;. Can also refer to things that are
- // multiple terms, like the 1-4 terms that make up the background-size
- // portion of the background shorthand.
- //
- // term:
- // The basic unit of author-facing CSS, like a single number (5),
- // dimension (5px), string ("foo"), or function. Officially defined
- // by the CSS 2.1 grammar (look for the 'term' production)
- //
- //
- // simple selector:
- // A single atomic selector, like a type selector, an attr selector, a
- // class selector, etc.
- //
- // compound selector:
- // One or more simple selectors without a combinator. div.example is
- // compound, div > .example is not.
- //
- // complex selector:
- // One or more compound selectors chained with combinators.
- //
- // combinator:
- // The parts of selectors that express relationships. There are four
- // currently - the space (descendant combinator), the greater-than
- // bracket (child combinator), the plus sign (next sibling combinator),
- // and the tilda (following sibling combinator).
- //
- // sequence of selectors:
- // One or more of the named type of selector chained with commas.
-
- state.tokenize = state.tokenize || tokenBase;
- if (state.tokenize == tokenBase && stream.eatSpace()) return null;
- var style = state.tokenize(stream, state);
- if (style && typeof style != "string") style = ret(style[0], style[1]);
-
- // Changing style returned based on context
- var context = state.stack[state.stack.length-1];
- if (style == "variable") {
- if (type == "variable-definition") state.stack.push("propertyValue");
- return "variable-2";
- } else if (style == "property") {
- if (context == "propertyValue"){
- if (valueKeywords[stream.current()]) {
- style = "string-2";
- } else if (colorKeywords[stream.current()]) {
- style = "keyword";
- } else {
- style = "variable-2";
- }
- } else if (context == "rule") {
- if (!propertyKeywords[stream.current()]) {
- style += " error";
- }
- } else if (context == "block") {
- // if a value is present in both property, value, or color, the order
- // of preference is property -> color -> value
- if (propertyKeywords[stream.current()]) {
- style = "property";
- } else if (colorKeywords[stream.current()]) {
- style = "keyword";
- } else if (valueKeywords[stream.current()]) {
- style = "string-2";
- } else {
- style = "tag";
- }
- } else if (!context || context == "@media{") {
- style = "tag";
- } else if (context == "@media") {
- if (atMediaTypes[stream.current()]) {
- style = "attribute"; // Known attribute
- } else if (/^(only|not)$/i.test(stream.current())) {
- style = "keyword";
- } else if (stream.current().toLowerCase() == "and") {
- style = "error"; // "and" is only allowed in @mediaType
- } else if (atMediaFeatures[stream.current()]) {
- style = "error"; // Known property, should be in @mediaType(
- } else {
- // Unknown, expecting keyword or attribute, assuming attribute
- style = "attribute error";
- }
- } else if (context == "@mediaType") {
- if (atMediaTypes[stream.current()]) {
- style = "attribute";
- } else if (stream.current().toLowerCase() == "and") {
- style = "operator";
- } else if (/^(only|not)$/i.test(stream.current())) {
- style = "error"; // Only allowed in @media
- } else if (atMediaFeatures[stream.current()]) {
- style = "error"; // Known property, should be in parentheses
- } else {
- // Unknown attribute or property, but expecting property (preceded
- // by "and"). Should be in parentheses
- style = "error";
- }
- } else if (context == "@mediaType(") {
- if (propertyKeywords[stream.current()]) {
- // do nothing, remains "property"
- } else if (atMediaTypes[stream.current()]) {
- style = "error"; // Known property, should be in parentheses
- } else if (stream.current().toLowerCase() == "and") {
- style = "operator";
- } else if (/^(only|not)$/i.test(stream.current())) {
- style = "error"; // Only allowed in @media
- } else {
- style += " error";
- }
- } else {
- style = "error";
- }
- } else if (style == "atom") {
- if(!context || context == "@media{" || context == "block") {
- style = "builtin";
- } else if (context == "propertyValue") {
- if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
- style += " error";
- }
- } else {
- style = "error";
- }
- } else if (context == "@media" && type == "{") {
- style = "error";
+ if (!state.tokenize && stream.eatSpace()) return null;
+ var style = (state.tokenize || tokenBase)(stream, state);
+ if (style && typeof style == "object") {
+ type = style[1];
+ style = style[0];
}
-
- // Push/pop context stack
- if (type == "{") {
- if (context == "@media" || context == "@mediaType") {
- state.stack.pop();
- state.stack[state.stack.length-1] = "@media{";
- }
- else {
- var newContext = allowNested ? "block" : "rule";
- state.stack.push(newContext);
- }
- }
- else if (type == "}") {
- var lastState = state.stack[state.stack.length - 1];
- if (lastState == "interpolation") style = "operator";
- state.stack.pop();
- if (context == "propertyValue") state.stack.pop();
- }
- else if (type == "interpolation") state.stack.push("interpolation");
- else if (type == "@media") state.stack.push("@media");
- else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
- state.stack.push("@mediaType");
- else if (context == "@mediaType" && stream.current() == ",") state.stack.pop();
- else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType(");
- else if (context == "@mediaType(" && type == ")") state.stack.pop();
- else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue");
- else if (context == "propertyValue" && type == ";") state.stack.pop();
- return style;
+ override = style;
+ state.state = states[state.state](type, stream, state);
+ return override;
},
indent: function(state, textAfter) {
- var n = state.stack.length;
- if (/^\}/.test(textAfter))
- n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1;
- return state.baseIndent + n * indentUnit;
+ var cx = state.context, ch = textAfter && textAfter.charAt(0);
+ var indent = cx.indent;
+ if (cx.prev &&
+ (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") ||
+ ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") ||
+ ch == "{" && (cx.type == "at" || cx.type == "media"))) {
+ indent = cx.indent - indentUnit;
+ cx = cx.prev;
+ }
+ return indent;
},
- electricChars: "}"
+ electricChars: "}",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ fold: "brace"
};
});
@@ -296,12 +334,12 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
return keys;
}
- var atMediaTypes = keySet([
+ var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
- ]);
+ ], mediaTypes = keySet(mediaTypes_);
- var atMediaFeatures = keySet([
+ var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
@@ -310,9 +348,9 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
- ]);
+ ], mediaFeatures = keySet(mediaFeatures_);
- var propertyKeywords = keySet([
+ var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
@@ -344,8 +382,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
- "float", "float-offset", "font", "font-feature-settings", "font-family",
- "font-kerning", "font-language-override", "font-size", "font-size-adjust",
+ "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
+ "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
@@ -369,52 +407,88 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
- "presentation-level", "punctuation-trim", "quotes", "rendering-intent",
- "resize", "rest", "rest-after", "rest-before", "richness", "right",
- "rotation", "rotation-point", "ruby-align", "ruby-overhang",
- "ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header",
+ "presentation-level", "punctuation-trim", "quotes", "region-break-after",
+ "region-break-before", "region-break-inside", "region-fragment",
+ "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
+ "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
+ "ruby-position", "ruby-span", "shape-inside", "shape-outside", "size",
+ "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
- "text-indent", "text-justify", "text-outline", "text-shadow",
- "text-space-collapse", "text-transform", "text-underline-position",
+ "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
+ "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
- "word-spacing", "word-wrap", "z-index"
- ]);
+ "word-spacing", "word-wrap", "z-index", "zoom",
+ // SVG-specific
+ "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
+ "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
+ "color-interpolation", "color-interpolation-filters", "color-profile",
+ "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
+ "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
+ "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
+ "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
+ "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
+ "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
+ ], propertyKeywords = keySet(propertyKeywords_);
- var colorKeywords = keySet([
- "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia",
- "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua"
- ]);
+ var colorKeywords_ = [
+ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
+ "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
+ "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
+ "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
+ "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
+ "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
+ "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
+ "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
+ "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
+ "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
+ "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
+ "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
+ "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
+ "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
+ "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
+ "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
+ "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+ "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
+ "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
+ "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
+ "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
+ "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
+ "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
+ "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
+ "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
+ "whitesmoke", "yellow", "yellowgreen"
+ ], colorKeywords = keySet(colorKeywords_);
- var valueKeywords = keySet([
+ var valueKeywords_ = [
"above", "absolute", "activeborder", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
- "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background",
- "backwards", "baseline", "below", "bidi-override", "binary", "bengali",
- "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
- "both", "bottom", "break-all", "break-word", "button", "button-bevel",
+ "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
+ "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
+ "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
+ "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
- "col-resize", "collapse", "compact", "condensed", "contain", "content",
+ "col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari",
"disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
"double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
- "element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
+ "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
@@ -430,7 +504,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
- "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer",
+ "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
"landscape", "lao", "large", "larger", "left", "level", "lighter",
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
@@ -449,11 +523,11 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
- "outside", "overlay", "overline", "padding", "padding-box", "painted",
- "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait",
- "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
- "radio", "read-only", "read-write", "read-write-plaintext-only", "relative",
- "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
+ "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
+ "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
+ "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
+ "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
+ "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
@@ -475,10 +549,18 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
- "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider",
+ "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
"xx-large", "xx-small"
- ]);
+ ], valueKeywords = keySet(valueKeywords_);
+
+ var fontProperties_ = [
+ "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
+ "font-stretch", "font-weight", "font-style"
+ ], fontProperties = keySet(fontProperties_);
+
+ var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
+ CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
@@ -492,56 +574,47 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
return ["comment", "comment"];
}
+ function tokenSGMLComment(stream, state) {
+ if (stream.skipTo("-->")) {
+ stream.match("-->");
+ state.tokenize = null;
+ } else {
+ stream.skipToEnd();
+ }
+ return ["comment", "comment"];
+ }
+
CodeMirror.defineMIME("text/css", {
- atMediaTypes: atMediaTypes,
- atMediaFeatures: atMediaFeatures,
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
- hooks: {
+ fontProperties: fontProperties,
+ tokenHooks: {
"<": function(stream, state) {
- function tokenSGMLComment(stream, state) {
- var dashes = 0, ch;
- while ((ch = stream.next()) != null) {
- if (dashes >= 2 && ch == ">") {
- state.tokenize = null;
- break;
- }
- dashes = (ch == "-") ? dashes + 1 : 0;
- }
- return ["comment", "comment"];
- }
- if (stream.eat("!")) {
- state.tokenize = tokenSGMLComment;
- return tokenSGMLComment(stream, state);
- }
+ if (!stream.match("!--")) return false;
+ state.tokenize = tokenSGMLComment;
+ return tokenSGMLComment(stream, state);
},
"/": function(stream, state) {
- if (stream.eat("*")) {
- state.tokenize = tokenCComment;
- return tokenCComment(stream, state);
- }
- return false;
+ if (!stream.eat("*")) return false;
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
}
},
- name: "css-base"
+ name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
- atMediaTypes: atMediaTypes,
- atMediaFeatures: atMediaFeatures,
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
+ fontProperties: fontProperties,
allowNested: true,
- hooks: {
- "$": function(stream) {
- stream.match(/^[\w-]+/);
- if (stream.peek() == ":") {
- return ["variable", "variable-definition"];
- }
- return ["variable", "variable"];
- },
+ tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
@@ -553,15 +626,58 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) {
return ["operator", "operator"];
}
},
+ ":": function(stream) {
+ if (stream.match(/\s*{/))
+ return [null, "{"];
+ return false;
+ },
+ "$": function(stream) {
+ stream.match(/^[\w-]+/);
+ if (stream.match(/^\s*:/, false))
+ return ["variable-2", "variable-definition"];
+ return ["variable-2", "variable"];
+ },
"#": function(stream) {
- if (stream.eat("{")) {
- return ["operator", "interpolation"];
- } else {
- stream.eatWhile(/[\w\\\-]/);
- return ["atom", "hash"];
- }
+ if (!stream.eat("{")) return false;
+ return [null, "interpolation"];
}
},
- name: "css-base"
+ name: "css",
+ helperType: "scss"
+ });
+
+ CodeMirror.defineMIME("text/x-less", {
+ mediaTypes: mediaTypes,
+ mediaFeatures: mediaFeatures,
+ propertyKeywords: propertyKeywords,
+ colorKeywords: colorKeywords,
+ valueKeywords: valueKeywords,
+ fontProperties: fontProperties,
+ allowNested: true,
+ tokenHooks: {
+ "/": function(stream, state) {
+ if (stream.eat("/")) {
+ stream.skipToEnd();
+ return ["comment", "comment"];
+ } else if (stream.eat("*")) {
+ state.tokenize = tokenCComment;
+ return tokenCComment(stream, state);
+ } else {
+ return ["operator", "operator"];
+ }
+ },
+ "@": function(stream) {
+ if (stream.match(/^(charset|document|font-face|import|keyframes|media|namespace|page|supports)\b/, false)) return false;
+ stream.eatWhile(/[\w\\\-]/);
+ if (stream.match(/^\s*:/, false))
+ return ["variable-2", "variable-definition"];
+ return ["variable-2", "variable"];
+ },
+ "&": function() {
+ return ["atom", "atom"];
+ }
+ },
+ name: "css",
+ helperType: "less"
});
})();
diff --git a/gulliver/js/codemirror/mode/css/index.html b/gulliver/js/codemirror/mode/css/index.html
index ae2c3bfce..80ef518e9 100644
--- a/gulliver/js/codemirror/mode/css/index.html
+++ b/gulliver/js/codemirror/mode/css/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: CSS mode
-
-
-
-
-
-
-
- CodeMirror: CSS mode
-
+
+CodeMirror: CSS mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CSS mode
+
/* Some example CSS */
@import url("something.css");
@@ -50,9 +63,8 @@ code {
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
- MIME types defined: text/css.
+ MIME types defined: text/css, text/x-scss (demo ), text/x-less (demo ).
Parsing/Highlighting Tests: normal , verbose .
-
-
+
diff --git a/gulliver/js/codemirror/mode/css/less.html b/gulliver/js/codemirror/mode/css/less.html
new file mode 100644
index 000000000..1030ca43f
--- /dev/null
+++ b/gulliver/js/codemirror/mode/css/less.html
@@ -0,0 +1,152 @@
+
+
+CodeMirror: LESS mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+LESS mode
+@media screen and (device-aspect-ratio: 16/9) { … }
+@media screen and (device-aspect-ratio: 1280/720) { … }
+@media screen and (device-aspect-ratio: 2560/1440) { … }
+
+html:lang(fr-be)
+
+tr:nth-child(2n+1) /* represents every odd row of an HTML table */
+
+img:nth-of-type(2n+1) { float: right; }
+img:nth-of-type(2n) { float: left; }
+
+body > h2:not(:first-of-type):not(:last-of-type)
+
+html|*:not(:link):not(:visited)
+*|*:not(:hover)
+p::first-line { text-transform: uppercase }
+
+@namespace foo url(http://www.example.com);
+foo|h1 { color: blue } /* first rule */
+
+span[hello="Ocean"][goodbye="Land"]
+
+E[foo]{
+ padding:65px;
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
+ padding: 0;
+ border: 0;
+}
+.btn {
+ // reset here as of 2.0.3 due to Recess property order
+ border-color: #ccc;
+ border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);
+}
+fieldset span button, fieldset span input[type="file"] {
+ font-size:12px;
+ font-family:Arial, Helvetica, sans-serif;
+}
+
+.rounded-corners (@radius: 5px) {
+ border-radius: @radius;
+ -webkit-border-radius: @radius;
+ -moz-border-radius: @radius;
+}
+
+@import url("something.css");
+
+@light-blue: hsl(190, 50%, 65%);
+
+#menu {
+ position: absolute;
+ width: 100%;
+ z-index: 3;
+ clear: both;
+ display: block;
+ background-color: @blue;
+ height: 42px;
+ border-top: 2px solid lighten(@alpha-blue, 20%);
+ border-bottom: 2px solid darken(@alpha-blue, 25%);
+ .box-shadow(0, 1px, 8px, 0.6);
+ -moz-box-shadow: 0 0 0 #000; // Because firefox sucks.
+
+ &.docked {
+ background-color: hsla(210, 60%, 40%, 0.4);
+ }
+ &:hover {
+ background-color: @blue;
+ }
+
+ #dropdown {
+ margin: 0 0 0 117px;
+ padding: 0;
+ padding-top: 5px;
+ display: none;
+ width: 190px;
+ border-top: 2px solid @medium;
+ color: @highlight;
+ border: 2px solid darken(@medium, 25%);
+ border-left-color: darken(@medium, 15%);
+ border-right-color: darken(@medium, 15%);
+ border-top-width: 0;
+ background-color: darken(@medium, 10%);
+ ul {
+ padding: 0px;
+ }
+ li {
+ font-size: 14px;
+ display: block;
+ text-align: left;
+ padding: 0;
+ border: 0;
+ a {
+ display: block;
+ padding: 0px 15px;
+ text-decoration: none;
+ color: white;
+ &:hover {
+ background-color: darken(@medium, 15%);
+ text-decoration: none;
+ }
+ }
+ }
+ .border-radius(5px, bottom);
+ .box-shadow(0, 6px, 8px, 0.5);
+ }
+}
+
+
+
+ The LESS mode is a sub-mode of the CSS mode (defined in css.js.
+
+ Parsing/Highlighting Tests: normal , verbose .
+
diff --git a/gulliver/js/codemirror/mode/css/less_test.js b/gulliver/js/codemirror/mode/css/less_test.js
new file mode 100644
index 000000000..ea64f91d1
--- /dev/null
+++ b/gulliver/js/codemirror/mode/css/less_test.js
@@ -0,0 +1,48 @@
+(function() {
+ "use strict";
+
+ var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); }
+
+ MT("variable",
+ "[variable-2 @base]: [atom #f04615];",
+ "[qualifier .class] {",
+ " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]",
+ " [property color]: [variable saturate]([variable-2 @base], [number 5%]);",
+ "}");
+
+ MT("amp",
+ "[qualifier .child], [qualifier .sibling] {",
+ " [qualifier .parent] [atom &] {",
+ " [property color]: [keyword black];",
+ " }",
+ " [atom &] + [atom &] {",
+ " [property color]: [keyword red];",
+ " }",
+ "}");
+
+ MT("mixin",
+ "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {",
+ " [property color]: [variable darken]([variable-2 @color], [number 10%]);",
+ "}",
+ "[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
+ " [property color]: [variable lighten]([variable-2 @color], [number 10%]);",
+ "}",
+ "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {",
+ " [property display]: [atom block];",
+ "}",
+ "[variable-2 @switch]: [variable light];",
+ "[qualifier .class] {",
+ " [qualifier .mixin]([variable-2 @switch]; [atom #888]);",
+ "}");
+
+ MT("nest",
+ "[qualifier .one] {",
+ " [def @media] ([property width]: [number 400px]) {",
+ " [property font-size]: [number 1.2em];",
+ " [def @media] [attribute print] [keyword and] [property color] {",
+ " [property color]: [keyword blue];",
+ " }",
+ " }",
+ "}");
+})();
diff --git a/gulliver/js/codemirror/mode/css/scss.html b/gulliver/js/codemirror/mode/css/scss.html
index b90cbe876..0677d08fe 100644
--- a/gulliver/js/codemirror/mode/css/scss.html
+++ b/gulliver/js/codemirror/mode/css/scss.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: SCSS mode
-
-
-
-
-
-
-
- CodeMirror: SCSS mode
-
+
+CodeMirror: SCSS mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+SCSS mode
+
/* Some example SCSS */
@import "compass/css3";
@@ -137,9 +150,8 @@ code {
});
- MIME types defined: text/scss.
+ The SCSS mode is a sub-mode of the CSS mode (defined in css.js.
Parsing/Highlighting Tests: normal , verbose .
-
-
+
diff --git a/gulliver/js/codemirror/mode/css/scss_test.js b/gulliver/js/codemirror/mode/css/scss_test.js
index 996dc7884..c51cb42bb 100644
--- a/gulliver/js/codemirror/mode/css/scss_test.js
+++ b/gulliver/js/codemirror/mode/css/scss_test.js
@@ -1,33 +1,33 @@
(function() {
- var mode = CodeMirror.getMode({tabSize: 4}, "text/x-scss");
+ var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
MT('url_with_quotation',
- "[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }");
+ "[tag foo] { [property background]:[atom url]([string test.jpg]) }");
MT('url_with_double_quotes',
- "[tag foo] { [property background][operator :][string-2 url]([string \"test.jpg\"]) }");
+ "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }");
MT('url_with_single_quotes',
- "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) }");
+ "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }");
MT('string',
"[def @import] [string \"compass/css3\"]");
MT('important_keyword',
- "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) [keyword !important] }");
+ "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }");
MT('variable',
- "[variable-2 $blue][operator :][atom #333]");
+ "[variable-2 $blue]:[atom #333]");
MT('variable_as_attribute',
- "[tag foo] { [property color][operator :][variable-2 $blue] }");
+ "[tag foo] { [property color]:[variable-2 $blue] }");
MT('numbers',
- "[tag foo] { [property padding][operator :][number 10px] [number 10] [number 10em] [number 8in] }");
+ "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }");
MT('number_percentage',
- "[tag foo] { [property width][operator :][number 80%] }");
+ "[tag foo] { [property width]:[number 80%] }");
MT('selector',
"[builtin #hello][qualifier .world]{}");
@@ -39,42 +39,69 @@
"[comment /*foobar*/]");
MT('attribute_with_hyphen',
- "[tag foo] { [property font-size][operator :][number 10px] }");
+ "[tag foo] { [property font-size]:[number 10px] }");
MT('string_after_attribute',
- "[tag foo] { [property content][operator :][string \"::\"] }");
+ "[tag foo] { [property content]:[string \"::\"] }");
MT('directives',
"[def @include] [qualifier .mixin]");
MT('basic_structure',
- "[tag p] { [property background][operator :][keyword red]; }");
+ "[tag p] { [property background]:[keyword red]; }");
MT('nested_structure',
- "[tag p] { [tag a] { [property color][operator :][keyword red]; } }");
+ "[tag p] { [tag a] { [property color]:[keyword red]; } }");
MT('mixin',
"[def @mixin] [tag table-base] {}");
MT('number_without_semicolon',
- "[tag p] {[property width][operator :][number 12]}",
- "[tag a] {[property color][operator :][keyword red];}");
+ "[tag p] {[property width]:[number 12]}",
+ "[tag a] {[property color]:[keyword red];}");
MT('atom_in_nested_block',
- "[tag p] { [tag a] { [property color][operator :][atom #000]; } }");
+ "[tag p] { [tag a] { [property color]:[atom #000]; } }");
MT('interpolation_in_property',
- "[tag foo] { [operator #{][variable-2 $hello][operator }:][atom #000]; }");
+ "[tag foo] { #{[variable-2 $hello]}:[number 2]; }");
MT('interpolation_in_selector',
- "[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }");
+ "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }");
MT('interpolation_error',
- "[tag foo][operator #{][error foo][operator }] { [property color][operator :][atom #000]; }");
+ "[tag foo]#{[error foo]} { [property color]:[atom #000]; }");
MT("divide_operator",
- "[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }");
+ "[tag foo] { [property width]:[number 4] [operator /] [number 2] }");
MT('nested_structure_with_id_selector',
- "[tag p] { [builtin #hello] { [property color][operator :][keyword red]; } }");
+ "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }");
+
+ MT('indent_mixin',
+ "[def @mixin] [tag container] (",
+ " [variable-2 $a]: [number 10],",
+ " [variable-2 $b]: [number 10])",
+ "{}");
+
+ MT('indent_nested',
+ "[tag foo] {",
+ " [tag bar] {",
+ " }",
+ "}");
+
+ MT('indent_parentheses',
+ "[tag foo] {",
+ " [property color]: [variable darken]([variable-2 $blue],",
+ " [number 9%]);",
+ "}");
+
+ MT('indent_vardef',
+ "[variable-2 $name]:",
+ " [string 'val'];",
+ "[tag tag] {",
+ " [tag inner] {",
+ " [property margin]: [number 3px];",
+ " }",
+ "}");
})();
diff --git a/gulliver/js/codemirror/mode/css/test.js b/gulliver/js/codemirror/mode/css/test.js
index 97dd0a8a3..b3f47767e 100644
--- a/gulliver/js/codemirror/mode/css/test.js
+++ b/gulliver/js/codemirror/mode/css/test.js
@@ -1,57 +1,19 @@
(function() {
- var mode = CodeMirror.getMode({tabSize: 4}, "css");
+ var mode = CodeMirror.getMode({indentUnit: 2}, "css");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
- // Requires at least one media query
- MT("atMediaEmpty",
- "[def @media] [error {] }");
-
- MT("atMediaMultiple",
- "[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }");
-
- MT("atMediaCheckStack",
- "[def @media] [attribute screen] { } [tag foo] { }");
-
- MT("atMediaCheckStack",
- "[def @media] [attribute screen] ([property color]) { } [tag foo] { }");
-
- MT("atMediaCheckStackInvalidAttribute",
- "[def @media] [attribute&error foobarhello] { } [tag foo] { }");
-
- // Error, because "and" is only allowed immediately preceding a media expression
- MT("atMediaInvalidAttribute",
- "[def @media] [attribute&error foobarhello] { }");
-
- // Error, because "and" is only allowed immediately preceding a media expression
- MT("atMediaInvalidAnd",
- "[def @media] [error and] [attribute screen] { }");
-
- // Error, because "not" is only allowed as the first item in each media query
- MT("atMediaInvalidNot",
- "[def @media] [attribute screen] [error not] ([error not]) { }");
-
- // Error, because "only" is only allowed as the first item in each media query
- MT("atMediaInvalidOnly",
- "[def @media] [attribute screen] [error only] ([error only]) { }");
-
// Error, because "foobarhello" is neither a known type or property, but
// property was expected (after "and"), and it should be in parenthese.
MT("atMediaUnknownType",
- "[def @media] [attribute screen] [operator and] [error foobarhello] { }");
-
- // Error, because "color" is not a known type, but is a known property, and
- // should be in parentheses.
- MT("atMediaInvalidType",
- "[def @media] [attribute screen] [operator and] [error color] { }");
-
- // Error, because "print" is not a known property, but is a known type,
- // and should not be in parenthese.
- MT("atMediaInvalidProperty",
- "[def @media] [attribute screen] [operator and] ([error print]) { }");
+ "[def @media] [attribute screen] [keyword and] [error foobarhello] { }");
// Soft error, because "foobarhello" is not a known property or type.
MT("atMediaUnknownProperty",
- "[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }");
+ "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }");
+
+ // Make sure nesting works with media queries
+ MT("atMediaMaxWidthNested",
+ "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }");
MT("tagSelector",
"[tag foo] { }");
@@ -63,51 +25,95 @@
"[builtin #foo] { [error #foo] }");
MT("tagSelectorUnclosed",
- "[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }");
+ "[tag foo] { [property margin]: [number 0] } [tag bar] { }");
MT("tagStringNoQuotes",
- "[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }");
+ "[tag foo] { [property font-family]: [variable hello] [variable world]; }");
MT("tagStringDouble",
- "[tag foo] { [property font-family][operator :] [string \"hello world\"]; }");
+ "[tag foo] { [property font-family]: [string \"hello world\"]; }");
MT("tagStringSingle",
- "[tag foo] { [property font-family][operator :] [string 'hello world']; }");
+ "[tag foo] { [property font-family]: [string 'hello world']; }");
MT("tagColorKeyword",
- "[tag foo] {" +
- "[property color][operator :] [keyword black];" +
- "[property color][operator :] [keyword navy];" +
- "[property color][operator :] [keyword yellow];" +
- "}");
+ "[tag foo] {",
+ " [property color]: [keyword black];",
+ " [property color]: [keyword navy];",
+ " [property color]: [keyword yellow];",
+ "}");
MT("tagColorHex3",
- "[tag foo] { [property background][operator :] [atom #fff]; }");
+ "[tag foo] { [property background]: [atom #fff]; }");
MT("tagColorHex6",
- "[tag foo] { [property background][operator :] [atom #ffffff]; }");
+ "[tag foo] { [property background]: [atom #ffffff]; }");
MT("tagColorHex4",
- "[tag foo] { [property background][operator :] [atom&error #ffff]; }");
+ "[tag foo] { [property background]: [atom&error #ffff]; }");
MT("tagColorHexInvalid",
- "[tag foo] { [property background][operator :] [atom&error #ffg]; }");
+ "[tag foo] { [property background]: [atom&error #ffg]; }");
MT("tagNegativeNumber",
- "[tag foo] { [property margin][operator :] [number -5px]; }");
+ "[tag foo] { [property margin]: [number -5px]; }");
MT("tagPositiveNumber",
- "[tag foo] { [property padding][operator :] [number 5px]; }");
+ "[tag foo] { [property padding]: [number 5px]; }");
MT("tagVendor",
- "[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }");
+ "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }");
MT("tagBogusProperty",
- "[tag foo] { [property&error barhelloworld][operator :] [number 0]; }");
+ "[tag foo] { [property&error barhelloworld]: [number 0]; }");
MT("tagTwoProperties",
- "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }");
+ "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
+
+ MT("tagTwoPropertiesURL",
+ "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
MT("commentSGML",
"[comment ]");
+
+ MT("commentSGML2",
+ "[comment ] [tag div] {}");
+
+ MT("indent_tagSelector",
+ "[tag strong], [tag em] {",
+ " [property background]: [atom rgba](",
+ " [number 255], [number 255], [number 0], [number .2]",
+ " );",
+ "}");
+
+ MT("indent_atMedia",
+ "[def @media] {",
+ " [tag foo] {",
+ " [property color]:",
+ " [keyword yellow];",
+ " }",
+ "}");
+
+ MT("indent_comma",
+ "[tag foo] {",
+ " [property font-family]: [variable verdana],",
+ " [atom sans-serif];",
+ "}");
+
+ MT("indent_parentheses",
+ "[tag foo]:[variable-3 before] {",
+ " [property background]: [atom url](",
+ "[string blahblah]",
+ "[string etc]",
+ "[string ]) [keyword !important];",
+ "}");
+
+ MT("font_face",
+ "[def @font-face] {",
+ " [property font-family]: [string 'myfont'];",
+ " [error nonsense]: [string 'abc'];",
+ " [property src]: [atom url]([string http://blah]),",
+ " [atom url]([string http://foo]);",
+ "}");
})();
diff --git a/gulliver/js/codemirror/mode/d/index.html b/gulliver/js/codemirror/mode/d/index.html
index 13332727a..8b25fcc5c 100755
--- a/gulliver/js/codemirror/mode/d/index.html
+++ b/gulliver/js/codemirror/mode/d/index.html
@@ -1,18 +1,30 @@
-
-
-
- CodeMirror: D mode
-
-
-
-
-
-
-
-
- CodeMirror: D mode
+CodeMirror: D mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+D mode
/* D demo code // copied from phobos/sd/metastrings.d */
// Written in the D programming language.
@@ -258,5 +270,4 @@ deprecated alias parseUinteger ParseInteger;
MIME types defined: text/x-d
.
-
-
+
diff --git a/gulliver/js/codemirror/mode/diff/index.html b/gulliver/js/codemirror/mode/diff/index.html
index 556025204..6ceae8b33 100644
--- a/gulliver/js/codemirror/mode/diff/index.html
+++ b/gulliver/js/codemirror/mode/diff/index.html
@@ -1,23 +1,36 @@
-
-
-
- CodeMirror: Diff mode
-
-
-
-
-
-
-
- CodeMirror: Diff mode
-
+
+
+
+
+
+
+
+
+Diff mode
+
diff --git a/index.html b/index.html
index c1d9156..7764744 100644
--- a/index.html
@@ -101,5 +114,4 @@ index 04646a9..9a39cc7 100644
MIME types defined: text/x-diff.
-
-
+
diff --git a/gulliver/js/codemirror/mode/ecl/ecl.js b/gulliver/js/codemirror/mode/ecl/ecl.js
index 3ee7a681d..7601b189a 100644
--- a/gulliver/js/codemirror/mode/ecl/ecl.js
+++ b/gulliver/js/codemirror/mode/ecl/ecl.js
@@ -75,18 +75,18 @@ CodeMirror.defineMode("ecl", function(config) {
} else if (builtin.propertyIsEnumerable(cur)) {
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
return "builtin";
- } else { //Data types are of from KEYWORD##
- var i = cur.length - 1;
- while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_'))
- --i;
-
- if (i > 0) {
- var cur2 = cur.substr(0, i + 1);
- if (variable_3.propertyIsEnumerable(cur2)) {
- if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement";
- return "variable-3";
- }
- }
+ } else { //Data types are of from KEYWORD##
+ var i = cur.length - 1;
+ while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_'))
+ --i;
+
+ if (i > 0) {
+ var cur2 = cur.substr(0, i + 1);
+ if (variable_3.propertyIsEnumerable(cur2)) {
+ if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement";
+ return "variable-3";
+ }
+ }
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
return null;
diff --git a/gulliver/js/codemirror/mode/ecl/index.html b/gulliver/js/codemirror/mode/ecl/index.html
index 0ba88c399..f4b612d61 100644
--- a/gulliver/js/codemirror/mode/ecl/index.html
+++ b/gulliver/js/codemirror/mode/ecl/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: ECL mode
-
-
-
-
-
-
-
- CodeMirror: ECL mode
-
+
+
+CodeMirror: ECL mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ECL mode
+
/*
sample useless code to demonstrate ecl syntax highlighting
this is a multiline comment!
@@ -35,5 +49,4 @@ output(d);
Based on CodeMirror's clike mode. For more information see HPCC Systems web site.
MIME types defined: text/x-ecl.
-
-
+
diff --git a/gulliver/js/codemirror/mode/erlang/erlang.js b/gulliver/js/codemirror/mode/erlang/erlang.js
index accf24e67..bc3bdce86 100644
--- a/gulliver/js/codemirror/mode/erlang/erlang.js
+++ b/gulliver/js/codemirror/mode/erlang/erlang.js
@@ -1,52 +1,24 @@
-// block; "begin", "case", "fun", "if", "receive", "try": closed by "end"
-// block internal; "after", "catch", "of"
-// guard; "when", closed by "->"
-// "->" opens a clause, closed by ";" or "."
-// "<<" opens a binary, closed by ">>"
-// "," appears in arglists, lists, tuples and terminates lines of code
-// "." resets indentation to 0
-// obsolete; "cond", "let", "query"
+/*jshint unused:true, eqnull:true, curly:true, bitwise:true */
+/*jshint undef:true, latedef:true, trailing:true */
+/*global CodeMirror:true */
+
+// erlang mode.
+// tokenizer -> token types -> CodeMirror styles
+// tokenizer maintains a parse stack
+// indenter uses the parse stack
+
+// TODO indenter:
+// bit syntax
+// old guard/bif/conversion clashes (e.g. "float/1")
+// type/spec/opaque
CodeMirror.defineMIME("text/x-erlang", "erlang");
CodeMirror.defineMode("erlang", function(cmCfg) {
+ "use strict";
- function rval(state,stream,type) {
- // distinguish between "." as terminator and record field operator
- if (type == "record") {
- state.context = "record";
- }else{
- state.context = false;
- }
-
- // remember last significant bit on last line for indenting
- if (type != "whitespace" && type != "comment") {
- state.lastToken = stream.current();
- }
- // erlang -> CodeMirror tag
- switch (type) {
- case "atom": return "atom";
- case "attribute": return "attribute";
- case "builtin": return "builtin";
- case "comment": return "comment";
- case "fun": return "meta";
- case "function": return "tag";
- case "guard": return "property";
- case "keyword": return "keyword";
- case "macro": return "variable-2";
- case "number": return "number";
- case "operator": return "operator";
- case "record": return "bracket";
- case "string": return "string";
- case "type": return "def";
- case "variable": return "variable";
- case "error": return "error";
- case "separator": return null;
- case "open_paren": return null;
- case "close_paren": return null;
- default: return null;
- }
- }
+/////////////////////////////////////////////////////////////////////////////
+// constants
var typeWords = [
"-type", "-spec", "-export_type", "-opaque"];
@@ -55,19 +27,23 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
"after","begin","catch","case","cond","end","fun","if",
"let","of","query","receive","try","when"];
+ var separatorRE = /[\->,;]/;
var separatorWords = [
- "->",";",":",".",","];
+ "->",";",","];
- var operatorWords = [
+ var operatorAtomWords = [
"and","andalso","band","bnot","bor","bsl","bsr","bxor",
"div","not","or","orelse","rem","xor"];
- var symbolWords = [
- "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"];
+ var operatorSymbolRE = /[\+\-\*\/<>=\|:!]/;
+ var operatorSymbolWords = [
+ "=","+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"];
+ var openParenRE = /[<\(\[\{]/;
var openParenWords = [
"<<","(","[","{"];
+ var closeParenRE = /[>\)\]\}]/;
var closeParenWords = [
"}","]",")",">>"];
@@ -102,53 +78,41 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
"term_to_binary","time","throw","tl","trunc","tuple_size",
"tuple_to_list","unlink","unregister","whereis"];
- // ignored for indenting purposes
- var ignoreWords = [
- ",", ":", "catch", "after", "of", "cond", "let", "query"];
+// upper case: [A-Z] [Ø-Þ] [À-Ö]
+// lower case: [a-z] [ß-ö] [ø-ÿ]
+ var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/;
+ var escapesRE =
+ /[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/;
+/////////////////////////////////////////////////////////////////////////////
+// tokenizer
- var smallRE = /[a-z_]/;
- var largeRE = /[A-Z_]/;
- var digitRE = /[0-9]/;
- var octitRE = /[0-7]/;
- var anumRE = /[a-z_A-Z0-9]/;
- var symbolRE = /[\+\-\*\/<>=\|:]/;
- var openParenRE = /[<\(\[\{]/;
- var closeParenRE = /[>\)\]\}]/;
- var sepRE = /[\->\.,:;]/;
-
- function isMember(element,list) {
- return (-1 < list.indexOf(element));
- }
-
- function isPrev(stream,string) {
- var start = stream.start;
- var len = string.length;
- if (len <= start) {
- var word = stream.string.slice(start-len,start);
- return word == string;
- }else{
- return false;
+ function tokenizer(stream,state) {
+ // in multi-line string
+ if (state.in_string) {
+ state.in_string = (!doubleQuote(stream));
+ return rval(state,stream,"string");
}
- }
- function tokenize(stream, state) {
+ // in multi-line atom
+ if (state.in_atom) {
+ state.in_atom = (!singleQuote(stream));
+ return rval(state,stream,"atom");
+ }
+
+ // whitespace
if (stream.eatSpace()) {
return rval(state,stream,"whitespace");
}
// attributes and type specs
- if ((peekToken(state).token == "" || peekToken(state).token == ".") &&
- stream.peek() == '-') {
- stream.next();
- if (stream.eat(smallRE) && stream.eatWhile(anumRE)) {
- if (isMember(stream.current(),typeWords)) {
- return rval(state,stream,"type");
- }else{
- return rval(state,stream,"attribute");
- }
+ if (!peekToken(state) &&
+ stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) {
+ if (is_member(stream.current(),typeWords)) {
+ return rval(state,stream,"type");
+ }else{
+ return rval(state,stream,"attribute");
}
- stream.backUp(1);
}
var ch = stream.next();
@@ -159,109 +123,131 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
return rval(state,stream,"comment");
}
+ // colon
+ if (ch == ":") {
+ return rval(state,stream,"colon");
+ }
+
// macro
if (ch == '?') {
+ stream.eatSpace();
stream.eatWhile(anumRE);
return rval(state,stream,"macro");
}
// record
- if ( ch == "#") {
+ if (ch == "#") {
+ stream.eatSpace();
stream.eatWhile(anumRE);
return rval(state,stream,"record");
}
- // char
- if ( ch == "$") {
- if (stream.next() == "\\") {
- if (!stream.eatWhile(octitRE)) {
- stream.next();
- }
+ // dollar escape
+ if (ch == "$") {
+ if (stream.next() == "\\" && !stream.match(escapesRE)) {
+ return rval(state,stream,"error");
}
- return rval(state,stream,"string");
+ return rval(state,stream,"number");
+ }
+
+ // dot
+ if (ch == ".") {
+ return rval(state,stream,"dot");
}
// quoted atom
if (ch == '\'') {
- if (singleQuote(stream)) {
- return rval(state,stream,"atom");
- }else{
- return rval(state,stream,"error");
+ if (!(state.in_atom = (!singleQuote(stream)))) {
+ if (stream.match(/\s*\/\s*[0-9]/,false)) {
+ stream.match(/\s*\/\s*[0-9]/,true);
+ return rval(state,stream,"fun"); // 'f'/0 style fun
+ }
+ if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) {
+ return rval(state,stream,"function");
+ }
}
+ return rval(state,stream,"atom");
}
// string
if (ch == '"') {
- if (doubleQuote(stream)) {
- return rval(state,stream,"string");
- }else{
- return rval(state,stream,"error");
- }
+ state.in_string = (!doubleQuote(stream));
+ return rval(state,stream,"string");
}
// variable
- if (largeRE.test(ch)) {
+ if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) {
stream.eatWhile(anumRE);
return rval(state,stream,"variable");
}
// atom/keyword/BIF/function
- if (smallRE.test(ch)) {
+ if (/[a-z_ß-öø-ÿ]/.test(ch)) {
stream.eatWhile(anumRE);
- if (stream.peek() == "/") {
- stream.next();
- if (stream.eatWhile(digitRE)) {
- return rval(state,stream,"fun"); // f/0 style fun
- }else{
- stream.backUp(1);
- return rval(state,stream,"atom");
- }
+ if (stream.match(/\s*\/\s*[0-9]/,false)) {
+ stream.match(/\s*\/\s*[0-9]/,true);
+ return rval(state,stream,"fun"); // f/0 style fun
}
var w = stream.current();
- if (isMember(w,keywordWords)) {
- pushToken(state,stream);
+ if (is_member(w,keywordWords)) {
return rval(state,stream,"keyword");
- }
- if (stream.peek() == "(") {
+ }else if (is_member(w,operatorAtomWords)) {
+ return rval(state,stream,"operator");
+ }else if (stream.match(/\s*\(/,false)) {
// 'put' and 'erlang:put' are bifs, 'foo:put' is not
- if (isMember(w,bifWords) &&
- (!isPrev(stream,":") || isPrev(stream,"erlang:"))) {
+ if (is_member(w,bifWords) &&
+ ((peekToken(state).token != ":") ||
+ (peekToken(state,2).token == "erlang"))) {
return rval(state,stream,"builtin");
+ }else if (is_member(w,guardWords)) {
+ return rval(state,stream,"guard");
}else{
return rval(state,stream,"function");
}
- }
- if (isMember(w,guardWords)) {
- return rval(state,stream,"guard");
- }
- if (isMember(w,operatorWords)) {
+ }else if (is_member(w,operatorAtomWords)) {
return rval(state,stream,"operator");
- }
- if (stream.peek() == ":") {
+ }else if (lookahead(stream) == ":") {
if (w == "erlang") {
return rval(state,stream,"builtin");
} else {
return rval(state,stream,"function");
}
+ }else if (is_member(w,["true","false"])) {
+ return rval(state,stream,"boolean");
+ }else if (is_member(w,["true","false"])) {
+ return rval(state,stream,"boolean");
+ }else{
+ return rval(state,stream,"atom");
}
- return rval(state,stream,"atom");
}
// number
+ var digitRE = /[0-9]/;
+ var radixRE = /[0-9a-zA-Z]/; // 36#zZ style int
if (digitRE.test(ch)) {
stream.eatWhile(digitRE);
- if (stream.eat('#')) {
- stream.eatWhile(digitRE); // 16#10 style integer
- } else {
- if (stream.eat('.')) { // float
- stream.eatWhile(digitRE);
+ if (stream.eat('#')) { // 36#aZ style integer
+ if (!stream.eatWhile(radixRE)) {
+ stream.backUp(1); //"36#" - syntax error
}
- if (stream.eat(/[eE]/)) {
- stream.eat(/[-+]/); // float with exponent
- stream.eatWhile(digitRE);
+ } else if (stream.eat('.')) { // float
+ if (!stream.eatWhile(digitRE)) {
+ stream.backUp(1); // "3." - probably end of function
+ } else {
+ if (stream.eat(/[eE]/)) { // float with exponent
+ if (stream.eat(/[-+]/)) {
+ if (!stream.eatWhile(digitRE)) {
+ stream.backUp(2); // "2e-" - syntax error
+ }
+ } else {
+ if (!stream.eatWhile(digitRE)) {
+ stream.backUp(1); // "2e" - syntax error
+ }
+ }
+ }
}
}
return rval(state,stream,"number"); // normal integer
@@ -269,39 +255,35 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
// open parens
if (nongreedy(stream,openParenRE,openParenWords)) {
- pushToken(state,stream);
return rval(state,stream,"open_paren");
}
// close parens
if (nongreedy(stream,closeParenRE,closeParenWords)) {
- pushToken(state,stream);
return rval(state,stream,"close_paren");
}
// separators
- if (greedy(stream,sepRE,separatorWords)) {
- // distinguish between "." as terminator and record field operator
- if (state.context == false) {
- pushToken(state,stream);
- }
+ if (greedy(stream,separatorRE,separatorWords)) {
return rval(state,stream,"separator");
}
// operators
- if (greedy(stream,symbolRE,symbolWords)) {
+ if (greedy(stream,operatorSymbolRE,operatorSymbolWords)) {
return rval(state,stream,"operator");
}
return rval(state,stream,null);
}
+/////////////////////////////////////////////////////////////////////////////
+// utilities
function nongreedy(stream,re,words) {
if (stream.current().length == 1 && re.test(stream.current())) {
stream.backUp(1);
while (re.test(stream.peek())) {
stream.next();
- if (isMember(stream.current(),words)) {
+ if (is_member(stream.current(),words)) {
return true;
}
}
@@ -316,7 +298,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
stream.next();
}
while (0 < stream.current().length) {
- if (isMember(stream.current(),words)) {
+ if (is_member(stream.current(),words)) {
return true;
}else{
stream.backUp(1);
@@ -347,117 +329,279 @@ CodeMirror.defineMode("erlang", function(cmCfg) {
return false;
}
- function Token(stream) {
- this.token = stream ? stream.current() : "";
- this.column = stream ? stream.column() : 0;
- this.indent = stream ? stream.indentation() : 0;
+ function lookahead(stream) {
+ var m = stream.match(/([\n\s]+|%[^\n]*\n)*(.)/,false);
+ return m ? m.pop() : "";
}
- function myIndent(state,textAfter) {
- var indent = cmCfg.indentUnit;
- var outdentWords = ["after","catch"];
- var token = (peekToken(state)).token;
- var wordAfter = takewhile(textAfter,/[^a-z]/);
+ function is_member(element,list) {
+ return (-1 < list.indexOf(element));
+ }
- if (isMember(token,openParenWords)) {
- return (peekToken(state)).column+token.length;
- }else if (token == "." || token == ""){
- return 0;
- }else if (token == "->") {
- if (wordAfter == "end") {
- return peekToken(state,2).column;
- }else if (peekToken(state,2).token == "fun") {
- return peekToken(state,2).column+indent;
- }else{
- return (peekToken(state)).indent+indent;
- }
- }else if (isMember(wordAfter,outdentWords)) {
- return (peekToken(state)).indent;
- }else{
- return (peekToken(state)).column+indent;
+ function rval(state,stream,type) {
+
+ // parse stack
+ pushToken(state,realToken(type,stream));
+
+ // map erlang token type to CodeMirror style class
+ // erlang -> CodeMirror tag
+ switch (type) {
+ case "atom": return "atom";
+ case "attribute": return "attribute";
+ case "boolean": return "special";
+ case "builtin": return "builtin";
+ case "close_paren": return null;
+ case "colon": return null;
+ case "comment": return "comment";
+ case "dot": return null;
+ case "error": return "error";
+ case "fun": return "meta";
+ case "function": return "tag";
+ case "guard": return "property";
+ case "keyword": return "keyword";
+ case "macro": return "variable-2";
+ case "number": return "number";
+ case "open_paren": return null;
+ case "operator": return "operator";
+ case "record": return "bracket";
+ case "separator": return null;
+ case "string": return "string";
+ case "type": return "def";
+ case "variable": return "variable";
+ default: return null;
}
}
- function takewhile(str,re) {
- var m = str.match(re);
- return m ? str.slice(0,m.index) : str;
+ function aToken(tok,col,ind,typ) {
+ return {token: tok,
+ column: col,
+ indent: ind,
+ type: typ};
}
- function popToken(state) {
- return state.tokenStack.pop();
+ function realToken(type,stream) {
+ return aToken(stream.current(),
+ stream.column(),
+ stream.indentation(),
+ type);
+ }
+
+ function fakeToken(type) {
+ return aToken(type,0,0,type);
}
function peekToken(state,depth) {
var len = state.tokenStack.length;
var dep = (depth ? depth : 1);
+
if (len < dep) {
- return new Token;
+ return false;
}else{
return state.tokenStack[len-dep];
}
}
- function pushToken(state,stream) {
- var token = stream.current();
- var prev_token = peekToken(state).token;
- if (isMember(token,ignoreWords)) {
- return false;
- }else if (drop_both(prev_token,token)) {
- popToken(state);
- return false;
- }else if (drop_first(prev_token,token)) {
- popToken(state);
- return pushToken(state,stream);
+ function pushToken(state,token) {
+
+ if (!(token.type == "comment" || token.type == "whitespace")) {
+ state.tokenStack = maybe_drop_pre(state.tokenStack,token);
+ state.tokenStack = maybe_drop_post(state.tokenStack);
+ }
+ }
+
+ function maybe_drop_pre(s,token) {
+ var last = s.length-1;
+
+ if (0 < last && s[last].type === "record" && token.type === "dot") {
+ s.pop();
+ }else if (0 < last && s[last].type === "group") {
+ s.pop();
+ s.push(token);
}else{
- state.tokenStack.push(new Token(stream));
- return true;
+ s.push(token);
+ }
+ return s;
+ }
+
+ function maybe_drop_post(s) {
+ var last = s.length-1;
+
+ if (s[last].type === "dot") {
+ return [];
+ }
+ if (s[last].type === "fun" && s[last-1].token === "fun") {
+ return s.slice(0,last-1);
+ }
+ switch (s[s.length-1].token) {
+ case "}": return d(s,{g:["{"]});
+ case "]": return d(s,{i:["["]});
+ case ")": return d(s,{i:["("]});
+ case ">>": return d(s,{i:["<<"]});
+ case "end": return d(s,{i:["begin","case","fun","if","receive","try"]});
+ case ",": return d(s,{e:["begin","try","when","->",
+ ",","(","[","{","<<"]});
+ case "->": return d(s,{r:["when"],
+ m:["try","if","case","receive"]});
+ case ";": return d(s,{E:["case","fun","if","receive","try","when"]});
+ case "catch":return d(s,{e:["try"]});
+ case "of": return d(s,{e:["case"]});
+ case "after":return d(s,{e:["receive","try"]});
+ default: return s;
}
}
- function drop_first(open, close) {
- switch (open+" "+close) {
- case "when ->": return true;
- case "-> end": return true;
- case "-> .": return true;
- case ". .": return true;
- default: return false;
+ function d(stack,tt) {
+ // stack is a stack of Token objects.
+ // tt is an object; {type:tokens}
+ // type is a char, tokens is a list of token strings.
+ // The function returns (possibly truncated) stack.
+ // It will descend the stack, looking for a Token such that Token.token
+ // is a member of tokens. If it does not find that, it will normally (but
+ // see "E" below) return stack. If it does find a match, it will remove
+ // all the Tokens between the top and the matched Token.
+ // If type is "m", that is all it does.
+ // If type is "i", it will also remove the matched Token and the top Token.
+ // If type is "g", like "i", but add a fake "group" token at the top.
+ // If type is "r", it will remove the matched Token, but not the top Token.
+ // If type is "e", it will keep the matched Token but not the top Token.
+ // If type is "E", it behaves as for type "e", except if there is no match,
+ // in which case it will return an empty stack.
+
+ for (var type in tt) {
+ var len = stack.length-1;
+ var tokens = tt[type];
+ for (var i = len-1; -1 < i ; i--) {
+ if (is_member(stack[i].token,tokens)) {
+ var ss = stack.slice(0,i);
+ switch (type) {
+ case "m": return ss.concat(stack[i]).concat(stack[len]);
+ case "r": return ss.concat(stack[len]);
+ case "i": return ss;
+ case "g": return ss.concat(fakeToken("group"));
+ case "E": return ss.concat(stack[i]);
+ case "e": return ss.concat(stack[i]);
+ }
+ }
+ }
+ }
+ return (type == "E" ? [] : stack);
+ }
+
+/////////////////////////////////////////////////////////////////////////////
+// indenter
+
+ function indenter(state,textAfter) {
+ var t;
+ var unit = cmCfg.indentUnit;
+ var wordAfter = wordafter(textAfter);
+ var currT = peekToken(state,1);
+ var prevT = peekToken(state,2);
+
+ if (state.in_string || state.in_atom) {
+ return CodeMirror.Pass;
+ }else if (!prevT) {
+ return 0;
+ }else if (currT.token == "when") {
+ return currT.column+unit;
+ }else if (wordAfter === "when" && prevT.type === "function") {
+ return prevT.indent+unit;
+ }else if (wordAfter === "(" && currT.token === "fun") {
+ return currT.column+3;
+ }else if (wordAfter === "catch" && (t = getToken(state,["try"]))) {
+ return t.column;
+ }else if (is_member(wordAfter,["end","after","of"])) {
+ t = getToken(state,["begin","case","fun","if","receive","try"]);
+ return t ? t.column : CodeMirror.Pass;
+ }else if (is_member(wordAfter,closeParenWords)) {
+ t = getToken(state,openParenWords);
+ return t ? t.column : CodeMirror.Pass;
+ }else if (is_member(currT.token,[",","|","||"]) ||
+ is_member(wordAfter,[",","|","||"])) {
+ t = postcommaToken(state);
+ return t ? t.column+t.token.length : unit;
+ }else if (currT.token == "->") {
+ if (is_member(prevT.token, ["receive","case","if","try"])) {
+ return prevT.column+unit+unit;
+ }else{
+ return prevT.column+unit;
+ }
+ }else if (is_member(currT.token,openParenWords)) {
+ return currT.column+currT.token.length;
+ }else{
+ t = defaultToken(state);
+ return truthy(t) ? t.column+unit : 0;
}
}
- function drop_both(open, close) {
- switch (open+" "+close) {
- case "( )": return true;
- case "[ ]": return true;
- case "{ }": return true;
- case "<< >>": return true;
- case "begin end": return true;
- case "case end": return true;
- case "fun end": return true;
- case "if end": return true;
- case "receive end": return true;
- case "try end": return true;
- case "-> ;": return true;
- default: return false;
+ function wordafter(str) {
+ var m = str.match(/,|[a-z]+|\}|\]|\)|>>|\|+|\(/);
+
+ return truthy(m) && (m.index === 0) ? m[0] : "";
+ }
+
+ function postcommaToken(state) {
+ var objs = state.tokenStack.slice(0,-1);
+ var i = getTokenIndex(objs,"type",["open_paren"]);
+
+ return truthy(objs[i]) ? objs[i] : false;
+ }
+
+ function defaultToken(state) {
+ var objs = state.tokenStack;
+ var stop = getTokenIndex(objs,"type",["open_paren","separator","keyword"]);
+ var oper = getTokenIndex(objs,"type",["operator"]);
+
+ if (truthy(stop) && truthy(oper) && stop < oper) {
+ return objs[stop+1];
+ } else if (truthy(stop)) {
+ return objs[stop];
+ } else {
+ return false;
}
}
+ function getToken(state,tokens) {
+ var objs = state.tokenStack;
+ var i = getTokenIndex(objs,"token",tokens);
+
+ return truthy(objs[i]) ? objs[i] : false;
+ }
+
+ function getTokenIndex(objs,propname,propvals) {
+
+ for (var i = objs.length-1; -1 < i ; i--) {
+ if (is_member(objs[i][propname],propvals)) {
+ return i;
+ }
+ }
+ return false;
+ }
+
+ function truthy(x) {
+ return (x !== false) && (x != null);
+ }
+
+/////////////////////////////////////////////////////////////////////////////
+// this object defines the mode
+
return {
startState:
function() {
return {tokenStack: [],
- context: false,
- lastToken: null};
+ in_string: false,
+ in_atom: false};
},
token:
function(stream, state) {
- return tokenize(stream, state);
+ return tokenizer(stream, state);
},
indent:
function(state, textAfter) {
-// console.log(state.tokenStack);
- return myIndent(state,textAfter);
- }
+ return indenter(state,textAfter);
+ },
+
+ lineComment: "%"
};
});
diff --git a/gulliver/js/codemirror/mode/erlang/index.html b/gulliver/js/codemirror/mode/erlang/index.html
index fd21521c8..9cacb759f 100644
--- a/gulliver/js/codemirror/mode/erlang/index.html
+++ b/gulliver/js/codemirror/mode/erlang/index.html
@@ -1,19 +1,31 @@
-
-
-
- CodeMirror: Erlang mode
-
-
-
-
-
-
-
-
-
- CodeMirror: Erlang mode
+CodeMirror: Erlang mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Erlang mode
%% -*- mode: erlang; erlang-indent-level: 2 -*-
%%% Created : 7 May 2012 by mats cronqvist
@@ -32,18 +44,19 @@
rec_info(demo) -> record_info(fields,demo).
demo() -> expand_recs(?MODULE,#demo{a="A",b="BB"}).
-
+
expand_recs(M,List) when is_list(List) ->
[expand_recs(M,L)||L<-List];
expand_recs(M,Tup) when is_tuple(Tup) ->
case tuple_size(Tup) of
L when L < 1 -> Tup;
L ->
- try Fields = M:rec_info(element(1,Tup)),
- L = length(Fields)+1,
- lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup))))
- catch _:_ ->
- list_to_tuple(expand_recs(M,tuple_to_list(Tup)))
+ try
+ Fields = M:rec_info(element(1,Tup)),
+ L = length(Fields)+1,
+ lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup))))
+ catch
+ _:_ -> list_to_tuple(expand_recs(M,tuple_to_list(Tup)))
end
end;
expand_recs(_,Term) ->
@@ -60,5 +73,4 @@ expand_recs(_,Term) ->
MIME types defined: text/x-erlang.
-
-
+
diff --git a/gulliver/js/codemirror/mode/gfm/gfm.js b/gulliver/js/codemirror/mode/gfm/gfm.js
index 1179b53dc..10d5e05c0 100644
--- a/gulliver/js/codemirror/mode/gfm/gfm.js
+++ b/gulliver/js/codemirror/mode/gfm/gfm.js
@@ -1,4 +1,4 @@
-CodeMirror.defineMode("gfm", function(config) {
+CodeMirror.defineMode("gfm", function(config, modeConfig) {
var codeDepth = 0;
function blankLine(state) {
state.code = false;
@@ -75,7 +75,8 @@ CodeMirror.defineMode("gfm", function(config) {
return "link";
}
}
- if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i)) {
+ if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i) &&
+ stream.string.slice(stream.start - 2, stream.start) != "](") {
// URLs
// Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
// And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
@@ -86,11 +87,16 @@ CodeMirror.defineMode("gfm", function(config) {
},
blankLine: blankLine
};
- CodeMirror.defineMIME("gfmBase", {
- name: "markdown",
+
+ var markdownConfig = {
underscoresBreakWords: false,
taskLists: true,
fencedCodeBlocks: true
- });
+ };
+ for (var attr in modeConfig) {
+ markdownConfig[attr] = modeConfig[attr];
+ }
+ markdownConfig.name = "markdown";
+ CodeMirror.defineMIME("gfmBase", markdownConfig);
return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay);
}, "markdown");
diff --git a/gulliver/js/codemirror/mode/gfm/index.html b/gulliver/js/codemirror/mode/gfm/index.html
index 826a96d2d..b71cd5c75 100644
--- a/gulliver/js/codemirror/mode/gfm/index.html
+++ b/gulliver/js/codemirror/mode/gfm/index.html
@@ -1,27 +1,36 @@
-
-
-
- CodeMirror: GFM mode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: GFM mode
+CodeMirror: GFM mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+GFM mode
GitHub Flavored Markdown
========================
@@ -70,5 +79,4 @@ See http://github.github.com/github-flavored-markdown/.
Parsing/Highlighting Tests: normal , verbose .
-
-
+
diff --git a/gulliver/js/codemirror/mode/gfm/test.js b/gulliver/js/codemirror/mode/gfm/test.js
index 3ccaec501..e5c3486eb 100644
--- a/gulliver/js/codemirror/mode/gfm/test.js
+++ b/gulliver/js/codemirror/mode/gfm/test.js
@@ -1,6 +1,23 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "gfm");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+ var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "gfm", highlightFormatting: true});
+ function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
+
+ FT("codeBackticks",
+ "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
+
+ FT("doubleBackticks",
+ "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
+
+ FT("codeBlock",
+ "[comment&formatting&formatting-code-block ```css]",
+ "[tag foo]",
+ "[comment&formatting&formatting-code-block ```]");
+
+ FT("taskList",
+ "[variable-2&formatting&formatting-list&formatting-list-ul - ][meta&formatting&formatting-task [ ]]][variable-2 foo]",
+ "[variable-2&formatting&formatting-list&formatting-list-ul - ][property&formatting&formatting-task [x]]][variable-2 foo]");
MT("emInWordAsterisk",
"foo[em *bar*]hello");
@@ -97,7 +114,7 @@
MT("notALink",
"[comment ```css]",
- "[tag foo] {[property color][operator :][keyword black];}",
+ "[tag foo] {[property color]:[keyword black];}",
"[comment ```][link http://www.example.com/]");
MT("notALink",
diff --git a/gulliver/js/codemirror/mode/go/go.js b/gulliver/js/codemirror/mode/go/go.js
index 8b84a5ca4..862c09112 100644
--- a/gulliver/js/codemirror/mode/go/go.js
+++ b/gulliver/js/codemirror/mode/go/go.js
@@ -158,7 +158,10 @@ CodeMirror.defineMode("go", function(config) {
else return ctx.indented + (closing ? 0 : indentUnit);
},
- electricChars: "{}:"
+ electricChars: "{}):",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//"
};
});
diff --git a/gulliver/js/codemirror/mode/go/index.html b/gulliver/js/codemirror/mode/go/index.html
index 8a6aafca2..3673fa0b0 100644
--- a/gulliver/js/codemirror/mode/go/index.html
+++ b/gulliver/js/codemirror/mode/go/index.html
@@ -1,19 +1,31 @@
-
-
-
- CodeMirror: Go mode
-
-
-
-
-
-
-
-
-
- CodeMirror: Go mode
+CodeMirror: Go mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Go mode
// Prime Sieve in Go.
// Taken from the Go specification.
@@ -70,5 +82,4 @@ func main() {
MIME type: text/x-go
-
-
+
diff --git a/gulliver/js/codemirror/mode/groovy/groovy.js b/gulliver/js/codemirror/mode/groovy/groovy.js
index 92b948192..6800e0aaf 100644
--- a/gulliver/js/codemirror/mode/groovy/groovy.js
+++ b/gulliver/js/codemirror/mode/groovy/groovy.js
@@ -203,7 +203,8 @@ CodeMirror.defineMode("groovy", function(config) {
else return ctx.indented + (closing ? 0 : config.indentUnit);
},
- electricChars: "{}"
+ electricChars: "{}",
+ fold: "brace"
};
});
diff --git a/gulliver/js/codemirror/mode/groovy/index.html b/gulliver/js/codemirror/mode/groovy/index.html
index 3d3959577..f5efdf758 100644
--- a/gulliver/js/codemirror/mode/groovy/index.html
+++ b/gulliver/js/codemirror/mode/groovy/index.html
@@ -1,18 +1,30 @@
-
-
-
- CodeMirror: Groovy mode
-
-
-
-
-
-
-
-
- CodeMirror: Groovy mode
+CodeMirror: Groovy mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Groovy mode
//Pattern for groovy script
def p = ~/.*\.groovy/
@@ -69,5 +81,4 @@ def change(currency, amount) {
MIME types defined: text/x-groovy
-
-
+
diff --git a/gulliver/js/codemirror/mode/haskell/haskell.js b/gulliver/js/codemirror/mode/haskell/haskell.js
index 71235f4ee..facfd00a6 100644
--- a/gulliver/js/codemirror/mode/haskell/haskell.js
+++ b/gulliver/js/codemirror/mode/haskell/haskell.js
@@ -1,26 +1,26 @@
-CodeMirror.defineMode("haskell", function() {
+CodeMirror.defineMode("haskell", function(_config, modeConfig) {
function switchState(source, setState, f) {
setState(f);
return f(source, setState);
}
-
+
// These should all be Unicode extended, as per the Haskell 2010 report
var smallRE = /[a-z_]/;
var largeRE = /[A-Z]/;
- var digitRE = /[0-9]/;
+ var digitRE = /\d/;
var hexitRE = /[0-9A-Fa-f]/;
var octitRE = /[0-7]/;
var idRE = /[a-z_A-Z0-9']/;
var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
var specialRE = /[(),;[\]`{}]/;
var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
-
+
function normal(source, setState) {
if (source.eatWhile(whiteCharRE)) {
return null;
}
-
+
var ch = source.next();
if (specialRE.test(ch)) {
if (ch == '{' && source.eat('-')) {
@@ -32,7 +32,7 @@ CodeMirror.defineMode("haskell", function() {
}
return null;
}
-
+
if (ch == '\'') {
if (source.eat('\\')) {
source.next(); // should handle other escapes here
@@ -45,11 +45,11 @@ CodeMirror.defineMode("haskell", function() {
}
return "error";
}
-
+
if (ch == '"') {
return switchState(source, setState, stringLiteral);
}
-
+
if (largeRE.test(ch)) {
source.eatWhile(idRE);
if (source.eat('.')) {
@@ -57,12 +57,12 @@ CodeMirror.defineMode("haskell", function() {
}
return "variable-2";
}
-
+
if (smallRE.test(ch)) {
source.eatWhile(idRE);
return "variable";
}
-
+
if (digitRE.test(ch)) {
if (ch == '0') {
if (source.eat(/[xX]/)) {
@@ -76,9 +76,8 @@ CodeMirror.defineMode("haskell", function() {
}
source.eatWhile(digitRE);
var t = "number";
- if (source.eat('.')) {
+ if (source.match(/^\.\d+/)) {
t = "number";
- source.eatWhile(digitRE); // should require at least 1
}
if (source.eat(/[eE]/)) {
t = "number";
@@ -87,7 +86,10 @@ CodeMirror.defineMode("haskell", function() {
}
return t;
}
-
+
+ if (ch == "." && source.eat("."))
+ return "keyword";
+
if (symbolRE.test(ch)) {
if (ch == '-' && source.eat(/-/)) {
source.eatWhile(/-/);
@@ -101,12 +103,12 @@ CodeMirror.defineMode("haskell", function() {
t = "variable-2";
}
source.eatWhile(symbolRE);
- return t;
+ return t;
}
-
+
return "error";
}
-
+
function ncomment(type, nest) {
if (nest == 0) {
return normal;
@@ -130,7 +132,7 @@ CodeMirror.defineMode("haskell", function() {
return type;
};
}
-
+
function stringLiteral(source, setState) {
while (!source.eol()) {
var ch = source.next();
@@ -153,7 +155,7 @@ CodeMirror.defineMode("haskell", function() {
setState(normal);
return "error";
}
-
+
function stringGap(source, setState) {
if (source.eat('\\')) {
return switchState(source, setState, stringLiteral);
@@ -162,8 +164,8 @@ CodeMirror.defineMode("haskell", function() {
setState(normal);
return "error";
}
-
-
+
+
var wellKnownWords = (function() {
var wkw = {};
function setType(t) {
@@ -172,19 +174,19 @@ CodeMirror.defineMode("haskell", function() {
wkw[arguments[i]] = t;
};
}
-
+
setType("keyword")(
"case", "class", "data", "default", "deriving", "do", "else", "foreign",
"if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
"module", "newtype", "of", "then", "type", "where", "_");
-
+
setType("keyword")(
"\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
-
+
setType("builtin")(
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
"==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
-
+
setType("builtin")(
"Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
"False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
@@ -192,7 +194,7 @@ CodeMirror.defineMode("haskell", function() {
"Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
"ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
"String", "True");
-
+
setType("builtin")(
"abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
"asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
@@ -220,21 +222,29 @@ CodeMirror.defineMode("haskell", function() {
"toRational", "truncate", "uncurry", "undefined", "unlines", "until",
"unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
"zip3", "zipWith", "zipWith3");
-
+
+ var override = modeConfig.overrideKeywords;
+ if (override) for (var word in override) if (override.hasOwnProperty(word))
+ wkw[word] = override[word];
+
return wkw;
})();
-
-
-
+
+
+
return {
startState: function () { return { f: normal }; },
copyState: function (s) { return { f: s.f }; },
-
+
token: function(stream, state) {
var t = state.f(stream, function(s) { state.f = s; });
var w = stream.current();
- return (w in wellKnownWords) ? wellKnownWords[w] : t;
- }
+ return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;
+ },
+
+ blockCommentStart: "{-",
+ blockCommentEnd: "-}",
+ lineComment: "--"
};
});
diff --git a/gulliver/js/codemirror/mode/haskell/index.html b/gulliver/js/codemirror/mode/haskell/index.html
index 56307b8a9..056b01d46 100644
--- a/gulliver/js/codemirror/mode/haskell/index.html
+++ b/gulliver/js/codemirror/mode/haskell/index.html
@@ -1,19 +1,31 @@
-
-
-
- CodeMirror: Haskell mode
-
-
-
-
-
-
-
-
-
- CodeMirror: Haskell mode
+CodeMirror: Haskell mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Haskell mode
module UniquePerms (
uniquePerms
@@ -58,5 +70,4 @@ permBag bs = concatMap (\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs
MIME types defined: text/x-haskell.
-
-
+
diff --git a/gulliver/js/codemirror/mode/haxe/haxe.js b/gulliver/js/codemirror/mode/haxe/haxe.js
index 786fe92d0..cb761ad1c 100644
--- a/gulliver/js/codemirror/mode/haxe/haxe.js
+++ b/gulliver/js/codemirror/mode/haxe/haxe.js
@@ -1,6 +1,6 @@
CodeMirror.defineMode("haxe", function(config, parserConfig) {
var indentUnit = config.indentUnit;
-
+
// Tokenizer
var keywords = function(){
@@ -12,10 +12,10 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
"if": A, "while": A, "else": B, "do": B, "try": B,
"return": C, "break": C, "continue": C, "new": C, "throw": C,
"var": kw("var"), "inline":attribute, "static": attribute, "using":kw("import"),
- "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"),
+ "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"),
"function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
- "in": operator, "never": kw("property_access"), "trace":kw("trace"),
+ "in": operator, "never": kw("property_access"), "trace":kw("trace"),
"class": type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type,
"true": atom, "false": atom, "null": atom
};
@@ -55,14 +55,14 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
- }
+ }
else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
}
else if (state.reAllowed && (ch == "~" && stream.eat(/\//))) {
nextUntilUnescaped(stream, "/");
- stream.eatWhile(/[gimsu]/);
+ stream.eatWhile(/[gimsu]/);
return ret("regexp", "string-2");
}
else if (ch == "/") {
@@ -146,13 +146,13 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
}
-
+
function parseHaxe(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
-
+
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
@@ -168,7 +168,7 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
}
}
}
-
+
function imported(state, typename)
{
if (/[a-z]/.test(typename.charAt(0)))
@@ -177,8 +177,8 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) {
for (var i = 0; i
-
-
-
- CodeMirror: Haxe mode
-
-
-
-
-
-
-
- CodeMirror: Haxe mode
+
+CodeMirror: Haxe mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Haxe mode
+
import one.two.Three;
@@ -86,5 +100,4 @@ enum Color
MIME types defined: text/x-haxe.
-
-
+
diff --git a/gulliver/js/codemirror/mode/htmlembedded/htmlembedded.js b/gulliver/js/codemirror/mode/htmlembedded/htmlembedded.js
index e183d6746..c316cd340 100644
--- a/gulliver/js/codemirror/mode/htmlembedded/htmlembedded.js
+++ b/gulliver/js/codemirror/mode/htmlembedded/htmlembedded.js
@@ -1,12 +1,12 @@
CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
-
+
//config settings
var scriptStartRegex = parserConfig.scriptStartRegex || /^<%/i,
scriptEndRegex = parserConfig.scriptEndRegex || /^%>/i;
-
+
//inner modes
var scriptingMode, htmlMixedMode;
-
+
//tokenizer when in html mode
function htmlDispatch(stream, state) {
if (stream.match(scriptStartRegex, false)) {
@@ -32,7 +32,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
startState: function() {
scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec);
htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed");
- return {
+ return {
token : parserConfig.startOpen ? scriptingDispatch : htmlDispatch,
htmlState : CodeMirror.startState(htmlMixedMode),
scriptState : CodeMirror.startState(scriptingMode)
@@ -49,7 +49,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
else if (scriptingMode.indent)
return scriptingMode.indent(state.scriptState, textAfter);
},
-
+
copyState: function(state) {
return {
token : state.token,
@@ -57,8 +57,6 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
scriptState : CodeMirror.copyState(scriptingMode, state.scriptState)
};
},
-
- electricChars: "/{}:",
innerMode: function(state) {
if (state.token == scriptingDispatch) return {state: state.scriptState, mode: scriptingMode};
diff --git a/gulliver/js/codemirror/mode/htmlembedded/index.html b/gulliver/js/codemirror/mode/htmlembedded/index.html
index 5a37dd637..4ab90f7d8 100644
--- a/gulliver/js/codemirror/mode/htmlembedded/index.html
+++ b/gulliver/js/codemirror/mode/htmlembedded/index.html
@@ -1,21 +1,33 @@
-
-
-
- CodeMirror: Html Embedded Scripts mode
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Html Embedded Scripts mode
+CodeMirror: Html Embedded Scripts mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Html Embedded Scripts mode
<%
function hello(who) {
@@ -45,5 +57,4 @@ This is an example of EJS (embedded javascript)
MIME types defined: application/x-aspx (ASP.NET),
application/x-ejs (Embedded Javascript), application/x-jsp (JavaServer Pages)
-
-
+
diff --git a/gulliver/js/codemirror/mode/htmlmixed/htmlmixed.js b/gulliver/js/codemirror/mode/htmlmixed/htmlmixed.js
index ec0c21d24..e9eab3b92 100644
--- a/gulliver/js/codemirror/mode/htmlmixed/htmlmixed.js
+++ b/gulliver/js/codemirror/mode/htmlmixed/htmlmixed.js
@@ -44,7 +44,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
if (close > -1) stream.backUp(cur.length - close);
else if (m = cur.match(/<\/?$/)) {
stream.backUp(cur.length);
- if (!stream.match(pat, false)) stream.match(cur[0]);
+ if (!stream.match(pat, false)) stream.match(cur);
}
return style;
}
@@ -93,8 +93,6 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
return CodeMirror.Pass;
},
- electricChars: "/{}:",
-
innerMode: function(state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
diff --git a/gulliver/js/codemirror/mode/htmlmixed/index.html b/gulliver/js/codemirror/mode/htmlmixed/index.html
index c56559e55..b46174351 100644
--- a/gulliver/js/codemirror/mode/htmlmixed/index.html
+++ b/gulliver/js/codemirror/mode/htmlmixed/index.html
@@ -1,21 +1,34 @@
-
-
-
- CodeMirror: HTML mixed mode
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: HTML mixed mode
-
+
+CodeMirror: HTML mixed mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HTML mixed mode
+
@@ -69,5 +82,4 @@
(redefined, only takes effect if you load this parser after the
XML parser).
-
-
+
diff --git a/gulliver/js/codemirror/mode/http/index.html b/gulliver/js/codemirror/mode/http/index.html
index 124eb84f9..705085e22 100644
--- a/gulliver/js/codemirror/mode/http/index.html
+++ b/gulliver/js/codemirror/mode/http/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: HTTP mode
-
-
-
-
-
-
-
- CodeMirror: HTTP mode
+
+CodeMirror: HTTP mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+HTTP mode
+
POST /somewhere HTTP/1.1
@@ -28,5 +42,4 @@ This is the request body!
MIME types defined: message/http.
-
-
+
diff --git a/gulliver/js/codemirror/mode/index.html b/gulliver/js/codemirror/mode/index.html
new file mode 100644
index 000000000..7c1f74061
--- /dev/null
+++ b/gulliver/js/codemirror/mode/index.html
@@ -0,0 +1,115 @@
+
+
+CodeMirror: Language Modes
+
+
+
+
+
+
+
+
+
+
+
+
+Language modes
+
+This is a list of every mode in the distribution. Each mode lives
+in a subdirectory of the mode/ directory, and typically
+defines a single JavaScript file that implements the mode. Loading
+such file will make the language available to CodeMirror, through
+the mode
+option.
+
+
+
+
diff --git a/gulliver/js/codemirror/mode/javascript/index.html b/gulliver/js/codemirror/mode/javascript/index.html
index cca7d04ea..45d70ffdb 100644
--- a/gulliver/js/codemirror/mode/javascript/index.html
+++ b/gulliver/js/codemirror/mode/javascript/index.html
@@ -1,18 +1,33 @@
-
-
-
- CodeMirror: JavaScript mode
-
-
-
-
-
-
-
-
-
- CodeMirror: JavaScript mode
+
+CodeMirror: JavaScript mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+JavaScript mode
+
// Demo code (the actual new parser character stream implementation)
@@ -68,7 +83,8 @@ StringStream.prototype = {
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
matchBrackets: true,
- continueComments: "Enter"
+ continueComments: "Enter",
+ extraKeys: {"Ctrl-Q": "toggleComment"}
});
@@ -76,13 +92,16 @@ StringStream.prototype = {
JavaScript mode supports a two configuration
options:
- json which will set the mode to expect JSON data rather than a JavaScript program.
-
- typescript which will activate additional syntax highlighting and some other things for TypeScript code (demo ).
-
+ json which will set the mode to expect JSON
+ data rather than a JavaScript program.
+ typescript which will activate additional
+ syntax highlighting and some other things for TypeScript code
+ (demo ).
+ statementIndent which (given a number) will
+ determine the amount of indentation to use for statements
+ continued on a new line.
MIME types defined: text/javascript, application/json, text/typescript, application/typescript.
-
-
+
diff --git a/gulliver/js/codemirror/mode/javascript/javascript.js b/gulliver/js/codemirror/mode/javascript/javascript.js
index ff6bb5d80..fbf574b4f 100644
--- a/gulliver/js/codemirror/mode/javascript/javascript.js
+++ b/gulliver/js/codemirror/mode/javascript/javascript.js
@@ -2,6 +2,7 @@
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
+ var statementIndent = parserConfig.statementIndent;
var jsonMode = parserConfig.json;
var isTS = parserConfig.typescript;
@@ -11,16 +12,17 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
-
+
var jsKeywords = {
- "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
- "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
+ "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
- "this": kw("this")
+ "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
+ "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
@@ -29,7 +31,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var tsKeywords = {
// object-like things
"interface": kw("interface"),
- "class": kw("class"),
"extends": kw("extends"),
"constructor": kw("constructor"),
@@ -39,8 +40,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"protected": kw("protected"),
"static": kw("static"),
- "super": kw("super"),
-
// types
"string": type, "number": type, "bool": type, "any": type
};
@@ -55,19 +54,16 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
- function chain(stream, state, f) {
- state.tokenize = f;
- return f(stream, state);
- }
-
- function nextUntilUnescaped(stream, end) {
- var escaped = false, next;
+ function readRegexp(stream) {
+ var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
- if (next == end && !escaped)
- return false;
+ if (!escaped) {
+ if (next == "/" && !inSet) return;
+ if (next == "[") inSet = true;
+ else if (inSet && next == "]") inSet = false;
+ }
escaped = !escaped && next == "\\";
}
- return escaped;
}
// Used as scratch variables to communicate multiple values without
@@ -77,49 +73,51 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
type = tp; content = cont;
return style;
}
-
- function jsTokenBase(stream, state) {
+ function tokenBase(stream, state) {
var ch = stream.next();
- if (ch == '"' || ch == "'")
- return chain(stream, state, jsTokenString(ch));
- else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+ if (ch == '"' || ch == "'") {
+ state.tokenize = tokenString(ch);
+ return state.tokenize(stream, state);
+ } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
+ return ret("number", "number");
+ } else if (ch == "." && stream.match("..")) {
+ return ret("spread", "meta");
+ } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
- else if (ch == "0" && stream.eat(/x/i)) {
+ } else if (ch == "=" && stream.eat(">")) {
+ return ret("=>", "operator");
+ } else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
- }
- else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
+ } else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
- }
- else if (ch == "/") {
+ } else if (ch == "/") {
if (stream.eat("*")) {
- return chain(stream, state, jsTokenComment);
- }
- else if (stream.eat("/")) {
+ state.tokenize = tokenComment;
+ return tokenComment(stream, state);
+ } else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
- }
- else if (state.lastType == "operator" || state.lastType == "keyword c" ||
- /^[\[{}\(,;:]$/.test(state.lastType)) {
- nextUntilUnescaped(stream, "/");
+ } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
+ state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
+ readRegexp(stream);
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
return ret("regexp", "string-2");
- }
- else {
+ } else {
stream.eatWhile(isOperatorChar);
- return ret("operator", null, stream.current());
+ return ret("operator", "operator", stream.current());
}
- }
- else if (ch == "#") {
+ } else if (ch == "`") {
+ state.tokenize = tokenQuasi;
+ return tokenQuasi(stream, state);
+ } else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
- }
- else if (isOperatorChar.test(ch)) {
+ } else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
- return ret("operator", null, stream.current());
- }
- else {
+ return ret("operator", "operator", stream.current());
+ } else {
stream.eatWhile(/[\w\$_]/);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
@@ -127,19 +125,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
}
- function jsTokenString(quote) {
+ function tokenString(quote) {
return function(stream, state) {
- if (!nextUntilUnescaped(stream, quote))
- state.tokenize = jsTokenBase;
+ var escaped = false, next;
+ while ((next = stream.next()) != null) {
+ if (next == quote && !escaped) break;
+ escaped = !escaped && next == "\\";
+ }
+ if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
- function jsTokenComment(stream, state) {
+ function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
- state.tokenize = jsTokenBase;
+ state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
@@ -147,6 +149,50 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return ret("comment", "comment");
}
+ function tokenQuasi(stream, state) {
+ var escaped = false, next;
+ while ((next = stream.next()) != null) {
+ if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ return ret("quasi", "string-2", stream.current());
+ }
+
+ var brackets = "([{}])";
+ // This is a crude lookahead trick to try and notice that we're
+ // parsing the argument patterns for a fat-arrow function before we
+ // actually hit the arrow token. It only works if the arrow is on
+ // the same line as the arguments and there's no strange noise
+ // (comments) in between. Fallback is to only notice when we hit the
+ // arrow, and not declare the arguments as locals for the arrow
+ // body.
+ function findFatArrow(stream, state) {
+ if (state.fatArrowAt) state.fatArrowAt = null;
+ var arrow = stream.string.indexOf("=>", stream.start);
+ if (arrow < 0) return;
+
+ var depth = 0, sawSomething = false;
+ for (var pos = arrow - 1; pos >= 0; --pos) {
+ var ch = stream.string.charAt(pos);
+ var bracket = brackets.indexOf(ch);
+ if (bracket >= 0 && bracket < 3) {
+ if (!depth) { ++pos; break; }
+ if (--depth == 0) break;
+ } else if (bracket >= 3 && bracket < 6) {
+ ++depth;
+ } else if (/[$\w]/.test(ch)) {
+ sawSomething = true;
+ } else if (sawSomething && !depth) {
+ ++pos;
+ break;
+ }
+ }
+ if (sawSomething && !depth) state.fatArrowAt = pos;
+ }
+
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
@@ -163,6 +209,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
+ for (var cx = state.context; cx; cx = cx.prev) {
+ for (var v = cx.vars; v; v = v.next)
+ if (v.name == varname) return true;
+ }
}
function parseJS(state, style, type, content, stream) {
@@ -170,7 +220,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
-
+
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
@@ -209,7 +259,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
- state.globalVars = {name: varname, next: state.globalVars};
+ if (parserConfig.globalVars)
+ state.globalVars = {name: varname, next: state.globalVars};
}
}
@@ -226,8 +277,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
function pushlex(type, info) {
var result = function() {
- var state = cx.state;
- state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
+ var state = cx.state, indent = state.indented;
+ if (state.lexical.type == "stat") indent = state.lexical.indented;
+ state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
@@ -250,53 +302,103 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
};
}
- function statement(type) {
- if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+ function statement(type, value) {
+ if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
+ if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
if (type == "function") return cont(functiondef);
- if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
- poplex, statement, poplex);
+ if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
- block, poplex, poplex);
+ block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
- statement, poplex, popcontext);
+ statement, poplex, popcontext);
+ if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
+ if (type == "class") return cont(pushlex("form"), className, objlit, poplex);
+ if (type == "export") return cont(pushlex("form"), afterExport, poplex);
+ if (type == "import") return cont(pushlex("form"), afterImport, poplex);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
- if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
+ return expressionInner(type, false);
+ }
+ function expressionNoComma(type) {
+ return expressionInner(type, true);
+ }
+ function expressionInner(type, noComma) {
+ if (cx.state.fatArrowAt == cx.stream.start) {
+ var body = noComma ? arrowBodyNoComma : arrowBody;
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
+ else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
+ }
+
+ var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef);
- if (type == "keyword c") return cont(maybeexpression);
- if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
- if (type == "operator") return cont(expression);
- if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
- if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
+ if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
+ if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
+ if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
+ if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
+ if (type == "{") return contCommasep(objprop, "}", null, maybeop);
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
-
- function maybeoperator(type, value) {
+ function maybeexpressionNoComma(type) {
+ if (type.match(/[;\}\)\],]/)) return pass();
+ return pass(expressionNoComma);
+ }
+
+ function maybeoperatorComma(type, value) {
+ if (type == ",") return cont(expression);
+ return maybeoperatorNoComma(type, value, false);
+ }
+ function maybeoperatorNoComma(type, value, noComma) {
+ var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
+ var expr = noComma == false ? expression : expressionNoComma;
+ if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
if (type == "operator") {
- if (/\+\+|--/.test(value)) return cont(maybeoperator);
- if (value == "?") return cont(expression, expect(":"), expression);
- return cont(expression);
+ if (/\+\+|--/.test(value)) return cont(me);
+ if (value == "?") return cont(expression, expect(":"), expr);
+ return cont(expr);
}
+ if (type == "quasi") { cx.cc.push(me); return quasi(value); }
if (type == ";") return;
- if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
- if (type == ".") return cont(property, maybeoperator);
- if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
+ if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
+ if (type == ".") return cont(property, me);
+ if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
+ }
+ function quasi(value) {
+ if (value.slice(value.length - 2) != "${") return cont();
+ return cont(expression, continueQuasi);
+ }
+ function continueQuasi(type) {
+ if (type == "}") {
+ cx.marked = "string-2";
+ cx.state.tokenize = tokenQuasi;
+ return cont();
+ }
+ }
+ function arrowBody(type) {
+ findFatArrow(cx.stream, cx.state);
+ if (type == "{") return pass(statement);
+ return pass(expression);
+ }
+ function arrowBodyNoComma(type) {
+ findFatArrow(cx.stream, cx.state);
+ if (type == "{") return pass(statement);
+ return pass(expressionNoComma);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
- return pass(maybeoperator, expect(";"), poplex);
+ return pass(maybeoperatorComma, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
@@ -307,89 +409,164 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (value == "get" || value == "set") return cont(getterSetter);
} else if (type == "number" || type == "string") {
cx.marked = type + " property";
+ } else if (type == "[") {
+ return cont(expression, expect("]"), afterprop);
}
- if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
+ if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
}
function getterSetter(type) {
- if (type == ":") return cont(expression);
- if (type != "variable") return cont(expect(":"), expression);
+ if (type != "variable") return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
+ function afterprop(type) {
+ if (type == ":") return cont(expressionNoComma);
+ if (type == "(") return pass(functiondef);
+ }
function commasep(what, end) {
function proceed(type) {
- if (type == ",") return cont(what, proceed);
+ if (type == ",") {
+ var lex = cx.state.lexical;
+ if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
+ return cont(what, proceed);
+ }
if (type == end) return cont();
return cont(expect(end));
}
return function(type) {
if (type == end) return cont();
- else return pass(what, proceed);
+ return pass(what, proceed);
};
}
+ function contCommasep(what, end, info) {
+ for (var i = 3; i < arguments.length; i++)
+ cx.cc.push(arguments[i]);
+ return cont(pushlex(end, info), commasep(what, end), poplex);
+ }
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type) {
- if (type == ":") return cont(typedef);
- return pass();
+ if (isTS && type == ":") return cont(typedef);
}
function typedef(type) {
if (type == "variable"){cx.marked = "variable-3"; return cont();}
- return pass();
}
- function vardef1(type, value) {
- if (type == "variable") {
+ function vardef() {
+ return pass(pattern, maybetype, maybeAssign, vardefCont);
+ }
+ function pattern(type, value) {
+ if (type == "variable") { register(value); return cont(); }
+ if (type == "[") return contCommasep(pattern, "]");
+ if (type == "{") return contCommasep(proppattern, "}");
+ }
+ function proppattern(type, value) {
+ if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
register(value);
- return isTS ? cont(maybetype, vardef2) : cont(vardef2);
+ return cont(maybeAssign);
}
- return pass();
+ if (type == "variable") cx.marked = "property";
+ return cont(expect(":"), pattern, maybeAssign);
}
- function vardef2(type, value) {
- if (value == "=") return cont(expression, vardef2);
- if (type == ",") return cont(vardef1);
+ function maybeAssign(_type, value) {
+ if (value == "=") return cont(expressionNoComma);
+ }
+ function vardefCont(type) {
+ if (type == ",") return cont(vardef);
+ }
+ function maybeelse(type, value) {
+ if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
+ }
+ function forspec(type) {
+ if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
}
function forspec1(type) {
- if (type == "var") return cont(vardef1, expect(";"), forspec2);
+ if (type == "var") return cont(vardef, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
- if (type == "variable") return cont(formaybein);
- return cont(forspec2);
+ if (type == "variable") return cont(formaybeinof);
+ return pass(expression, expect(";"), forspec2);
}
- function formaybein(_type, value) {
- if (value == "in") return cont(expression);
- return cont(maybeoperator, forspec2);
+ function formaybeinof(_type, value) {
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+ return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
- if (value == "in") return cont(expression);
- return cont(expression, expect(";"), forspec3);
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+ return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
+ if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);}
- if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
}
- function funarg(type, value) {
- if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
+ function funarg(type) {
+ if (type == "spread") return cont(funarg);
+ return pass(pattern, maybetype);
+ }
+ function className(type, value) {
+ if (type == "variable") {register(value); return cont(classNameAfter);}
+ }
+ function classNameAfter(_type, value) {
+ if (value == "extends") return cont(expression);
+ }
+ function objlit(type) {
+ if (type == "{") return contCommasep(objprop, "}");
+ }
+ function afterModule(type, value) {
+ if (type == "string") return cont(statement);
+ if (type == "variable") { register(value); return cont(maybeFrom); }
+ }
+ function afterExport(_type, value) {
+ if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
+ if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
+ return pass(statement);
+ }
+ function afterImport(type) {
+ if (type == "string") return cont();
+ return pass(importSpec, maybeFrom);
+ }
+ function importSpec(type, value) {
+ if (type == "{") return contCommasep(importSpec, "}");
+ if (type == "variable") register(value);
+ return cont();
+ }
+ function maybeFrom(_type, value) {
+ if (value == "from") { cx.marked = "keyword"; return cont(expression); }
+ }
+ function arrayLiteral(type) {
+ if (type == "]") return cont();
+ return pass(expressionNoComma, maybeArrayComprehension);
+ }
+ function maybeArrayComprehension(type) {
+ if (type == "for") return pass(comprehension, expect("]"));
+ if (type == ",") return cont(commasep(expressionNoComma, "]"));
+ return pass(commasep(expressionNoComma, "]"));
+ }
+ function comprehension(type) {
+ if (type == "for") return cont(forspec, comprehension);
+ if (type == "if") return cont(expression, comprehension);
}
// Interface
return {
startState: function(basecolumn) {
- return {
- tokenize: jsTokenBase,
- lastType: null,
+ var state = {
+ tokenize: tokenBase,
+ lastType: "sof",
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
- globalVars: parserConfig.globalVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
+ if (parserConfig.globalVars) state.globalVars = parserConfig.globalVars;
+ return state;
},
token: function(stream, state) {
@@ -397,33 +574,48 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
+ findFatArrow(stream, state);
}
- if (stream.eatSpace()) return null;
+ if (state.tokenize != tokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
- state.lastType = type;
+ state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
- if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
- if (state.tokenize != jsTokenBase) return 0;
+ if (state.tokenize == tokenComment) return CodeMirror.Pass;
+ if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
+ // Kludge to prevent 'maybelse' from blocking lexical scope pops
+ for (var i = state.cc.length - 1; i >= 0; --i) {
+ var c = state.cc[i];
+ if (c == poplex) lexical = lexical.prev;
+ else if (c != maybeelse) break;
+ }
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
+ if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
+ lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
- if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
+
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
- return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
- else if (lexical.info == "switch" && !closing)
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
+ else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricChars: ":{}",
+ blockCommentStart: jsonMode ? null : "/*",
+ blockCommentEnd: jsonMode ? null : "*/",
+ lineComment: jsonMode ? null : "//",
+ fold: "brace",
+ helperType: jsonMode ? "json" : "javascript",
jsonMode: jsonMode
};
});
@@ -433,5 +625,6 @@ CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
diff --git a/gulliver/js/codemirror/mode/javascript/test.js b/gulliver/js/codemirror/mode/javascript/test.js
new file mode 100644
index 000000000..911bbbfd7
--- /dev/null
+++ b/gulliver/js/codemirror/mode/javascript/test.js
@@ -0,0 +1,113 @@
+(function() {
+ var mode = CodeMirror.getMode({indentUnit: 2}, "javascript");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+
+ MT("locals",
+ "[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
+
+ MT("comma-and-binop",
+ "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }");
+
+ MT("destructuring",
+ "([keyword function]([def a], [[[def b], [def c] ]]) {",
+ " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);",
+ " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];",
+ "})();");
+
+ MT("class",
+ "[keyword class] [variable Point] [keyword extends] [variable SuperThing] {",
+ " [[ [string-2 /expr/] ]]: [number 24],",
+ " [property constructor]([def x], [def y]) {",
+ " [keyword super]([string 'something']);",
+ " [keyword this].[property x] [operator =] [variable-2 x];",
+ " }",
+ "}");
+
+ MT("module",
+ "[keyword module] [string 'foo'] {",
+ " [keyword export] [keyword let] [def x] [operator =] [number 42];",
+ " [keyword export] [keyword *] [keyword from] [string 'somewhere'];",
+ "}");
+
+ MT("import",
+ "[keyword function] [variable foo]() {",
+ " [keyword import] [def $] [keyword from] [string 'jquery'];",
+ " [keyword module] [def crypto] [keyword from] [string 'crypto'];",
+ " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
+ "}");
+
+ MT("const",
+ "[keyword function] [variable f]() {",
+ " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
+ "}");
+
+ MT("for/of",
+ "[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}");
+
+ MT("generator",
+ "[keyword function*] [variable repeat]([def n]) {",
+ " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
+ " [keyword yield] [variable-2 i];",
+ "}");
+
+ MT("fatArrow",
+ "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
+ "[variable a];", // No longer in scope
+ "[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
+ "[variable c];");
+
+ MT("spread",
+ "[keyword function] [variable f]([def a], [meta ...][def b]) {",
+ " [variable something]([variable-2 a], [meta ...][variable-2 b]);",
+ "}");
+
+ MT("comprehension",
+ "[keyword function] [variable f]() {",
+ " [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
+ " ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
+ "}");
+
+ MT("quasi",
+ "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
+
+ MT("indent_statement",
+ "[keyword var] [variable x] [operator =] [number 10]",
+ "[variable x] [operator +=] [variable y] [operator +]",
+ " [atom Infinity]",
+ "[keyword debugger];");
+
+ MT("indent_if",
+ "[keyword if] ([number 1])",
+ " [keyword break];",
+ "[keyword else] [keyword if] ([number 2])",
+ " [keyword continue];",
+ "[keyword else]",
+ " [number 10];",
+ "[keyword if] ([number 1]) {",
+ " [keyword break];",
+ "} [keyword else] [keyword if] ([number 2]) {",
+ " [keyword continue];",
+ "} [keyword else] {",
+ " [number 10];",
+ "}");
+
+ MT("indent_for",
+ "[keyword for] ([keyword var] [variable i] [operator =] [number 0];",
+ " [variable i] [operator <] [number 100];",
+ " [variable i][operator ++])",
+ " [variable doSomething]([variable i]);",
+ "[keyword debugger];");
+
+ MT("indent_c_style",
+ "[keyword function] [variable foo]()",
+ "{",
+ " [keyword debugger];",
+ "}");
+
+ MT("multilinestring",
+ "[keyword var] [variable x] [operator =] [string 'foo\\]",
+ "[string bar'];");
+
+ MT("scary_regexp",
+ "[string-2 /foo[[/]]bar/];");
+})();
diff --git a/gulliver/js/codemirror/mode/javascript/typescript.html b/gulliver/js/codemirror/mode/javascript/typescript.html
index 58315e7ac..9cc5f4932 100644
--- a/gulliver/js/codemirror/mode/javascript/typescript.html
+++ b/gulliver/js/codemirror/mode/javascript/typescript.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: TypeScript mode
-
-
-
-
-
-
-
- CodeMirror: TypeScript mode
+
+CodeMirror: TypeScript mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+TypeScript mode
+
class Greeter {
@@ -44,5 +58,4 @@ document.body.appendChild(button)
This is a specialization of the JavaScript mode .
-
-
+
diff --git a/gulliver/js/codemirror/mode/jinja2/index.html b/gulliver/js/codemirror/mode/jinja2/index.html
index 7cd1da233..66bf2ec60 100644
--- a/gulliver/js/codemirror/mode/jinja2/index.html
+++ b/gulliver/js/codemirror/mode/jinja2/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Jinja2 mode
-
-
-
-
-
-
-
- CodeMirror: Jinja2 mode
-
+
+CodeMirror: Jinja2 mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Jinja2 mode
+
<html style="color: green">
<!-- this is a comment -->
<head>
@@ -34,5 +47,4 @@
CodeMirror.fromTextArea(document.getElementById("code"), {mode:
{name: "jinja2", htmlMode: true}});
-
-
+
diff --git a/gulliver/js/codemirror/mode/jinja2/jinja2.js b/gulliver/js/codemirror/mode/jinja2/jinja2.js
index 1472d398f..b28af098d 100644
--- a/gulliver/js/codemirror/mode/jinja2/jinja2.js
+++ b/gulliver/js/codemirror/mode/jinja2/jinja2.js
@@ -1,7 +1,17 @@
CodeMirror.defineMode("jinja2", function() {
- var keywords = ["block", "endblock", "for", "endfor", "in", "true", "false",
- "loop", "none", "self", "super", "if", "as", "not", "and",
- "else", "import", "with", "without", "context"];
+ var keywords = ["and", "as", "block", "endblock", "by", "cycle", "debug", "else", "elif",
+ "extends", "filter", "endfilter", "firstof", "for",
+ "endfor", "if", "endif", "ifchanged", "endifchanged",
+ "ifequal", "endifequal", "ifnotequal",
+ "endifnotequal", "in", "include", "load", "not", "now", "or",
+ "parsed", "regroup", "reversed", "spaceless",
+ "endspaceless", "ssi", "templatetag", "openblock",
+ "closeblock", "openvariable", "closevariable",
+ "openbrace", "closebrace", "opencomment",
+ "closecomment", "widthratio", "url", "with", "endwith",
+ "get_current_language", "trans", "noop", "blocktrans",
+ "endblocktrans", "get_available_languages",
+ "get_current_language_bidi", "plural"];
keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b");
function tokenBase (stream, state) {
@@ -38,5 +48,5 @@ CodeMirror.defineMode("jinja2", function() {
token: function (stream, state) {
return state.tokenize(stream, state);
}
- };
+ };
});
diff --git a/gulliver/js/codemirror/mode/less/index.html b/gulliver/js/codemirror/mode/less/index.html
index 78c1e5307..7239143c8 100644
--- a/gulliver/js/codemirror/mode/less/index.html
+++ b/gulliver/js/codemirror/mode/less/index.html
@@ -1,19 +1,32 @@
-
-
-
- CodeMirror: LESS mode
-
-
-
-
-
-
-
-
-
- CodeMirror: LESS mode
- @media screen and (device-aspect-ratio: 16/9) { … }
+
+CodeMirror: LESS mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+LESS mode
+@media screen and (device-aspect-ratio: 16/9) { … }
@media screen and (device-aspect-ratio: 32/18) { … }
@media screen and (device-aspect-ratio: 1280/720) { … }
@media screen and (device-aspect-ratio: 2560/1440) { … }
@@ -737,5 +750,4 @@ td {
MIME types defined: text/x-less, text/css (if not previously defined).
-
-
+
diff --git a/gulliver/js/codemirror/mode/less/less.js b/gulliver/js/codemirror/mode/less/less.js
index 70cd5c937..da681ea67 100644
--- a/gulliver/js/codemirror/mode/less/less.js
+++ b/gulliver/js/codemirror/mode/less/less.js
@@ -1,90 +1,80 @@
/*
LESS mode - http://www.lesscss.org/
Ported to CodeMirror by Peter Kroon
- Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues GitHub: @peterkroon
+ Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues
+ GitHub: @peterkroon
*/
CodeMirror.defineMode("less", function(config) {
var indentUnit = config.indentUnit, type;
function ret(style, tp) {type = tp; return style;}
- //html tags
- var tags = "a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption cite code col colgroup command datalist dd del details dfn dir div dl dt em embed fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins keygen kbd label legend li link map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr".split(' ');
-
- function inTagsArray(val){
- for(var i=0; i*\/]/.test(ch)) {
+ } else if (/[,+<>*\/]/.test(ch)) {
if(stream.peek() == "=" || type == "a")return ret("string", "string");
+ if(ch === ",")return ret(null, ch);
return ret(null, "select-op");
- }
- else if (/[;{}:\[\]()~\|]/.test(ch)) {
- if(ch == ":"){
+ } else if (/[;{}:\[\]()~\|]/.test(ch)) {
+ if(ch == ":"){
stream.eatWhile(/[a-z\\\-]/);
if( selectors.test(stream.current()) ){
return ret("tag", "tag");
- }else if(stream.peek() == ":"){//::-webkit-search-decoration
+ } else if(stream.peek() == ":"){//::-webkit-search-decoration
stream.next();
stream.eatWhile(/[a-z\\\-]/);
if(stream.current().match(/\:\:\-(o|ms|moz|webkit)\-/))return ret("string", "string");
if( selectors.test(stream.current().substring(1)) )return ret("tag", "tag");
return ret(null, ch);
- }else{
- return ret(null, ch);
+ } else {
+ return ret(null, ch);
}
- }else if(ch == "~"){
+ } else if(ch == "~"){
if(type == "r")return ret("string", "string");
- }else{
+ } else {
return ret(null, ch);
}
- }
- else if (ch == ".") {
- if(type == "(" || type == "string")return ret("string", "string"); // allow url(../image.png)
+ } else if (ch == ".") {
+ if(type == "(")return ret("string", "string"); // allow url(../image.png)
stream.eatWhile(/[\a-zA-Z0-9\-_]/);
- if(stream.peek() == " ")stream.eatSpace();
- if(stream.peek() == ")")return ret("number", "unit");//rgba(0,0,0,.25);
+ if(stream.peek() === " ")stream.eatSpace();
+ if(stream.peek() === ")" || type === ":")return ret("number", "unit");//rgba(0,0,0,.25);
+ else if(stream.current().length >1){
+ if(state.stack[state.stack.length-1] === "rule" && !stream.match(/^[{,+(]/, false)) return ret("number", "unit");
+ }
return ret("tag", "tag");
- }
- else if (ch == "#") {
+ } else if (ch == "#") {
//we don't eat white-space, we want the hex color and or id only
stream.eatWhile(/[A-Za-z0-9]/);
//check if there is a proper hex color length e.g. #eee || #eeeEEE
@@ -95,7 +85,9 @@ CodeMirror.defineMode("less", function(config) {
//eat white-space
stream.eatSpace();
//when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
- if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag");
+ if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) ){
+ if(type === "select-op")return ret("number", "unit"); else return ret("atom", "tag");
+ }
//#time { color: #aaa }
else if(stream.peek() == "}" )return ret("number", "unit");
//we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
@@ -104,40 +96,53 @@ CodeMirror.defineMode("less", function(config) {
else if(stream.eol())return ret("atom", "tag");
//default
else return ret("number", "unit");
- }else{//when not a valid hexvalue in the current stream e.g. #footer
+ } else {//when not a valid hexvalue in the current stream e.g. #footer
stream.eatWhile(/[\w\\\-]/);
- return ret("atom", "tag");
+ return ret("atom", stream.current());
}
- }else{//when not a valid hexvalue length
+ } else {//when not a valid hexvalue length
stream.eatWhile(/[\w\\\-]/);
+ if(state.stack[state.stack.length-1] === "rule")return ret("atom", stream.current());return ret("atom", stream.current());
return ret("atom", "tag");
}
- }
- else if (ch == "&") {
+ } else if (ch == "&") {
stream.eatWhile(/[\w\-]/);
return ret(null, ch);
- }
- else {
+ } else {
stream.eatWhile(/[\w\\\-_%.{]/);
- if(type == "string"){
- return ret("string", "string");
- }else if(stream.current().match(/(^http$|^https$)/) != null){
+ if(stream.current().match(/\\/) !== null){
+ if(stream.current().charAt(stream.current().length-1) === "\\"){
+ stream.eat(/\'|\"|\)|\(/);
+ while(stream.eatWhile(/[\w\\\-_%.{]/)){
+ stream.eat(/\'|\"|\)|\(/);
+ }
+ return ret("string", stream.current());
+ }
+ } //else if(type === "tag")return ret("tag", "tag");
+ else if(type == "string"){
+ if(state.stack[state.stack.length-1] === "{" && stream.peek() === ":")return ret("variable", "variable");
+ if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
+ return ret(type, stream.current());
+ } else if(stream.current().match(/(^http$|^https$)/) != null){
stream.eatWhile(/[\w\\\-_%.{:\/]/);
+ if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
return ret("string", "string");
- }else if(stream.peek() == "<" || stream.peek() == ">"){
+ } else if(stream.peek() == "<" || stream.peek() == ">" || stream.peek() == "+"){
+ if(type === "(" && (stream.current() === "n" || stream.current() === "-n"))return ret("string", stream.current());
return ret("tag", "tag");
- }else if( /\(/.test(stream.peek()) ){
+ } else if( /\(/.test(stream.peek()) ){
+ if(stream.current() === "when")return ret("variable","variable");
+ else if(state.stack[state.stack.length-1] === "@media" && stream.current() === "and")return ret("variable",stream.current());
return ret(null, ch);
- }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png)
- return ret("string", "string");
- }else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign
+ } else if (stream.peek() == "/" && state.stack[state.stack.length-1] !== undefined){ // url(dir/center/image.png)
+ if(stream.peek() === "/")stream.eatWhile(/[\w\\\-_%.{:\/]/);
+ return ret("string", stream.current());
+ } else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign
//commment out these 2 comment if you want the minus sign to be parsed as null -500px
//stream.backUp(stream.current().length-1);
- //return ret(null, ch); //console.log( stream.current() );
+ //return ret(null, ch);
return ret("number", "unit");
- }else if( inTagsArray(stream.current().toLowerCase()) ){ // match html tags
- return ret("tag", "tag");
- }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
+ } else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
stream.backUp(1);
return ret("tag", "tag");
@@ -145,41 +150,104 @@ CodeMirror.defineMode("less", function(config) {
stream.eatSpace();
if( /[{<>.a-zA-Z\/]/.test(stream.peek()) || stream.eol() )return ret("tag", "tag"); // e.g. button.icon-plus
return ret("string", "string"); // let url(/images/logo.png) without quotes return as string
- }else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){
+ } else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){
+
if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
+ else if(state.stack[state.stack.length-1] === "border-color" || state.stack[state.stack.length-1] === "background-position" || state.stack[state.stack.length-1] === "font-family")return ret(null, stream.current());
+ else if(type === "tag")return ret("tag", "tag");
+ else if((type === ":" || type === "unit") && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
+ else if(state.stack[state.stack.length-1] === "rule" && type === "tag")return ret("string", stream.current());
+ else if(state.stack[state.stack.length-1] === ";" && type === ":")return ret(null, stream.current());
+ //else if(state.stack[state.stack.length-1] === ";" || type === "")return ret("variable", stream.current());
+ else if(stream.peek() === "#" && type !== undefined && type.match(/\+|,|tag|select\-op|}|{|;/g) === null)return ret("string", stream.current());
+ else if(type === "variable")return ret(null, stream.current());
+ else if(state.stack[state.stack.length-1] === "{" && type === "comment")return ret("variable", stream.current());
+ else if(state.stack.length === 0 && (type === ";" || type === "comment"))return ret("tag", stream.current());
+ else if((state.stack[state.stack.length-1] === "{" || type === ";") && state.stack[state.stack.length-1] !== "@media{")return ret("variable", stream.current());
+ else if(state.stack[state.stack.length-2] === "{" && state.stack[state.stack.length-1] === ";")return ret("variable", stream.current());
+
return ret("tag", "tag");
- }else if(type == "compare" || type == "a" || type == "("){
+ } else if(type == "compare" || type == "a" || type == "("){
return ret("string", "string");
- }else if(type == "|" || stream.current() == "-" || type == "["){
+ } else if(type == "|" || stream.current() == "-" || type == "["){
+ if (type == "|" && stream.match(/^[\]=~]/, false)) return ret("number", stream.current());
+ else if(type == "|" )return ret("tag", "tag");
+ else if(type == "["){
+ stream.eatWhile(/\w\-/);
+ return ret("number", stream.current());
+ }
return ret(null, ch);
- }else if(stream.peek() == ":") {
+ } else if((stream.peek() == ":") || ( stream.eatSpace() && stream.peek() == ":")) {
stream.next();
var t_v = stream.peek() == ":" ? true : false;
if(!t_v){
- var old_pos = stream.pos;
- var sc = stream.current().length;
- stream.eatWhile(/[a-z\\\-]/);
- var new_pos = stream.pos;
- if(stream.current().substring(sc-1).match(selectors) != null){
- stream.backUp(new_pos-(old_pos-1));
- return ret("tag", "tag");
- } else stream.backUp(new_pos-(old_pos-1));
- }else{
- stream.backUp(1);
- }
- if(t_v)return ret("tag", "tag"); else return ret("variable", "variable");
- }else{
- return ret("variable", "variable");
+ var old_pos = stream.pos;
+ var sc = stream.current().length;
+ stream.eatWhile(/[a-z\\\-]/);
+ var new_pos = stream.pos;
+ if(stream.current().substring(sc-1).match(selectors) != null){
+ stream.backUp(new_pos-(old_pos-1));
+ return ret("tag", "tag");
+ } else stream.backUp(new_pos-(old_pos-1));
+ } else {
+ stream.backUp(1);
+ }
+ if(t_v)return ret("tag", "tag"); else return ret("variable", "variable");
+ } else if(state.stack[state.stack.length-1] === "font-family" || state.stack[state.stack.length-1] === "background-position" || state.stack[state.stack.length-1] === "border-color"){
+ return ret(null, null);
+ } else {
+
+ if(state.stack[state.stack.length-1] === null && type === ":")return ret(null, stream.current());
+
+ //else if((type === ")" && state.stack[state.stack.length-1] === "rule") || (state.stack[state.stack.length-2] === "{" && state.stack[state.stack.length-1] === "rule" && type === "variable"))return ret(null, stream.current());
+
+ else if (/\^|\$/.test(stream.current()) && stream.match(/^[~=]/, false)) return ret("string", "string");//att^=val
+
+ else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
+ else if(type === "unit" && state.stack[state.stack.length-1] === ";")return ret(null, "unit");
+ else if(type === ")" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
+ else if(type && type.match("@") !== null && state.stack[state.stack.length-1] === "rule")return ret(null, "unit");
+ //else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
+
+ else if((type === ";" || type === "}" || type === ",") && state.stack[state.stack.length-1] === ";")return ret("tag", stream.current());
+ else if((type === ";" && stream.peek() !== undefined && !stream.match(/^[{\.]/, false)) ||
+ (type === ";" && stream.eatSpace() && !stream.match(/^[{\.]/))) return ret("variable", stream.current());
+ else if((type === "@media" && state.stack[state.stack.length-1] === "@media") || type === "@namespace")return ret("tag", stream.current());
+
+ else if(type === "{" && state.stack[state.stack.length-1] === ";" && stream.peek() === "{")return ret("tag", "tag");
+ else if((type === "{" || type === ":") && state.stack[state.stack.length-1] === ";")return ret(null, stream.current());
+ else if((state.stack[state.stack.length-1] === "{" && stream.eatSpace() && !stream.match(/^[\.#]/)) || type === "select-op" || (state.stack[state.stack.length-1] === "rule" && type === ",") )return ret("tag", "tag");
+ else if(type === "variable" && state.stack[state.stack.length-1] === "rule")return ret("tag", "tag");
+ else if((stream.eatSpace() && stream.peek() === "{") || stream.eol() || stream.peek() === "{")return ret("tag", "tag");
+ //this one messes up indentation
+ //else if((type === "}" && stream.peek() !== ":") || (type === "}" && stream.eatSpace() && stream.peek() !== ":"))return(type, "tag");
+
+ else if(type === ")" && (stream.current() == "and" || stream.current() == "and "))return ret("variable", "variable");
+ else if(type === ")" && (stream.current() == "when" || stream.current() == "when "))return ret("variable", "variable");
+ else if(type === ")" || type === "comment" || type === "{")return ret("tag", "tag");
+ else if(stream.sol())return ret("tag", "tag");
+ else if((stream.eatSpace() && stream.peek() === "#") || stream.peek() === "#")return ret("tag", "tag");
+ else if(state.stack.length === 0)return ret("tag", "tag");
+ else if(type === ";" && stream.peek() !== undefined && stream.match(/^[\.|#]/g)) return ret("tag", "tag");
+
+ else if(type === ":"){stream.eatSpace();return ret(null, stream.current());}
+
+ else if(stream.current() === "and " || stream.current() === "and")return ret("variable", stream.current());
+ else if(type === ";" && state.stack[state.stack.length-1] === "{")return ret("variable", stream.current());
+
+ else if(state.stack[state.stack.length-1] === "rule")return ret(null, stream.current());
+
+ return ret("tag", stream.current());
}
- }
+ }
}
-
+
function tokenSComment(stream, state) { // SComment = Slash comment
stream.skipToEnd();
state.tokenize = tokenBase;
return ret("comment", "comment");
}
-
+
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
@@ -191,7 +259,7 @@ CodeMirror.defineMode("less", function(config) {
}
return ret("comment", "comment");
}
-
+
function tokenSGMLComment(stream, state) {
var dashes = 0, ch;
while ((ch = stream.next()) != null) {
@@ -203,7 +271,7 @@ CodeMirror.defineMode("less", function(config) {
}
return ret("comment", "comment");
}
-
+
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
@@ -216,18 +284,18 @@ CodeMirror.defineMode("less", function(config) {
return ret("string", "string");
};
}
-
+
return {
- startState: function(base) {
+ startState: function(base) {
return {tokenize: tokenBase,
baseIndent: base || 0,
stack: []};
},
-
+
token: function(stream, state) {
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
-
+
var context = state.stack[state.stack.length-1];
if (type == "hash" && context == "rule") style = "atom";
else if (style == "variable") {
@@ -237,7 +305,7 @@ CodeMirror.defineMode("less", function(config) {
/[\s,|\s\)|\s]/.test(stream.peek()) ? "tag" : type;
}
}
-
+
if (context == "rule" && /^[\{\};]$/.test(type))
state.stack.pop();
if (type == "{") {
@@ -246,21 +314,34 @@ CodeMirror.defineMode("less", function(config) {
}
else if (type == "}") state.stack.pop();
else if (type == "@media") state.stack.push("@media");
- else if (context == "{" && type != "comment") state.stack.push("rule");
+ else if (stream.current() === "font-family") state.stack[state.stack.length-1] = "font-family";
+ else if (stream.current() === "background-position") state.stack[state.stack.length-1] = "background-position";
+ else if (stream.current() === "border-color") state.stack[state.stack.length-1] = "border-color";
+ else if (context == "{" && type != "comment" && type !== "tag") state.stack.push("rule");
+ else if (stream.peek() === ":" && stream.current().match(/@|#/) === null) style = type;
+ if(type === ";" && (state.stack[state.stack.length-1] == "font-family" || state.stack[state.stack.length-1] == "background-position" || state.stack[state.stack.length-1] == "border-color"))state.stack[state.stack.length-1] = stream.current();
+ else if(type === "tag" && stream.peek() === ")" && stream.current().match(/\:/) === null){type = null; style = null;}
+ // ????
+ else if((type === "variable" && stream.peek() === ")") || (type === "variable" && stream.eatSpace() && stream.peek() === ")"))return ret(null,stream.current());
return style;
},
-
+
indent: function(state, textAfter) {
var n = state.stack.length;
if (/^\}/.test(textAfter))
- n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
+ n -= state.stack[state.stack.length-1] === "rule" ? 2 : 1;
+ else if (state.stack[state.stack.length-2] === "{")
+ n -= state.stack[state.stack.length-1] === "rule" ? 1 : 0;
return state.baseIndent + n * indentUnit;
},
-
- electricChars: "}"
+
+ electricChars: "}",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//"
};
});
CodeMirror.defineMIME("text/x-less", "less");
if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
- CodeMirror.defineMIME("text/css", "less");
\ No newline at end of file
+ CodeMirror.defineMIME("text/css", "less");
diff --git a/gulliver/js/codemirror/mode/livescript/LICENSE b/gulliver/js/codemirror/mode/livescript/LICENSE
deleted file mode 100644
index a675c4023..000000000
--- a/gulliver/js/codemirror/mode/livescript/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-The MIT License
-
-Copyright (c) 2013 Kenneth Bentley
-Modified from the CoffeeScript CodeMirror mode, Copyright (c) 2011 Jeff Pickhardt
-Modified from the Python CodeMirror mode, Copyright (c) 2010 Timothy Farrell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
diff --git a/gulliver/js/codemirror/mode/livescript/index.html b/gulliver/js/codemirror/mode/livescript/index.html
index 3054e35b0..b5944697d 100644
--- a/gulliver/js/codemirror/mode/livescript/index.html
+++ b/gulliver/js/codemirror/mode/livescript/index.html
@@ -1,17 +1,31 @@
-
-
- CodeMirror: LiveScript mode
-
-
-
-
-
-
-
-
- CodeMirror: LiveScript mode
-
+
+CodeMirror: LiveScript mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+LiveScript mode
+
# LiveScript mode for CodeMirror
# The following script, prelude.ls, is used to
# demonstrate LiveScript mode for CodeMirror.
@@ -442,5 +456,4 @@ export prelude = out$
The LiveScript mode was written by Kenneth Bentley (license ).
-
-
+
diff --git a/gulliver/js/codemirror/mode/lua/index.html b/gulliver/js/codemirror/mode/lua/index.html
index a0a42d91c..69433e44a 100644
--- a/gulliver/js/codemirror/mode/lua/index.html
+++ b/gulliver/js/codemirror/mode/lua/index.html
@@ -1,19 +1,32 @@
-
-
-
- CodeMirror: Lua mode
-
-
-
-
-
-
-
-
-
- CodeMirror: Lua mode
-
+
+CodeMirror: Lua mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lua mode
+
--[[
example useless code to show lua syntax highlighting
this is multiline comment
@@ -70,5 +83,4 @@ end
the lua-special style.
MIME types defined: text/x-lua.
-
-
+
diff --git a/gulliver/js/codemirror/mode/lua/lua.js b/gulliver/js/codemirror/mode/lua/lua.js
index 97fb2c6f9..b8deaa257 100644
--- a/gulliver/js/codemirror/mode/lua/lua.js
+++ b/gulliver/js/codemirror/mode/lua/lua.js
@@ -1,7 +1,7 @@
// LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's
// CodeMirror 1 mode.
// highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting
-
+
CodeMirror.defineMode("lua", function(config, parserConfig) {
var indentUnit = config.indentUnit;
@@ -12,7 +12,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
return new RegExp("^(?:" + words.join("|") + ")$", "i");
}
var specials = wordRE(parserConfig.specials || []);
-
+
// long list of standard functions from lua manual
var builtins = wordRE([
"_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load",
@@ -47,8 +47,8 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
"table.concat","table.insert","table.maxn","table.remove","table.sort"
]);
var keywords = wordRE(["and","break","elseif","false","nil","not","or","return",
- "true","function", "end", "if", "then", "else", "do",
- "while", "repeat", "until", "for", "in", "local" ]);
+ "true","function", "end", "if", "then", "else", "do",
+ "while", "repeat", "until", "for", "in", "local" ]);
var indentTokens = wordRE(["function", "if","repeat","do", "\\(", "{"]);
var dedentTokens = wordRE(["end", "until", "\\)", "}"]);
@@ -68,7 +68,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state);
stream.skipToEnd();
return "comment";
- }
+ }
if (ch == "\"" || ch == "'")
return (state.cur = string(ch))(stream, state);
if (ch == "[" && /[\[=]/.test(stream.peek()))
@@ -108,7 +108,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
return "string";
};
}
-
+
return {
startState: function(basecol) {
return {basecol: basecol || 0, indentDepth: 0, cur: normal};
@@ -121,7 +121,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
if (style == "variable") {
if (keywords.test(word)) style = "keyword";
else if (builtins.test(word)) style = "builtin";
- else if (specials.test(word)) style = "variable-2";
+ else if (specials.test(word)) style = "variable-2";
}
if ((style != "comment") && (style != "string")){
if (indentTokens.test(word)) ++state.indentDepth;
@@ -133,7 +133,11 @@ CodeMirror.defineMode("lua", function(config, parserConfig) {
indent: function(state, textAfter) {
var closing = dedentPartial.test(textAfter);
return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0));
- }
+ },
+
+ lineComment: "--",
+ blockCommentStart: "--[[",
+ blockCommentEnd: "]]"
};
});
diff --git a/gulliver/js/codemirror/mode/markdown/index.html b/gulliver/js/codemirror/mode/markdown/index.html
index 6f97b10e7..a6b541e2e 100644
--- a/gulliver/js/codemirror/mode/markdown/index.html
+++ b/gulliver/js/codemirror/mode/markdown/index.html
@@ -1,20 +1,36 @@
-
-
-
- CodeMirror: Markdown mode
-
-
-
-
-
-
-
-
-
- CodeMirror: Markdown mode
-
+CodeMirror: Markdown mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Markdown mode
Markdown: Basics
================
@@ -340,5 +356,4 @@ Output:
Parsing/Highlighting Tests: normal , verbose .
-
-
+
diff --git a/gulliver/js/codemirror/mode/markdown/markdown.js b/gulliver/js/codemirror/mode/markdown/markdown.js
index be4308228..da2ba93fe 100644
--- a/gulliver/js/codemirror/mode/markdown/markdown.js
+++ b/gulliver/js/codemirror/mode/markdown/markdown.js
@@ -1,7 +1,7 @@
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
- var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
- var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
+ var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
+ var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
var aliases = {
html: "htmlmixed",
js: "javascript",
@@ -36,33 +36,43 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (aliases[a] in modes || aliases[a] in mimes)
modes[a] = aliases[a];
}
-
+
return function (lang) {
return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
};
}());
-
+
+ // Should characters that affect highlighting be highlighted separate?
+ // Does not include characters that will be output (such as `1.` and `-` for lists)
+ if (modeCfg.highlightFormatting === undefined)
+ modeCfg.highlightFormatting = false;
+
+ // Maximum number of nested blockquotes. Set to 0 for infinite nesting.
+ // Excess `>` will emit `error` token.
+ if (modeCfg.maxBlockquoteDepth === undefined)
+ modeCfg.maxBlockquoteDepth = 0;
+
// Should underscores in words open/close em/strong?
if (modeCfg.underscoresBreakWords === undefined)
modeCfg.underscoresBreakWords = true;
-
+
// Turn on fenced code blocks? ("```" to start/end)
if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
-
+
// Turn on task lists? ("- [ ] " and "- [x] ")
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
-
+
var codeDepth = 0;
var header = 'header'
, code = 'comment'
- , quote1 = 'atom'
- , quote2 = 'number'
+ , quote = 'quote'
, list1 = 'variable-2'
, list2 = 'variable-3'
, list3 = 'keyword'
, hr = 'hr'
, image = 'tag'
+ , formatting = 'formatting'
, linkinline = 'link'
, linkemail = 'link'
, linktext = 'link'
@@ -74,8 +84,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+\.\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
- , headerRE = /^(?:\={1,}|-{1,})$/
- , textRE = /^[^!\[\]*_\\<>` "'(]+/;
+ , atxHeaderRE = /^#+/
+ , setextHeaderRE = /^(?:\={1,}|-{1,})$/
+ , textRE = /^[^#!\[\]*_\\<>` "'(]+/;
function switchInline(stream, state, f) {
state.f = state.inline = f;
@@ -103,13 +114,18 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.f = inlineNormal;
state.block = blockNormal;
}
+ // Reset state.trailingSpace
+ state.trailingSpace = 0;
+ state.trailingSpaceNewLine = false;
// Mark this line as blank
state.thisLineHasContent = false;
return null;
}
function blockNormal(stream, state) {
-
+
+ var sol = stream.sol();
+
var prevLineIsList = (state.list !== false);
if (state.list !== false && state.indentationDiff >= 0) { // Continued list
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
@@ -123,55 +139,71 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.list = false;
state.listDepth = 0;
}
-
+
+ var match = null;
if (state.indentationDiff >= 4) {
state.indentation -= 4;
stream.skipToEnd();
return code;
} else if (stream.eatSpace()) {
return null;
- } else if (stream.peek() === '#' || (state.prevLineHasContent && stream.match(headerRE)) ) {
- state.header = true;
+ } else if (match = stream.match(atxHeaderRE)) {
+ state.header = match[0].length <= 6 ? match[0].length : 6;
+ if (modeCfg.highlightFormatting) state.formatting = "header";
+ state.f = state.inline;
+ return getType(state);
+ } else if (state.prevLineHasContent && (match = stream.match(setextHeaderRE))) {
+ state.header = match[0].charAt(0) == '=' ? 1 : 2;
+ if (modeCfg.highlightFormatting) state.formatting = "header";
+ state.f = state.inline;
+ return getType(state);
} else if (stream.eat('>')) {
state.indentation++;
- state.quote = 1;
+ state.quote = sol ? 1 : state.quote + 1;
+ if (modeCfg.highlightFormatting) state.formatting = "quote";
stream.eatSpace();
- while (stream.eat('>')) {
- stream.eatSpace();
- state.quote++;
- }
+ return getType(state);
} else if (stream.peek() === '[') {
return switchInline(stream, state, footnoteLink);
} else if (stream.match(hrRE, true)) {
return hr;
- } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) {
+ } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {
+ var listType = null;
+ if (stream.match(ulRE, true)) {
+ listType = 'ul';
+ } else {
+ stream.match(olRE, true);
+ listType = 'ol';
+ }
state.indentation += 4;
state.list = true;
state.listDepth++;
if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true;
}
+ state.f = state.inline;
+ if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
+ return getType(state);
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
// try switching mode
state.localMode = getMode(RegExp.$1);
if (state.localMode) state.localState = state.localMode.startState();
switchBlock(stream, state, local);
- return code;
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
+ state.code = true;
+ return getType(state);
}
-
+
return switchInline(stream, state, state.inline);
}
function htmlBlock(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
- if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
+ if ((htmlFound && !state.htmlState.tagName && !state.htmlState.context) ||
+ (state.md_inside && stream.current().indexOf(">") > -1)) {
state.f = inlineNormal;
state.block = blockNormal;
- }
- if (state.md_inside && stream.current().indexOf(">")!=-1) {
- state.f = inlineNormal;
- state.block = blockNormal;
- state.htmlState.context = undefined;
+ state.htmlState = null;
}
return style;
}
@@ -181,7 +213,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.localMode = state.localState = null;
state.f = inlineNormal;
state.block = blockNormal;
- return code;
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
+ state.code = true;
+ var returnType = getType(state);
+ state.code = false;
+ return returnType;
} else if (state.localMode) {
return state.localMode.token(stream, state.localState);
} else {
@@ -193,19 +229,65 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
// Inline
function getType(state) {
var styles = [];
-
- if (state.taskOpen) { return "meta"; }
- if (state.taskClosed) { return "property"; }
-
+
+ if (state.formatting) {
+ styles.push(formatting);
+
+ if (typeof state.formatting === "string") state.formatting = [state.formatting];
+
+ for (var i = 0; i < state.formatting.length; i++) {
+ styles.push(formatting + "-" + state.formatting[i]);
+
+ if (state.formatting[i] === "header") {
+ styles.push(formatting + "-" + state.formatting[i] + state.header);
+ }
+
+ // Add `formatting-quote` and `formatting-quote-#` for blockquotes
+ // Add `error` instead if the maximum blockquote nesting depth is passed
+ if (state.formatting[i] === "quote") {
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
+ styles.push(formatting + "-" + state.formatting[i] + "-" + state.quote);
+ } else {
+ styles.push("error");
+ }
+ }
+ }
+ }
+
+ if (state.taskOpen) {
+ styles.push("meta");
+ return styles.length ? styles.join(' ') : null;
+ }
+ if (state.taskClosed) {
+ styles.push("property");
+ return styles.length ? styles.join(' ') : null;
+ }
+
+ if (state.linkHref) {
+ styles.push(linkhref);
+ return styles.length ? styles.join(' ') : null;
+ }
+
if (state.strong) { styles.push(strong); }
if (state.em) { styles.push(em); }
-
+
if (state.linkText) { styles.push(linktext); }
-
+
if (state.code) { styles.push(code); }
-
- if (state.header) { styles.push(header); }
- if (state.quote) { styles.push(state.quote % 2 ? quote1 : quote2); }
+
+ if (state.header) { styles.push(header); styles.push(header + state.header); }
+
+ if (state.quote) {
+ styles.push(quote);
+
+ // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
+ styles.push(quote + "-" + state.quote);
+ } else {
+ styles.push(quote + "-" + modeCfg.maxBlockquoteDepth);
+ }
+ }
+
if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3;
if (!listMod) {
@@ -217,6 +299,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}
+ if (state.trailingSpaceNewLine) {
+ styles.push("trailing-space-new-line");
+ } else if (state.trailingSpace) {
+ styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
+ }
+
return styles.length ? styles.join(' ') : null;
}
@@ -224,37 +312,52 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (stream.match(textRE, true)) {
return getType(state);
}
- return undefined;
+ return undefined;
}
function inlineNormal(stream, state) {
var style = state.text(stream, state);
if (typeof style !== 'undefined')
return style;
-
+
if (state.list) { // List marker (*, +, -, 1., etc)
state.list = null;
return getType(state);
}
-
+
if (state.taskList) {
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
if (taskOpen) state.taskOpen = true;
else state.taskClosed = true;
+ if (modeCfg.highlightFormatting) state.formatting = "task";
state.taskList = false;
return getType(state);
}
-
+
state.taskOpen = false;
state.taskClosed = false;
-
- var ch = stream.next();
-
- if (ch === '\\') {
- stream.next();
+
+ if (state.header && stream.match(/^#+$/, true)) {
+ if (modeCfg.highlightFormatting) state.formatting = "header";
return getType(state);
}
-
+
+ // Get sol() value now, before character is consumed
+ var sol = stream.sol();
+
+ var ch = stream.next();
+
+ if (state.escape) {
+ state.escape = false;
+ return getType(state);
+ }
+
+ if (ch === '\\') {
+ if (modeCfg.highlightFormatting) state.formatting = "escape";
+ state.escape = true;
+ return getType(state);
+ }
+
// Matches link titles present on next line
if (state.linkTitle) {
state.linkTitle = false;
@@ -268,9 +371,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return linkhref;
}
}
-
+
// If this block is changed, it may need to be updated in GFM mode
if (ch === '`') {
+ var previousFormatting = state.formatting;
+ if (modeCfg.highlightFormatting) state.formatting = "code";
var t = getType(state);
var before = stream.pos;
stream.eatWhile('`');
@@ -284,12 +389,13 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.code = false;
return t;
}
+ state.formatting = previousFormatting;
return getType(state);
}
} else if (state.code) {
return getType(state);
}
-
+
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
stream.match(/\[[^\]]*\]/);
state.inline = state.f = linkHref;
@@ -298,40 +404,59 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
state.linkText = true;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
return getType(state);
}
if (ch === ']' && state.linkText) {
+ if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
state.linkText = false;
state.inline = state.f = linkHref;
return type;
}
-
- if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) {
- return switchInline(stream, state, inlineElement(linkinline, '>'));
+
+ if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
+ state.f = state.inline = linkInline;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkinline;
}
-
- if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) {
- return switchInline(stream, state, inlineElement(linkemail, '>'));
+
+ if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
+ state.f = state.inline = linkInline;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkemail;
}
-
+
if (ch === '<' && stream.match(/^\w/, false)) {
- if (stream.string.indexOf(">")!=-1) {
+ if (stream.string.indexOf(">") != -1) {
var atts = stream.string.substring(1,stream.string.indexOf(">"));
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
state.md_inside = true;
}
}
stream.backUp(1);
+ state.htmlState = CodeMirror.startState(htmlMode);
return switchBlock(stream, state, htmlBlock);
}
-
+
if (ch === '<' && stream.match(/^\/\w*?>/)) {
state.md_inside = false;
return "tag";
}
-
+
var ignoreUnderscore = false;
if (!modeCfg.underscoresBreakWords) {
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
@@ -344,19 +469,26 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}
}
- var t = getType(state);
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
- if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
+ if (sol && stream.peek() === ' ') {
+ // Do nothing, surrounded by newline and space
+ } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
+ if (modeCfg.highlightFormatting) state.formatting = "strong";
+ var t = getType(state);
state.strong = false;
return t;
} else if (!state.strong && stream.eat(ch)) { // Add STRONG
state.strong = ch;
+ if (modeCfg.highlightFormatting) state.formatting = "strong";
return getType(state);
} else if (state.em === ch) { // Remove EM
+ if (modeCfg.highlightFormatting) state.formatting = "em";
+ var t = getType(state);
state.em = false;
return t;
} else if (!state.em) { // Add EM
state.em = ch;
+ if (modeCfg.highlightFormatting) state.formatting = "em";
return getType(state);
}
} else if (ch === ' ') {
@@ -368,10 +500,38 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
}
}
-
+
+ if (ch === ' ') {
+ if (stream.match(/ +$/, false)) {
+ state.trailingSpace++;
+ } else if (state.trailingSpace) {
+ state.trailingSpaceNewLine = true;
+ }
+ }
+
return getType(state);
}
+ function linkInline(stream, state) {
+ var ch = stream.next();
+
+ if (ch === ">") {
+ state.f = state.inline = inlineNormal;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkinline;
+ }
+
+ stream.match(/^[^>]+/, true);
+
+ return linkinline;
+ }
+
function linkHref(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
@@ -379,19 +539,60 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
var ch = stream.next();
if (ch === '(' || ch === '[') {
- return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
+ state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
+ state.linkHref = true;
+ return getType(state);
}
return 'error';
}
+ function getLinkHrefInside(endChar) {
+ return function(stream, state) {
+ var ch = stream.next();
+
+ if (ch === endChar) {
+ state.f = state.inline = inlineNormal;
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
+ var returnState = getType(state);
+ state.linkHref = false;
+ return returnState;
+ }
+
+ if (stream.match(inlineRE(endChar), true)) {
+ stream.backUp(1);
+ }
+
+ state.linkHref = true;
+ return getType(state);
+ };
+ }
+
function footnoteLink(stream, state) {
- if (stream.match(/^[^\]]*\]:/, true)) {
- state.f = footnoteUrl;
- return linktext;
+ if (stream.match(/^[^\]]*\]:/, false)) {
+ state.f = footnoteLinkInside;
+ stream.next(); // Consume [
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ state.linkText = true;
+ return getType(state);
}
return switchInline(stream, state, inlineNormal);
}
+ function footnoteLinkInside(stream, state) {
+ if (stream.match(/^\]:/, true)) {
+ state.f = state.inline = footnoteUrl;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var returnType = getType(state);
+ state.linkText = false;
+ return returnType;
+ }
+
+ stream.match(/^[^\]]+/, true);
+
+ return linktext;
+ }
+
function footnoteUrl(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
@@ -414,65 +615,63 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
if (!savedInlineRE[endChar]) {
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
- // Match any non-endChar, escaped character, as well as the closing
+ // Match any non-endChar, escaped character, as well as the closing
// endChar.
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
}
return savedInlineRE[endChar];
}
- function inlineElement(type, endChar, next) {
- next = next || inlineNormal;
- return function(stream, state) {
- stream.match(inlineRE(endChar));
- state.inline = state.f = next;
- return type;
- };
- }
-
- return {
+ var mode = {
startState: function() {
return {
f: blockNormal,
-
+
prevLineHasContent: false,
thisLineHasContent: false,
-
+
block: blockNormal,
- htmlState: CodeMirror.startState(htmlMode),
+ htmlState: null,
indentation: 0,
-
+
inline: inlineNormal,
text: handleText,
-
+
+ escape: false,
+ formatting: false,
linkText: false,
+ linkHref: false,
linkTitle: false,
em: false,
strong: false,
- header: false,
+ header: 0,
taskList: false,
list: false,
listDepth: 0,
- quote: 0
+ quote: 0,
+ trailingSpace: 0,
+ trailingSpaceNewLine: false
};
},
copyState: function(s) {
return {
f: s.f,
-
+
prevLineHasContent: s.prevLineHasContent,
thisLineHasContent: s.thisLineHasContent,
-
+
block: s.block,
- htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
+ htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
indentation: s.indentation,
-
+
localMode: s.localMode,
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
-
+
inline: s.inline,
text: s.text,
+ escape: false,
+ formatting: false,
linkTitle: s.linkTitle,
em: s.em,
strong: s.strong,
@@ -481,13 +680,24 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
list: s.list,
listDepth: s.listDepth,
quote: s.quote,
+ trailingSpace: s.trailingSpace,
+ trailingSpaceNewLine: s.trailingSpaceNewLine,
md_inside: s.md_inside
};
},
token: function(stream, state) {
+
+ // Reset state.formatting
+ state.formatting = false;
+
if (stream.sol()) {
- if (stream.match(/^\s*$/, true)) {
+ var forceBlankLine = stream.match(/^\s*$/, true) || state.header;
+
+ // Reset state.header
+ state.header = 0;
+
+ if (forceBlankLine) {
state.prevLineHasContent = false;
return blankLine(state);
} else {
@@ -495,15 +705,19 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.thisLineHasContent = true;
}
- // Reset state.header
- state.header = false;
-
+ // Reset state.escape
+ state.escape = false;
+
// Reset state.taskList
state.taskList = false;
-
+
// Reset state.code
state.code = false;
+ // Reset state.trailingSpace
+ state.trailingSpace = 0;
+ state.trailingSpaceNewLine = false;
+
state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4;
@@ -516,11 +730,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return state.f(stream, state);
},
+ innerMode: function(state) {
+ if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
+ if (state.localState) return {state: state.localState, mode: state.localMode};
+ return {state: state, mode: mode};
+ },
+
blankLine: blankLine,
getType: getType
};
-
+ return mode;
}, "xml");
CodeMirror.defineMIME("text/x-markdown", "markdown");
diff --git a/gulliver/js/codemirror/mode/markdown/test.js b/gulliver/js/codemirror/mode/markdown/test.js
index cfc229bc3..30e82ca65 100644
--- a/gulliver/js/codemirror/mode/markdown/test.js
+++ b/gulliver/js/codemirror/mode/markdown/test.js
@@ -1,10 +1,75 @@
(function() {
var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+ var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
+ function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
+
+ FT("formatting_emAsterisk",
+ "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
+
+ FT("formatting_emUnderscore",
+ "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
+
+ FT("formatting_strongAsterisk",
+ "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
+
+ FT("formatting_strongUnderscore",
+ "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
+
+ FT("formatting_codeBackticks",
+ "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
+
+ FT("formatting_doubleBackticks",
+ "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
+
+ FT("formatting_atxHeader",
+ "[header&header1&formatting&formatting-header&formatting-header1 #][header&header1 foo # bar ][header&header1&formatting&formatting-header&formatting-header1 #]");
+
+ FT("formatting_setextHeader",
+ "foo",
+ "[header&header1&formatting&formatting-header&formatting-header1 =]");
+
+ FT("formatting_blockquote",
+ "[quote"e-1&formatting&formatting-quote&formatting-quote-1 > ][quote"e-1 foo]");
+
+ FT("formatting_list",
+ "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
+ FT("formatting_list",
+ "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
+
+ FT("formatting_link",
+ "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string (][string http://example.com/][string&formatting&formatting-link-string )]");
+
+ FT("formatting_linkReference",
+ "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string [][string bar][string&formatting&formatting-link-string ]]]",
+ "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string http://example.com/]");
+
+ FT("formatting_linkWeb",
+ "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
+
+ FT("formatting_linkEmail",
+ "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
+
+ FT("formatting_escape",
+ "[formatting&formatting-escape \\]*");
MT("plainText",
"foo");
+ // Don't style single trailing space
+ MT("trailingSpace1",
+ "foo ");
+
+ // Two or more trailing spaces should be styled with line break character
+ MT("trailingSpace2",
+ "foo[trailing-space-a ][trailing-space-new-line ]");
+
+ MT("trailingSpace3",
+ "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]");
+
+ MT("trailingSpace4",
+ "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]");
+
// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
MT("codeBlocksUsing4Spaces",
" [comment foo]");
@@ -39,20 +104,20 @@
"[comment `]");
// Unclosed backticks
- // Instead of simply marking as CODE, it would be nice to have an
+ // Instead of simply marking as CODE, it would be nice to have an
// incomplete flag for CODE, that is styled slightly different.
MT("unclosedBackticks",
"foo [comment `bar]");
- // Per documentation: "To include a literal backtick character within a
- // code span, you can use multiple backticks as the opening and closing
+ // Per documentation: "To include a literal backtick character within a
+ // code span, you can use multiple backticks as the opening and closing
// delimiters"
MT("doubleBackticks",
"[comment ``foo ` bar``]");
// Tests based on Dingus
// http://daringfireball.net/projects/markdown/dingus
- //
+ //
// Multiple backticks within an inline code block
MT("consecutiveBackticks",
"[comment `foo```bar`]");
@@ -73,101 +138,105 @@
// http://daringfireball.net/projects/markdown/syntax#header
MT("atxH1",
- "[header # foo]");
+ "[header&header1 # foo]");
MT("atxH2",
- "[header ## foo]");
+ "[header&header2 ## foo]");
MT("atxH3",
- "[header ### foo]");
+ "[header&header3 ### foo]");
MT("atxH4",
- "[header #### foo]");
+ "[header&header4 #### foo]");
MT("atxH5",
- "[header ##### foo]");
+ "[header&header5 ##### foo]");
MT("atxH6",
- "[header ###### foo]");
+ "[header&header6 ###### foo]");
// H6 - 7x '#' should still be H6, per Dingus
// http://daringfireball.net/projects/markdown/dingus
MT("atxH6NotH7",
- "[header ####### foo]");
+ "[header&header6 ####### foo]");
+
+ // Inline styles should be parsed inside headers
+ MT("atxH1inline",
+ "[header&header1 # foo ][header&header1&em *bar*]");
// Setext headers - H1, H2
// Per documentation, "Any number of underlining =’s or -’s will work."
// http://daringfireball.net/projects/markdown/syntax#header
- // Ideally, the text would be marked as `header` as well, but this is
- // not really feasible at the moment. So, instead, we're testing against
+ // Ideally, the text would be marked as `header` as well, but this is
+ // not really feasible at the moment. So, instead, we're testing against
// what works today, to avoid any regressions.
- //
+ //
// Check if single underlining = works
MT("setextH1",
"foo",
- "[header =]");
+ "[header&header1 =]");
// Check if 3+ ='s work
MT("setextH1",
"foo",
- "[header ===]");
+ "[header&header1 ===]");
// Check if single underlining - works
MT("setextH2",
"foo",
- "[header -]");
+ "[header&header2 -]");
// Check if 3+ -'s work
MT("setextH2",
"foo",
- "[header ---]");
+ "[header&header2 ---]");
// Single-line blockquote with trailing space
MT("blockquoteSpace",
- "[atom > foo]");
+ "[quote"e-1 > foo]");
// Single-line blockquote
MT("blockquoteNoSpace",
- "[atom >foo]");
+ "[quote"e-1 >foo]");
// No blank line before blockquote
MT("blockquoteNoBlankLine",
"foo",
- "[atom > bar]");
+ "[quote"e-1 > bar]");
// Nested blockquote
MT("blockquoteSpace",
- "[atom > foo]",
- "[number > > foo]",
- "[atom > > > foo]");
+ "[quote"e-1 > foo]",
+ "[quote"e-1 >][quote"e-2 > foo]",
+ "[quote"e-1 >][quote"e-2 >][quote"e-3 > foo]");
// Single-line blockquote followed by normal paragraph
MT("blockquoteThenParagraph",
- "[atom >foo]",
+ "[quote"e-1 >foo]",
"",
"bar");
// Multi-line blockquote (lazy mode)
MT("multiBlockquoteLazy",
- "[atom >foo]",
- "[atom bar]");
+ "[quote"e-1 >foo]",
+ "[quote"e-1 bar]");
// Multi-line blockquote followed by normal paragraph (lazy mode)
MT("multiBlockquoteLazyThenParagraph",
- "[atom >foo]",
- "[atom bar]",
+ "[quote"e-1 >foo]",
+ "[quote"e-1 bar]",
"",
"hello");
// Multi-line blockquote (non-lazy mode)
MT("multiBlockquote",
- "[atom >foo]",
- "[atom >bar]");
+ "[quote"e-1 >foo]",
+ "[quote"e-1 >bar]");
// Multi-line blockquote followed by normal paragraph (non-lazy mode)
MT("multiBlockquoteThenParagraph",
- "[atom >foo]",
- "[atom >bar]",
+ "[quote"e-1 >foo]",
+ "[quote"e-1 >bar]",
"",
"hello");
@@ -207,6 +276,11 @@
"1. bar",
"2. hello");
+ // List after header
+ MT("listAfterHeader",
+ "[header&header1 # foo]",
+ "[variable-2 - bar]");
+
// Formatting in lists (*)
MT("listAsteriskFormatting",
"[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
@@ -292,7 +366,7 @@
"",
"[variable-2 * bar]",
"",
- " [variable-2&atom > hello]");
+ " [variable-2"e"e-1 > hello]");
// Code block
MT("blockquoteCode",
@@ -350,7 +424,7 @@
"",
" [variable-3 + bar]",
"",
- " [atom&variable-3 > hello]");
+ " [quote"e-1&variable-3 > hello]");
MT("listCode",
"[variable-2 * foo]",
@@ -368,7 +442,7 @@
" [comment world]",
" [comment foo]",
" [variable-2 bar]");
-
+
// List nesting edge cases
MT("listNested",
"[variable-2 * foo]",
@@ -533,9 +607,15 @@
MT("linkWeb",
"[link ] foo");
+ MT("linkWebDouble",
+ "[link ] foo [link ]");
+
MT("linkEmail",
"[link ] foo");
+ MT("linkEmailDouble",
+ "[link ] foo [link ]");
+
MT("emAsterisk",
"[em *foo*] bar");
@@ -548,7 +628,7 @@
MT("emInWordUnderscore",
"foo[em _bar_]hello");
- // Per documentation: "...surround an * or _ with spaces, it’ll be
+ // Per documentation: "...surround an * or _ with spaces, it’ll be
// treated as a literal asterisk or underscore."
MT("emEscapedBySpaceIn",
@@ -557,8 +637,12 @@
MT("emEscapedBySpaceOut",
"foo _ bar[em _hello_]world");
+ MT("emEscapedByNewline",
+ "foo",
+ "_ bar[em _hello_]world");
+
// Unclosed emphasis characters
- // Instead of simply marking as EM / STRONG, it would be nice to have an
+ // Instead of simply marking as EM / STRONG, it would be nice to have an
// incomplete flag for EM and STRONG, that is styled slightly different.
MT("emIncompleteAsterisk",
"foo [em *bar]");
@@ -623,9 +707,13 @@
MT("doubleEscapeHash",
"\\\\# foo");
+ MT("escapeNewline",
+ "\\",
+ "[em *foo*]");
+
// Tests to make sure GFM-specific things aren't getting through
-
+
MT("taskList",
"[variable-2 * [ ]] bar]");
diff --git a/gulliver/js/codemirror/mode/meta.js b/gulliver/js/codemirror/mode/meta.js
index e01ea30d4..f37cea55b 100644
--- a/gulliver/js/codemirror/mode/meta.js
+++ b/gulliver/js/codemirror/mode/meta.js
@@ -3,6 +3,7 @@ CodeMirror.modeInfo = [
{name: 'Asterisk', mime: 'text/x-asterisk', mode: 'asterisk'},
{name: 'C', mime: 'text/x-csrc', mode: 'clike'},
{name: 'C++', mime: 'text/x-c++src', mode: 'clike'},
+ {name: 'Cobol', mime: 'text/x-cobol', mode: 'cobol'},
{name: 'Java', mime: 'text/x-java', mode: 'clike'},
{name: 'C#', mime: 'text/x-csharp', mode: 'clike'},
{name: 'Scala', mime: 'text/x-scala', mode: 'clike'},
@@ -12,11 +13,18 @@ CodeMirror.modeInfo = [
{name: 'CSS', mime: 'text/css', mode: 'css'},
{name: 'D', mime: 'text/x-d', mode: 'd'},
{name: 'diff', mime: 'text/x-diff', mode: 'diff'},
+ {name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'},
{name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'},
+ {name: 'Eiffel', mime: 'text/x-eiffel', mode: 'eiffel'},
{name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'},
- {name: 'GitHub Flavored Markdown', mode: 'gfm'},
- {name: 'GO', mime: 'text/x-go', mode: 'go'},
+ {name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'},
+ {name: 'F#', mime: 'text/x-fsharp', mode: 'mllike'},
+ {name: 'Gas', mime: 'text/x-gas', mode: 'gas'},
+ {name: 'Gherkin', mime: 'text/x-feature', mode: 'gherkin'},
+ {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'},
+ {name: 'Go', mime: 'text/x-go', mode: 'go'},
{name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'},
+ {name: 'HAML', mime: 'text/x-haml', mode: 'haml'},
{name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'},
{name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'},
{name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'},
@@ -24,25 +32,32 @@ CodeMirror.modeInfo = [
{name: 'JavaServer Pages', mime: 'application/x-jsp', mode: 'htmlembedded'},
{name: 'HTML', mime: 'text/html', mode: 'htmlmixed'},
{name: 'HTTP', mime: 'message/http', mode: 'http'},
+ {name: 'Jade', mime: 'text/x-jade', mode: 'jade'},
{name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'},
+ {name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
{name: 'JSON', mime: 'application/json', mode: 'javascript'},
{name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
- {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'},
+ {name: 'Jinja2', mime: null, mode: 'jinja2'},
+ {name: 'Julia', mime: 'text/x-julia', mode: 'julia'},
{name: 'LESS', mime: 'text/x-less', mode: 'less'},
{name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'},
{name: 'Lua', mime: 'text/x-lua', mode: 'lua'},
{name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'},
{name: 'mIRC', mime: 'text/mirc', mode: 'mirc'},
+ {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'},
{name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'},
- {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'},
+ {name: 'OCaml', mime: 'text/x-ocaml', mode: 'mllike'},
+ {name: 'Octave', mime: 'text/x-octave', mode: 'octave'},
{name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'},
+ {name: 'PEG.js', mime: null, mode: 'pegjs'},
{name: 'Perl', mime: 'text/x-perl', mode: 'perl'},
{name: 'PHP', mime: 'text/x-php', mode: 'php'},
{name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'},
{name: 'Pig', mime: 'text/x-pig', mode: 'pig'},
{name: 'Plain Text', mime: 'text/plain', mode: 'null'},
- {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'},
+ {name: 'Properties files', mime: 'text/x-properties', mode: 'properties'},
{name: 'Python', mime: 'text/x-python', mode: 'python'},
+ {name: 'Cython', mime: 'text/x-cython', mode: 'python'},
{name: 'R', mime: 'text/x-rsrc', mode: 'r'},
{name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'},
{name: 'Ruby', mime: 'text/x-ruby', mode: 'ruby'},
@@ -54,6 +69,7 @@ CodeMirror.modeInfo = [
{name: 'Sieve', mime: 'application/sieve', mode: 'sieve'},
{name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'},
{name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'},
+ {name: 'SmartyMixed', mime: 'text/x-smarty', mode: 'smartymixed'},
{name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'},
{name: 'SQL', mime: 'text/x-sql', mode: 'sql'},
{name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'},
@@ -62,6 +78,8 @@ CodeMirror.modeInfo = [
{name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'},
{name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'},
{name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'},
+ {name: 'TOML', mime: 'text/x-toml', mode: 'toml'},
+ {name: 'Turtle', mime: 'text/turtle', mode: 'turtle'},
{name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'},
{name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'},
{name: 'Velocity', mime: 'text/velocity', mode: 'velocity'},
diff --git a/gulliver/js/codemirror/mode/mirc/index.html b/gulliver/js/codemirror/mode/mirc/index.html
index 0ff5ec9a2..dbd7a06d8 100644
--- a/gulliver/js/codemirror/mode/mirc/index.html
+++ b/gulliver/js/codemirror/mode/mirc/index.html
@@ -1,18 +1,31 @@
-
-
-
- CodeMirror: mIRC mode
-
-
-
-
-
-
-
-
- CodeMirror: mIRC mode
-
+
+CodeMirror: mIRC mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+mIRC mode
+
;AKA Nick Tracker by Ford_Lawnmower irc.GeekShed.net #Script-Help
;*****************************************************************************;
;**Start Setup
@@ -145,5 +158,4 @@ Raw 315:*: {
MIME types defined: text/mirc.
-
-
+
diff --git a/gulliver/js/codemirror/mode/mirc/mirc.js b/gulliver/js/codemirror/mode/mirc/mirc.js
index f76f78276..fc88bc56f 100644
--- a/gulliver/js/codemirror/mode/mirc/mirc.js
+++ b/gulliver/js/codemirror/mode/mirc/mirc.js
@@ -8,65 +8,65 @@ CodeMirror.defineMode("mirc", function() {
}
var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " +
"$activewid $address $addtok $agent $agentname $agentstat $agentver " +
- "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " +
- "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " +
- "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " +
- "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " +
- "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " +
- "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " +
- "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " +
- "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " +
- "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " +
- "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " +
- "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " +
- "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " +
- "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " +
- "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " +
- "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " +
- "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " +
- "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " +
- "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " +
- "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " +
- "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " +
- "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " +
- "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " +
- "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " +
- "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " +
- "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " +
- "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " +
- "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " +
- "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " +
- "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " +
- "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " +
- "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " +
- "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " +
- "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " +
- "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor");
+ "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " +
+ "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " +
+ "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " +
+ "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " +
+ "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " +
+ "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " +
+ "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " +
+ "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " +
+ "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " +
+ "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " +
+ "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " +
+ "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " +
+ "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " +
+ "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " +
+ "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " +
+ "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " +
+ "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " +
+ "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " +
+ "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " +
+ "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " +
+ "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " +
+ "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " +
+ "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " +
+ "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " +
+ "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " +
+ "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " +
+ "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " +
+ "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " +
+ "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " +
+ "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " +
+ "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " +
+ "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " +
+ "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " +
+ "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor");
var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " +
"away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " +
- "channel clear clearall cline clipboard close cnick color comclose comopen " +
- "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " +
- "debug dec describe dialog did didtok disable disconnect dlevel dline dll " +
- "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " +
- "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " +
- "events exit fclose filter findtext finger firewall flash flist flood flush " +
- "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " +
- "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " +
- "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " +
- "ialmark identd if ignore iline inc invite iuser join kick linesep links list " +
- "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " +
- "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " +
- "qme qmsg query queryn quit raw reload remini remote remove rename renwin " +
- "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " +
- "say scid scon server set showmirc signam sline sockaccept sockclose socklist " +
- "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " +
- "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " +
- "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " +
- "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " +
- "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " +
- "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " +
- "elseif else goto menu nicklist status title icon size option text edit " +
- "button check radio box scroll list combo link tab item");
+ "channel clear clearall cline clipboard close cnick color comclose comopen " +
+ "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " +
+ "debug dec describe dialog did didtok disable disconnect dlevel dline dll " +
+ "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " +
+ "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " +
+ "events exit fclose filter findtext finger firewall flash flist flood flush " +
+ "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " +
+ "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " +
+ "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " +
+ "ialmark identd if ignore iline inc invite iuser join kick linesep links list " +
+ "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " +
+ "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " +
+ "qme qmsg query queryn quit raw reload remini remote remove rename renwin " +
+ "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " +
+ "say scid scon server set showmirc signam sline sockaccept sockclose socklist " +
+ "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " +
+ "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " +
+ "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " +
+ "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " +
+ "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " +
+ "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " +
+ "elseif else goto menu nicklist status title icon size option text edit " +
+ "button check radio box scroll list combo link tab item");
var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch");
var isOperatorChar = /[+\-*&%=<>!?^\/\|]/;
function chain(stream, state, f) {
diff --git a/gulliver/js/codemirror/mode/ntriples/index.html b/gulliver/js/codemirror/mode/ntriples/index.html
index 052a53d86..c8a67916d 100644
--- a/gulliver/js/codemirror/mode/ntriples/index.html
+++ b/gulliver/js/codemirror/mode/ntriples/index.html
@@ -1,20 +1,33 @@
-
-
-
- CodeMirror: NTriples mode
-
-
-
-
-
-
-
- CodeMirror: NTriples mode
+
+
+
+
+
+
+
+
+
+NTriples mode
.
@@ -29,5 +42,4 @@ _:bnode5 "literal 3"^^ .
var editor = CodeMirror.fromTextArea(document.getElementById("ntriples"), {});
MIME types defined: text/n-triples.
-
-
+
diff --git a/gulliver/js/codemirror/mode/ntriples/ntriples.js b/gulliver/js/codemirror/mode/ntriples/ntriples.js
index ced864516..ed0cee34b 100644
--- a/gulliver/js/codemirror/mode/ntriples/ntriples.js
+++ b/gulliver/js/codemirror/mode/ntriples/ntriples.js
@@ -1,22 +1,22 @@
/**********************************************************
-* This script provides syntax highlighting support for
+* This script provides syntax highlighting support for
* the Ntriples format.
-* Ntriples format specification:
+* Ntriples format specification:
* http://www.w3.org/TR/rdf-testcases/#ntriples
***********************************************************/
-/*
+/*
The following expression defines the defined ASF grammar transitions.
pre_subject ->
{
( writing_subject_uri | writing_bnode_uri )
- -> pre_predicate
- -> writing_predicate_uri
- -> pre_object
- -> writing_object_uri | writing_object_bnode |
- (
- writing_object_literal
+ -> pre_predicate
+ -> writing_predicate_uri
+ -> pre_object
+ -> writing_object_uri | writing_object_bnode |
+ (
+ writing_object_literal
-> writing_literal_lang | writing_literal_type
)
-> post_object
@@ -25,7 +25,7 @@
-> ERROR
}
*/
-CodeMirror.defineMode("ntriples", function() {
+CodeMirror.defineMode("ntriples", function() {
var Location = {
PRE_SUBJECT : 0,
@@ -45,7 +45,7 @@ CodeMirror.defineMode("ntriples", function() {
function transitState(currState, c) {
var currLocation = currState.location;
var ret;
-
+
// Opening.
if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI;
else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI;
@@ -53,7 +53,7 @@ CodeMirror.defineMode("ntriples", function() {
else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI;
else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE;
else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL;
-
+
// Closing.
else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED;
else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED;
@@ -63,33 +63,33 @@ CodeMirror.defineMode("ntriples", function() {
else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ;
else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ;
else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ;
-
+
// Closing typed and language literal.
else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG;
else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE;
// Spaces.
- else if( c == ' ' &&
+ else if( c == ' ' &&
(
- currLocation == Location.PRE_SUBJECT ||
- currLocation == Location.PRE_PRED ||
- currLocation == Location.PRE_OBJ ||
+ currLocation == Location.PRE_SUBJECT ||
+ currLocation == Location.PRE_PRED ||
+ currLocation == Location.PRE_OBJ ||
currLocation == Location.POST_OBJ
)
) ret = currLocation;
-
+
// Reset.
- else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;
-
+ else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;
+
// Error
else ret = Location.ERROR;
-
+
currState.location=ret;
}
return {
startState: function() {
- return {
+ return {
location : Location.PRE_SUBJECT,
uris : [],
anchors : [],
diff --git a/gulliver/js/codemirror/mode/ocaml/index.html b/gulliver/js/codemirror/mode/ocaml/index.html
deleted file mode 100644
index c10a84fad..000000000
--- a/gulliver/js/codemirror/mode/ocaml/index.html
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
-CodeMirror: OCaml mode
-
-
-
-
-
-
-
-
-
-
-CodeMirror: OCaml mode
-
-
-(* Summing a list of integers *)
-let rec sum xs =
- match xs with
- | [] -> 0
- | x :: xs' -> x + sum xs'
-
-(* Quicksort *)
-let rec qsort = function
- | [] -> []
- | pivot :: rest ->
- let is_less x = x < pivot in
- let left, right = List.partition is_less rest in
- qsort left @ [pivot] @ qsort right
-
-(* Fibonacci Sequence *)
-let rec fib_aux n a b =
- match n with
- | 0 -> a
- | _ -> fib_aux (n - 1) (a + b) a
-let fib n = fib_aux n 0 1
-
-(* Birthday paradox *)
-let year_size = 365.
-
-let rec birthday_paradox prob people =
- let prob' = (year_size -. float people) /. year_size *. prob in
- if prob' < 0.5 then
- Printf.printf "answer = %d\n" (people+1)
- else
- birthday_paradox prob' (people+1) ;;
-
-birthday_paradox 1.0 1
-
-(* Church numerals *)
-let zero f x = x
-let succ n f x = f (n f x)
-let one = succ zero
-let two = succ (succ zero)
-let add n1 n2 f x = n1 f (n2 f x)
-let to_string n = n (fun k -> "S" ^ k) "0"
-let _ = to_string (add (succ two) two)
-
-(* Elementary functions *)
-let square x = x * x;;
-let rec fact x =
- if x <= 1 then 1 else x * fact (x - 1);;
-
-(* Automatic memory management *)
-let l = 1 :: 2 :: 3 :: [];;
-[1; 2; 3];;
-5 :: l;;
-
-(* Polymorphism: sorting lists *)
-let rec sort = function
- | [] -> []
- | x :: l -> insert x (sort l)
-
-and insert elem = function
- | [] -> [elem]
- | x :: l ->
- if elem < x then elem :: x :: l else x :: insert elem l;;
-
-(* Imperative features *)
-let add_polynom p1 p2 =
- let n1 = Array.length p1
- and n2 = Array.length p2 in
- let result = Array.create (max n1 n2) 0 in
- for i = 0 to n1 - 1 do result.(i) <- p1.(i) done;
- for i = 0 to n2 - 1 do result.(i) <- result.(i) + p2.(i) done;
- result;;
-add_polynom [| 1; 2 |] [| 1; 2; 3 |];;
-
-(* We may redefine fact using a reference cell and a for loop *)
-let fact n =
- let result = ref 1 in
- for i = 2 to n do
- result := i * !result
- done;
- !result;;
-fact 5;;
-
-(* Triangle (graphics) *)
-let () =
- ignore( Glut.init Sys.argv );
- Glut.initDisplayMode ~double_buffer:true ();
- ignore (Glut.createWindow ~title:"OpenGL Demo");
- let angle t = 10. *. t *. t in
- let render () =
- GlClear.clear [ `color ];
- GlMat.load_identity ();
- GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();
- GlDraw.begins `triangles;
- List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];
- GlDraw.ends ();
- Glut.swapBuffers () in
- GlMat.mode `modelview;
- Glut.displayFunc ~cb:render;
- Glut.idleFunc ~cb:(Some Glut.postRedisplay);
- Glut.mainLoop ()
-
-(* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *)
-(* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *)
-
-
-
-
-MIME types defined: text/x-ocaml.
diff --git a/gulliver/js/codemirror/mode/ocaml/ocaml.js b/gulliver/js/codemirror/mode/ocaml/ocaml.js
deleted file mode 100644
index 2ce3fb8f0..000000000
--- a/gulliver/js/codemirror/mode/ocaml/ocaml.js
+++ /dev/null
@@ -1,113 +0,0 @@
-CodeMirror.defineMode('ocaml', function() {
-
- var words = {
- 'true': 'atom',
- 'false': 'atom',
- 'let': 'keyword',
- 'rec': 'keyword',
- 'in': 'keyword',
- 'of': 'keyword',
- 'and': 'keyword',
- 'succ': 'keyword',
- 'if': 'keyword',
- 'then': 'keyword',
- 'else': 'keyword',
- 'for': 'keyword',
- 'to': 'keyword',
- 'while': 'keyword',
- 'do': 'keyword',
- 'done': 'keyword',
- 'fun': 'keyword',
- 'function': 'keyword',
- 'val': 'keyword',
- 'type': 'keyword',
- 'mutable': 'keyword',
- 'match': 'keyword',
- 'with': 'keyword',
- 'try': 'keyword',
- 'raise': 'keyword',
- 'begin': 'keyword',
- 'end': 'keyword',
- 'open': 'builtin',
- 'trace': 'builtin',
- 'ignore': 'builtin',
- 'exit': 'builtin',
- 'print_string': 'builtin',
- 'print_endline': 'builtin'
- };
-
- function tokenBase(stream, state) {
- var ch = stream.next();
-
- if (ch === '"') {
- state.tokenize = tokenString;
- return state.tokenize(stream, state);
- }
- if (ch === '(') {
- if (stream.eat('*')) {
- state.commentLevel++;
- state.tokenize = tokenComment;
- return state.tokenize(stream, state);
- }
- }
- if (ch === '~') {
- stream.eatWhile(/\w/);
- return 'variable-2';
- }
- if (ch === '`') {
- stream.eatWhile(/\w/);
- return 'quote';
- }
- if (/\d/.test(ch)) {
- stream.eatWhile(/[\d]/);
- if (stream.eat('.')) {
- stream.eatWhile(/[\d]/);
- }
- return 'number';
- }
- if ( /[+\-*&%=<>!?|]/.test(ch)) {
- return 'operator';
- }
- stream.eatWhile(/\w/);
- var cur = stream.current();
- return words[cur] || 'variable';
- }
-
- function tokenString(stream, state) {
- var next, end = false, escaped = false;
- while ((next = stream.next()) != null) {
- if (next === '"' && !escaped) {
- end = true;
- break;
- }
- escaped = !escaped && next === '\\';
- }
- if (end && !escaped) {
- state.tokenize = tokenBase;
- }
- return 'string';
- };
-
- function tokenComment(stream, state) {
- var prev, next;
- while(state.commentLevel > 0 && (next = stream.next()) != null) {
- if (prev === '(' && next === '*') state.commentLevel++;
- if (prev === '*' && next === ')') state.commentLevel--;
- prev = next;
- }
- if (state.commentLevel <= 0) {
- state.tokenize = tokenBase;
- }
- return 'comment';
- }
-
- return {
- startState: function() {return {tokenize: tokenBase, commentLevel: 0};},
- token: function(stream, state) {
- if (stream.eatSpace()) return null;
- return state.tokenize(stream, state);
- }
- };
-});
-
-CodeMirror.defineMIME('text/x-ocaml', 'ocaml');
diff --git a/gulliver/js/codemirror/mode/pascal/LICENSE b/gulliver/js/codemirror/mode/pascal/LICENSE
deleted file mode 100644
index 8e3747e74..000000000
--- a/gulliver/js/codemirror/mode/pascal/LICENSE
+++ /dev/null
@@ -1,7 +0,0 @@
-Copyright (c) 2011 souceLair
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
diff --git a/gulliver/js/codemirror/mode/pascal/index.html b/gulliver/js/codemirror/mode/pascal/index.html
index b3016afb1..bf8ff0d63 100644
--- a/gulliver/js/codemirror/mode/pascal/index.html
+++ b/gulliver/js/codemirror/mode/pascal/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: Pascal mode
-
-
-
-
-
-
-
- CodeMirror: Pascal mode
+
+CodeMirror: Pascal mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Pascal mode
+
(* Example Pascal code *)
@@ -44,5 +58,4 @@ end;
MIME types defined: text/x-pascal.
-
-
+
diff --git a/gulliver/js/codemirror/mode/perl/LICENSE b/gulliver/js/codemirror/mode/perl/LICENSE
deleted file mode 100644
index 96f4115af..000000000
--- a/gulliver/js/codemirror/mode/perl/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2011 by Sabaca under the MIT license.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
diff --git a/gulliver/js/codemirror/mode/perl/index.html b/gulliver/js/codemirror/mode/perl/index.html
index 13c7af64d..2b7578efe 100644
--- a/gulliver/js/codemirror/mode/perl/index.html
+++ b/gulliver/js/codemirror/mode/perl/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: Perl mode
-
-
-
-
-
-
-
- CodeMirror: Perl mode
+
+CodeMirror: Perl mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Perl mode
+
#!/usr/bin/perl
@@ -58,5 +72,4 @@ something...
MIME types defined: text/x-perl.
-
-
+
diff --git a/gulliver/js/codemirror/mode/perl/perl.js b/gulliver/js/codemirror/mode/perl/perl.js
index 52361c610..5954b1a61 100644
--- a/gulliver/js/codemirror/mode/perl/perl.js
+++ b/gulliver/js/codemirror/mode/perl/perl.js
@@ -1,816 +1,816 @@
// CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
// This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
CodeMirror.defineMode("perl",function(){
- // http://perldoc.perl.org
- var PERL={ // null - magic touch
- // 1 - keyword
- // 2 - def
- // 3 - atom
- // 4 - operator
- // 5 - variable-2 (predefined)
- // [x,y] - x=1,2,3; y=must be defined if x{...}
- // PERL operators
- '->' : 4,
- '++' : 4,
- '--' : 4,
- '**' : 4,
- // ! ~ \ and unary + and -
- '=~' : 4,
- '!~' : 4,
- '*' : 4,
- '/' : 4,
- '%' : 4,
- 'x' : 4,
- '+' : 4,
- '-' : 4,
- '.' : 4,
- '<<' : 4,
- '>>' : 4,
- // named unary operators
- '<' : 4,
- '>' : 4,
- '<=' : 4,
- '>=' : 4,
- 'lt' : 4,
- 'gt' : 4,
- 'le' : 4,
- 'ge' : 4,
- '==' : 4,
- '!=' : 4,
- '<=>' : 4,
- 'eq' : 4,
- 'ne' : 4,
- 'cmp' : 4,
- '~~' : 4,
- '&' : 4,
- '|' : 4,
- '^' : 4,
- '&&' : 4,
- '||' : 4,
- '//' : 4,
- '..' : 4,
- '...' : 4,
- '?' : 4,
- ':' : 4,
- '=' : 4,
- '+=' : 4,
- '-=' : 4,
- '*=' : 4, // etc. ???
- ',' : 4,
- '=>' : 4,
- '::' : 4,
- // list operators (rightward)
- 'not' : 4,
- 'and' : 4,
- 'or' : 4,
- 'xor' : 4,
- // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
- 'BEGIN' : [5,1],
- 'END' : [5,1],
- 'PRINT' : [5,1],
- 'PRINTF' : [5,1],
- 'GETC' : [5,1],
- 'READ' : [5,1],
- 'READLINE' : [5,1],
- 'DESTROY' : [5,1],
- 'TIE' : [5,1],
- 'TIEHANDLE' : [5,1],
- 'UNTIE' : [5,1],
- 'STDIN' : 5,
- 'STDIN_TOP' : 5,
- 'STDOUT' : 5,
- 'STDOUT_TOP' : 5,
- 'STDERR' : 5,
- 'STDERR_TOP' : 5,
- '$ARG' : 5,
- '$_' : 5,
- '@ARG' : 5,
- '@_' : 5,
- '$LIST_SEPARATOR' : 5,
- '$"' : 5,
- '$PROCESS_ID' : 5,
- '$PID' : 5,
- '$$' : 5,
- '$REAL_GROUP_ID' : 5,
- '$GID' : 5,
- '$(' : 5,
- '$EFFECTIVE_GROUP_ID' : 5,
- '$EGID' : 5,
- '$)' : 5,
- '$PROGRAM_NAME' : 5,
- '$0' : 5,
- '$SUBSCRIPT_SEPARATOR' : 5,
- '$SUBSEP' : 5,
- '$;' : 5,
- '$REAL_USER_ID' : 5,
- '$UID' : 5,
- '$<' : 5,
- '$EFFECTIVE_USER_ID' : 5,
- '$EUID' : 5,
- '$>' : 5,
- '$a' : 5,
- '$b' : 5,
- '$COMPILING' : 5,
- '$^C' : 5,
- '$DEBUGGING' : 5,
- '$^D' : 5,
- '${^ENCODING}' : 5,
- '$ENV' : 5,
- '%ENV' : 5,
- '$SYSTEM_FD_MAX' : 5,
- '$^F' : 5,
- '@F' : 5,
- '${^GLOBAL_PHASE}' : 5,
- '$^H' : 5,
- '%^H' : 5,
- '@INC' : 5,
- '%INC' : 5,
- '$INPLACE_EDIT' : 5,
- '$^I' : 5,
- '$^M' : 5,
- '$OSNAME' : 5,
- '$^O' : 5,
- '${^OPEN}' : 5,
- '$PERLDB' : 5,
- '$^P' : 5,
- '$SIG' : 5,
- '%SIG' : 5,
- '$BASETIME' : 5,
- '$^T' : 5,
- '${^TAINT}' : 5,
- '${^UNICODE}' : 5,
- '${^UTF8CACHE}' : 5,
- '${^UTF8LOCALE}' : 5,
- '$PERL_VERSION' : 5,
- '$^V' : 5,
- '${^WIN32_SLOPPY_STAT}' : 5,
- '$EXECUTABLE_NAME' : 5,
- '$^X' : 5,
- '$1' : 5, // - regexp $1, $2...
- '$MATCH' : 5,
- '$&' : 5,
- '${^MATCH}' : 5,
- '$PREMATCH' : 5,
- '$`' : 5,
- '${^PREMATCH}' : 5,
- '$POSTMATCH' : 5,
- "$'" : 5,
- '${^POSTMATCH}' : 5,
- '$LAST_PAREN_MATCH' : 5,
- '$+' : 5,
- '$LAST_SUBMATCH_RESULT' : 5,
- '$^N' : 5,
- '@LAST_MATCH_END' : 5,
- '@+' : 5,
- '%LAST_PAREN_MATCH' : 5,
- '%+' : 5,
- '@LAST_MATCH_START' : 5,
- '@-' : 5,
- '%LAST_MATCH_START' : 5,
- '%-' : 5,
- '$LAST_REGEXP_CODE_RESULT' : 5,
- '$^R' : 5,
- '${^RE_DEBUG_FLAGS}' : 5,
- '${^RE_TRIE_MAXBUF}' : 5,
- '$ARGV' : 5,
- '@ARGV' : 5,
- 'ARGV' : 5,
- 'ARGVOUT' : 5,
- '$OUTPUT_FIELD_SEPARATOR' : 5,
- '$OFS' : 5,
- '$,' : 5,
- '$INPUT_LINE_NUMBER' : 5,
- '$NR' : 5,
- '$.' : 5,
- '$INPUT_RECORD_SEPARATOR' : 5,
- '$RS' : 5,
- '$/' : 5,
- '$OUTPUT_RECORD_SEPARATOR' : 5,
- '$ORS' : 5,
- '$\\' : 5,
- '$OUTPUT_AUTOFLUSH' : 5,
- '$|' : 5,
- '$ACCUMULATOR' : 5,
- '$^A' : 5,
- '$FORMAT_FORMFEED' : 5,
- '$^L' : 5,
- '$FORMAT_PAGE_NUMBER' : 5,
- '$%' : 5,
- '$FORMAT_LINES_LEFT' : 5,
- '$-' : 5,
- '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
- '$:' : 5,
- '$FORMAT_LINES_PER_PAGE' : 5,
- '$=' : 5,
- '$FORMAT_TOP_NAME' : 5,
- '$^' : 5,
- '$FORMAT_NAME' : 5,
- '$~' : 5,
- '${^CHILD_ERROR_NATIVE}' : 5,
- '$EXTENDED_OS_ERROR' : 5,
- '$^E' : 5,
- '$EXCEPTIONS_BEING_CAUGHT' : 5,
- '$^S' : 5,
- '$WARNING' : 5,
- '$^W' : 5,
- '${^WARNING_BITS}' : 5,
- '$OS_ERROR' : 5,
- '$ERRNO' : 5,
- '$!' : 5,
- '%OS_ERROR' : 5,
- '%ERRNO' : 5,
- '%!' : 5,
- '$CHILD_ERROR' : 5,
- '$?' : 5,
- '$EVAL_ERROR' : 5,
- '$@' : 5,
- '$OFMT' : 5,
- '$#' : 5,
- '$*' : 5,
- '$ARRAY_BASE' : 5,
- '$[' : 5,
- '$OLD_PERL_VERSION' : 5,
- '$]' : 5,
- // PERL blocks
- 'if' :[1,1],
- elsif :[1,1],
- 'else' :[1,1],
- 'while' :[1,1],
- unless :[1,1],
- 'for' :[1,1],
- foreach :[1,1],
- // PERL functions
- 'abs' :1, // - absolute value function
- accept :1, // - accept an incoming socket connect
- alarm :1, // - schedule a SIGALRM
- 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
- bind :1, // - binds an address to a socket
- binmode :1, // - prepare binary files for I/O
- bless :1, // - create an object
- bootstrap :1, //
- 'break' :1, // - break out of a "given" block
- caller :1, // - get context of the current subroutine call
- chdir :1, // - change your current working directory
- chmod :1, // - changes the permissions on a list of files
- chomp :1, // - remove a trailing record separator from a string
- chop :1, // - remove the last character from a string
- chown :1, // - change the owership on a list of files
- chr :1, // - get character this number represents
- chroot :1, // - make directory new root for path lookups
- close :1, // - close file (or pipe or socket) handle
- closedir :1, // - close directory handle
- connect :1, // - connect to a remote socket
- 'continue' :[1,1], // - optional trailing block in a while or foreach
- 'cos' :1, // - cosine function
- crypt :1, // - one-way passwd-style encryption
- dbmclose :1, // - breaks binding on a tied dbm file
- dbmopen :1, // - create binding on a tied dbm file
- 'default' :1, //
- defined :1, // - test whether a value, variable, or function is defined
- 'delete' :1, // - deletes a value from a hash
- die :1, // - raise an exception or bail out
- 'do' :1, // - turn a BLOCK into a TERM
- dump :1, // - create an immediate core dump
- each :1, // - retrieve the next key/value pair from a hash
- endgrent :1, // - be done using group file
- endhostent :1, // - be done using hosts file
- endnetent :1, // - be done using networks file
- endprotoent :1, // - be done using protocols file
- endpwent :1, // - be done using passwd file
- endservent :1, // - be done using services file
- eof :1, // - test a filehandle for its end
- 'eval' :1, // - catch exceptions or compile and run code
- 'exec' :1, // - abandon this program to run another
- exists :1, // - test whether a hash key is present
- exit :1, // - terminate this program
- 'exp' :1, // - raise I to a power
- fcntl :1, // - file control system call
- fileno :1, // - return file descriptor from filehandle
- flock :1, // - lock an entire file with an advisory lock
- fork :1, // - create a new process just like this one
- format :1, // - declare a picture format with use by the write() function
- formline :1, // - internal function used for formats
- getc :1, // - get the next character from the filehandle
- getgrent :1, // - get next group record
- getgrgid :1, // - get group record given group user ID
- getgrnam :1, // - get group record given group name
- gethostbyaddr :1, // - get host record given its address
- gethostbyname :1, // - get host record given name
- gethostent :1, // - get next hosts record
- getlogin :1, // - return who logged in at this tty
- getnetbyaddr :1, // - get network record given its address
- getnetbyname :1, // - get networks record given name
- getnetent :1, // - get next networks record
- getpeername :1, // - find the other end of a socket connection
- getpgrp :1, // - get process group
- getppid :1, // - get parent process ID
- getpriority :1, // - get current nice value
- getprotobyname :1, // - get protocol record given name
- getprotobynumber :1, // - get protocol record numeric protocol
- getprotoent :1, // - get next protocols record
- getpwent :1, // - get next passwd record
- getpwnam :1, // - get passwd record given user login name
- getpwuid :1, // - get passwd record given user ID
- getservbyname :1, // - get services record given its name
- getservbyport :1, // - get services record given numeric port
- getservent :1, // - get next services record
- getsockname :1, // - retrieve the sockaddr for a given socket
- getsockopt :1, // - get socket options on a given socket
- given :1, //
- glob :1, // - expand filenames using wildcards
- gmtime :1, // - convert UNIX time into record or string using Greenwich time
- 'goto' :1, // - create spaghetti code
- grep :1, // - locate elements in a list test true against a given criterion
- hex :1, // - convert a string to a hexadecimal number
- 'import' :1, // - patch a module's namespace into your own
- index :1, // - find a substring within a string
- 'int' :1, // - get the integer portion of a number
- ioctl :1, // - system-dependent device control system call
- 'join' :1, // - join a list into a string using a separator
- keys :1, // - retrieve list of indices from a hash
- kill :1, // - send a signal to a process or process group
- last :1, // - exit a block prematurely
- lc :1, // - return lower-case version of a string
- lcfirst :1, // - return a string with just the next letter in lower case
- length :1, // - return the number of bytes in a string
- 'link' :1, // - create a hard link in the filesytem
- listen :1, // - register your socket as a server
- local : 2, // - create a temporary value for a global variable (dynamic scoping)
- localtime :1, // - convert UNIX time into record or string using local time
- lock :1, // - get a thread lock on a variable, subroutine, or method
- 'log' :1, // - retrieve the natural logarithm for a number
- lstat :1, // - stat a symbolic link
- m :null, // - match a string with a regular expression pattern
- map :1, // - apply a change to a list to get back a new list with the changes
- mkdir :1, // - create a directory
- msgctl :1, // - SysV IPC message control operations
- msgget :1, // - get SysV IPC message queue
- msgrcv :1, // - receive a SysV IPC message from a message queue
- msgsnd :1, // - send a SysV IPC message to a message queue
- my : 2, // - declare and assign a local variable (lexical scoping)
- 'new' :1, //
- next :1, // - iterate a block prematurely
- no :1, // - unimport some module symbols or semantics at compile time
- oct :1, // - convert a string to an octal number
- open :1, // - open a file, pipe, or descriptor
- opendir :1, // - open a directory
- ord :1, // - find a character's numeric representation
- our : 2, // - declare and assign a package variable (lexical scoping)
- pack :1, // - convert a list into a binary representation
- 'package' :1, // - declare a separate global namespace
- pipe :1, // - open a pair of connected filehandles
- pop :1, // - remove the last element from an array and return it
- pos :1, // - find or set the offset for the last/next m//g search
- print :1, // - output a list to a filehandle
- printf :1, // - output a formatted list to a filehandle
- prototype :1, // - get the prototype (if any) of a subroutine
- push :1, // - append one or more elements to an array
- q :null, // - singly quote a string
- qq :null, // - doubly quote a string
- qr :null, // - Compile pattern
- quotemeta :null, // - quote regular expression magic characters
- qw :null, // - quote a list of words
- qx :null, // - backquote quote a string
- rand :1, // - retrieve the next pseudorandom number
- read :1, // - fixed-length buffered input from a filehandle
- readdir :1, // - get a directory from a directory handle
- readline :1, // - fetch a record from a file
- readlink :1, // - determine where a symbolic link is pointing
- readpipe :1, // - execute a system command and collect standard output
- recv :1, // - receive a message over a Socket
- redo :1, // - start this loop iteration over again
- ref :1, // - find out the type of thing being referenced
- rename :1, // - change a filename
- require :1, // - load in external functions from a library at runtime
- reset :1, // - clear all variables of a given name
- 'return' :1, // - get out of a function early
- reverse :1, // - flip a string or a list
- rewinddir :1, // - reset directory handle
- rindex :1, // - right-to-left substring search
- rmdir :1, // - remove a directory
- s :null, // - replace a pattern with a string
- say :1, // - print with newline
- scalar :1, // - force a scalar context
- seek :1, // - reposition file pointer for random-access I/O
- seekdir :1, // - reposition directory pointer
- select :1, // - reset default output or do I/O multiplexing
- semctl :1, // - SysV semaphore control operations
- semget :1, // - get set of SysV semaphores
- semop :1, // - SysV semaphore operations
- send :1, // - send a message over a socket
- setgrent :1, // - prepare group file for use
- sethostent :1, // - prepare hosts file for use
- setnetent :1, // - prepare networks file for use
- setpgrp :1, // - set the process group of a process
- setpriority :1, // - set a process's nice value
- setprotoent :1, // - prepare protocols file for use
- setpwent :1, // - prepare passwd file for use
- setservent :1, // - prepare services file for use
- setsockopt :1, // - set some socket options
- shift :1, // - remove the first element of an array, and return it
- shmctl :1, // - SysV shared memory operations
- shmget :1, // - get SysV shared memory segment identifier
- shmread :1, // - read SysV shared memory
- shmwrite :1, // - write SysV shared memory
- shutdown :1, // - close down just half of a socket connection
- 'sin' :1, // - return the sine of a number
- sleep :1, // - block for some number of seconds
- socket :1, // - create a socket
- socketpair :1, // - create a pair of sockets
- 'sort' :1, // - sort a list of values
- splice :1, // - add or remove elements anywhere in an array
- 'split' :1, // - split up a string using a regexp delimiter
- sprintf :1, // - formatted print into a string
- 'sqrt' :1, // - square root function
- srand :1, // - seed the random number generator
- stat :1, // - get a file's status information
- state :1, // - declare and assign a state variable (persistent lexical scoping)
- study :1, // - optimize input data for repeated searches
- 'sub' :1, // - declare a subroutine, possibly anonymously
- 'substr' :1, // - get or alter a portion of a stirng
- symlink :1, // - create a symbolic link to a file
- syscall :1, // - execute an arbitrary system call
- sysopen :1, // - open a file, pipe, or descriptor
- sysread :1, // - fixed-length unbuffered input from a filehandle
- sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
- system :1, // - run a separate program
- syswrite :1, // - fixed-length unbuffered output to a filehandle
- tell :1, // - get current seekpointer on a filehandle
- telldir :1, // - get current seekpointer on a directory handle
- tie :1, // - bind a variable to an object class
- tied :1, // - get a reference to the object underlying a tied variable
- time :1, // - return number of seconds since 1970
- times :1, // - return elapsed time for self and child processes
- tr :null, // - transliterate a string
- truncate :1, // - shorten a file
- uc :1, // - return upper-case version of a string
- ucfirst :1, // - return a string with just the next letter in upper case
- umask :1, // - set file creation mode mask
- undef :1, // - remove a variable or function definition
- unlink :1, // - remove one link to a file
- unpack :1, // - convert binary structure into normal perl variables
- unshift :1, // - prepend more elements to the beginning of a list
- untie :1, // - break a tie binding to a variable
- use :1, // - load in a module at compile time
- utime :1, // - set a file's last access and modify times
- values :1, // - return a list of the values in a hash
- vec :1, // - test or set particular bits in a string
- wait :1, // - wait for any child process to die
- waitpid :1, // - wait for a particular child process to die
- wantarray :1, // - get void vs scalar vs list context of current subroutine call
- warn :1, // - print debugging info
- when :1, //
- write :1, // - print a picture record
- y :null}; // - transliterate a string
+ // http://perldoc.perl.org
+ var PERL={ // null - magic touch
+ // 1 - keyword
+ // 2 - def
+ // 3 - atom
+ // 4 - operator
+ // 5 - variable-2 (predefined)
+ // [x,y] - x=1,2,3; y=must be defined if x{...}
+ // PERL operators
+ '->' : 4,
+ '++' : 4,
+ '--' : 4,
+ '**' : 4,
+ // ! ~ \ and unary + and -
+ '=~' : 4,
+ '!~' : 4,
+ '*' : 4,
+ '/' : 4,
+ '%' : 4,
+ 'x' : 4,
+ '+' : 4,
+ '-' : 4,
+ '.' : 4,
+ '<<' : 4,
+ '>>' : 4,
+ // named unary operators
+ '<' : 4,
+ '>' : 4,
+ '<=' : 4,
+ '>=' : 4,
+ 'lt' : 4,
+ 'gt' : 4,
+ 'le' : 4,
+ 'ge' : 4,
+ '==' : 4,
+ '!=' : 4,
+ '<=>' : 4,
+ 'eq' : 4,
+ 'ne' : 4,
+ 'cmp' : 4,
+ '~~' : 4,
+ '&' : 4,
+ '|' : 4,
+ '^' : 4,
+ '&&' : 4,
+ '||' : 4,
+ '//' : 4,
+ '..' : 4,
+ '...' : 4,
+ '?' : 4,
+ ':' : 4,
+ '=' : 4,
+ '+=' : 4,
+ '-=' : 4,
+ '*=' : 4, // etc. ???
+ ',' : 4,
+ '=>' : 4,
+ '::' : 4,
+ // list operators (rightward)
+ 'not' : 4,
+ 'and' : 4,
+ 'or' : 4,
+ 'xor' : 4,
+ // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
+ 'BEGIN' : [5,1],
+ 'END' : [5,1],
+ 'PRINT' : [5,1],
+ 'PRINTF' : [5,1],
+ 'GETC' : [5,1],
+ 'READ' : [5,1],
+ 'READLINE' : [5,1],
+ 'DESTROY' : [5,1],
+ 'TIE' : [5,1],
+ 'TIEHANDLE' : [5,1],
+ 'UNTIE' : [5,1],
+ 'STDIN' : 5,
+ 'STDIN_TOP' : 5,
+ 'STDOUT' : 5,
+ 'STDOUT_TOP' : 5,
+ 'STDERR' : 5,
+ 'STDERR_TOP' : 5,
+ '$ARG' : 5,
+ '$_' : 5,
+ '@ARG' : 5,
+ '@_' : 5,
+ '$LIST_SEPARATOR' : 5,
+ '$"' : 5,
+ '$PROCESS_ID' : 5,
+ '$PID' : 5,
+ '$$' : 5,
+ '$REAL_GROUP_ID' : 5,
+ '$GID' : 5,
+ '$(' : 5,
+ '$EFFECTIVE_GROUP_ID' : 5,
+ '$EGID' : 5,
+ '$)' : 5,
+ '$PROGRAM_NAME' : 5,
+ '$0' : 5,
+ '$SUBSCRIPT_SEPARATOR' : 5,
+ '$SUBSEP' : 5,
+ '$;' : 5,
+ '$REAL_USER_ID' : 5,
+ '$UID' : 5,
+ '$<' : 5,
+ '$EFFECTIVE_USER_ID' : 5,
+ '$EUID' : 5,
+ '$>' : 5,
+ '$a' : 5,
+ '$b' : 5,
+ '$COMPILING' : 5,
+ '$^C' : 5,
+ '$DEBUGGING' : 5,
+ '$^D' : 5,
+ '${^ENCODING}' : 5,
+ '$ENV' : 5,
+ '%ENV' : 5,
+ '$SYSTEM_FD_MAX' : 5,
+ '$^F' : 5,
+ '@F' : 5,
+ '${^GLOBAL_PHASE}' : 5,
+ '$^H' : 5,
+ '%^H' : 5,
+ '@INC' : 5,
+ '%INC' : 5,
+ '$INPLACE_EDIT' : 5,
+ '$^I' : 5,
+ '$^M' : 5,
+ '$OSNAME' : 5,
+ '$^O' : 5,
+ '${^OPEN}' : 5,
+ '$PERLDB' : 5,
+ '$^P' : 5,
+ '$SIG' : 5,
+ '%SIG' : 5,
+ '$BASETIME' : 5,
+ '$^T' : 5,
+ '${^TAINT}' : 5,
+ '${^UNICODE}' : 5,
+ '${^UTF8CACHE}' : 5,
+ '${^UTF8LOCALE}' : 5,
+ '$PERL_VERSION' : 5,
+ '$^V' : 5,
+ '${^WIN32_SLOPPY_STAT}' : 5,
+ '$EXECUTABLE_NAME' : 5,
+ '$^X' : 5,
+ '$1' : 5, // - regexp $1, $2...
+ '$MATCH' : 5,
+ '$&' : 5,
+ '${^MATCH}' : 5,
+ '$PREMATCH' : 5,
+ '$`' : 5,
+ '${^PREMATCH}' : 5,
+ '$POSTMATCH' : 5,
+ "$'" : 5,
+ '${^POSTMATCH}' : 5,
+ '$LAST_PAREN_MATCH' : 5,
+ '$+' : 5,
+ '$LAST_SUBMATCH_RESULT' : 5,
+ '$^N' : 5,
+ '@LAST_MATCH_END' : 5,
+ '@+' : 5,
+ '%LAST_PAREN_MATCH' : 5,
+ '%+' : 5,
+ '@LAST_MATCH_START' : 5,
+ '@-' : 5,
+ '%LAST_MATCH_START' : 5,
+ '%-' : 5,
+ '$LAST_REGEXP_CODE_RESULT' : 5,
+ '$^R' : 5,
+ '${^RE_DEBUG_FLAGS}' : 5,
+ '${^RE_TRIE_MAXBUF}' : 5,
+ '$ARGV' : 5,
+ '@ARGV' : 5,
+ 'ARGV' : 5,
+ 'ARGVOUT' : 5,
+ '$OUTPUT_FIELD_SEPARATOR' : 5,
+ '$OFS' : 5,
+ '$,' : 5,
+ '$INPUT_LINE_NUMBER' : 5,
+ '$NR' : 5,
+ '$.' : 5,
+ '$INPUT_RECORD_SEPARATOR' : 5,
+ '$RS' : 5,
+ '$/' : 5,
+ '$OUTPUT_RECORD_SEPARATOR' : 5,
+ '$ORS' : 5,
+ '$\\' : 5,
+ '$OUTPUT_AUTOFLUSH' : 5,
+ '$|' : 5,
+ '$ACCUMULATOR' : 5,
+ '$^A' : 5,
+ '$FORMAT_FORMFEED' : 5,
+ '$^L' : 5,
+ '$FORMAT_PAGE_NUMBER' : 5,
+ '$%' : 5,
+ '$FORMAT_LINES_LEFT' : 5,
+ '$-' : 5,
+ '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
+ '$:' : 5,
+ '$FORMAT_LINES_PER_PAGE' : 5,
+ '$=' : 5,
+ '$FORMAT_TOP_NAME' : 5,
+ '$^' : 5,
+ '$FORMAT_NAME' : 5,
+ '$~' : 5,
+ '${^CHILD_ERROR_NATIVE}' : 5,
+ '$EXTENDED_OS_ERROR' : 5,
+ '$^E' : 5,
+ '$EXCEPTIONS_BEING_CAUGHT' : 5,
+ '$^S' : 5,
+ '$WARNING' : 5,
+ '$^W' : 5,
+ '${^WARNING_BITS}' : 5,
+ '$OS_ERROR' : 5,
+ '$ERRNO' : 5,
+ '$!' : 5,
+ '%OS_ERROR' : 5,
+ '%ERRNO' : 5,
+ '%!' : 5,
+ '$CHILD_ERROR' : 5,
+ '$?' : 5,
+ '$EVAL_ERROR' : 5,
+ '$@' : 5,
+ '$OFMT' : 5,
+ '$#' : 5,
+ '$*' : 5,
+ '$ARRAY_BASE' : 5,
+ '$[' : 5,
+ '$OLD_PERL_VERSION' : 5,
+ '$]' : 5,
+ // PERL blocks
+ 'if' :[1,1],
+ elsif :[1,1],
+ 'else' :[1,1],
+ 'while' :[1,1],
+ unless :[1,1],
+ 'for' :[1,1],
+ foreach :[1,1],
+ // PERL functions
+ 'abs' :1, // - absolute value function
+ accept :1, // - accept an incoming socket connect
+ alarm :1, // - schedule a SIGALRM
+ 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
+ bind :1, // - binds an address to a socket
+ binmode :1, // - prepare binary files for I/O
+ bless :1, // - create an object
+ bootstrap :1, //
+ 'break' :1, // - break out of a "given" block
+ caller :1, // - get context of the current subroutine call
+ chdir :1, // - change your current working directory
+ chmod :1, // - changes the permissions on a list of files
+ chomp :1, // - remove a trailing record separator from a string
+ chop :1, // - remove the last character from a string
+ chown :1, // - change the owership on a list of files
+ chr :1, // - get character this number represents
+ chroot :1, // - make directory new root for path lookups
+ close :1, // - close file (or pipe or socket) handle
+ closedir :1, // - close directory handle
+ connect :1, // - connect to a remote socket
+ 'continue' :[1,1], // - optional trailing block in a while or foreach
+ 'cos' :1, // - cosine function
+ crypt :1, // - one-way passwd-style encryption
+ dbmclose :1, // - breaks binding on a tied dbm file
+ dbmopen :1, // - create binding on a tied dbm file
+ 'default' :1, //
+ defined :1, // - test whether a value, variable, or function is defined
+ 'delete' :1, // - deletes a value from a hash
+ die :1, // - raise an exception or bail out
+ 'do' :1, // - turn a BLOCK into a TERM
+ dump :1, // - create an immediate core dump
+ each :1, // - retrieve the next key/value pair from a hash
+ endgrent :1, // - be done using group file
+ endhostent :1, // - be done using hosts file
+ endnetent :1, // - be done using networks file
+ endprotoent :1, // - be done using protocols file
+ endpwent :1, // - be done using passwd file
+ endservent :1, // - be done using services file
+ eof :1, // - test a filehandle for its end
+ 'eval' :1, // - catch exceptions or compile and run code
+ 'exec' :1, // - abandon this program to run another
+ exists :1, // - test whether a hash key is present
+ exit :1, // - terminate this program
+ 'exp' :1, // - raise I to a power
+ fcntl :1, // - file control system call
+ fileno :1, // - return file descriptor from filehandle
+ flock :1, // - lock an entire file with an advisory lock
+ fork :1, // - create a new process just like this one
+ format :1, // - declare a picture format with use by the write() function
+ formline :1, // - internal function used for formats
+ getc :1, // - get the next character from the filehandle
+ getgrent :1, // - get next group record
+ getgrgid :1, // - get group record given group user ID
+ getgrnam :1, // - get group record given group name
+ gethostbyaddr :1, // - get host record given its address
+ gethostbyname :1, // - get host record given name
+ gethostent :1, // - get next hosts record
+ getlogin :1, // - return who logged in at this tty
+ getnetbyaddr :1, // - get network record given its address
+ getnetbyname :1, // - get networks record given name
+ getnetent :1, // - get next networks record
+ getpeername :1, // - find the other end of a socket connection
+ getpgrp :1, // - get process group
+ getppid :1, // - get parent process ID
+ getpriority :1, // - get current nice value
+ getprotobyname :1, // - get protocol record given name
+ getprotobynumber :1, // - get protocol record numeric protocol
+ getprotoent :1, // - get next protocols record
+ getpwent :1, // - get next passwd record
+ getpwnam :1, // - get passwd record given user login name
+ getpwuid :1, // - get passwd record given user ID
+ getservbyname :1, // - get services record given its name
+ getservbyport :1, // - get services record given numeric port
+ getservent :1, // - get next services record
+ getsockname :1, // - retrieve the sockaddr for a given socket
+ getsockopt :1, // - get socket options on a given socket
+ given :1, //
+ glob :1, // - expand filenames using wildcards
+ gmtime :1, // - convert UNIX time into record or string using Greenwich time
+ 'goto' :1, // - create spaghetti code
+ grep :1, // - locate elements in a list test true against a given criterion
+ hex :1, // - convert a string to a hexadecimal number
+ 'import' :1, // - patch a module's namespace into your own
+ index :1, // - find a substring within a string
+ 'int' :1, // - get the integer portion of a number
+ ioctl :1, // - system-dependent device control system call
+ 'join' :1, // - join a list into a string using a separator
+ keys :1, // - retrieve list of indices from a hash
+ kill :1, // - send a signal to a process or process group
+ last :1, // - exit a block prematurely
+ lc :1, // - return lower-case version of a string
+ lcfirst :1, // - return a string with just the next letter in lower case
+ length :1, // - return the number of bytes in a string
+ 'link' :1, // - create a hard link in the filesytem
+ listen :1, // - register your socket as a server
+ local : 2, // - create a temporary value for a global variable (dynamic scoping)
+ localtime :1, // - convert UNIX time into record or string using local time
+ lock :1, // - get a thread lock on a variable, subroutine, or method
+ 'log' :1, // - retrieve the natural logarithm for a number
+ lstat :1, // - stat a symbolic link
+ m :null, // - match a string with a regular expression pattern
+ map :1, // - apply a change to a list to get back a new list with the changes
+ mkdir :1, // - create a directory
+ msgctl :1, // - SysV IPC message control operations
+ msgget :1, // - get SysV IPC message queue
+ msgrcv :1, // - receive a SysV IPC message from a message queue
+ msgsnd :1, // - send a SysV IPC message to a message queue
+ my : 2, // - declare and assign a local variable (lexical scoping)
+ 'new' :1, //
+ next :1, // - iterate a block prematurely
+ no :1, // - unimport some module symbols or semantics at compile time
+ oct :1, // - convert a string to an octal number
+ open :1, // - open a file, pipe, or descriptor
+ opendir :1, // - open a directory
+ ord :1, // - find a character's numeric representation
+ our : 2, // - declare and assign a package variable (lexical scoping)
+ pack :1, // - convert a list into a binary representation
+ 'package' :1, // - declare a separate global namespace
+ pipe :1, // - open a pair of connected filehandles
+ pop :1, // - remove the last element from an array and return it
+ pos :1, // - find or set the offset for the last/next m//g search
+ print :1, // - output a list to a filehandle
+ printf :1, // - output a formatted list to a filehandle
+ prototype :1, // - get the prototype (if any) of a subroutine
+ push :1, // - append one or more elements to an array
+ q :null, // - singly quote a string
+ qq :null, // - doubly quote a string
+ qr :null, // - Compile pattern
+ quotemeta :null, // - quote regular expression magic characters
+ qw :null, // - quote a list of words
+ qx :null, // - backquote quote a string
+ rand :1, // - retrieve the next pseudorandom number
+ read :1, // - fixed-length buffered input from a filehandle
+ readdir :1, // - get a directory from a directory handle
+ readline :1, // - fetch a record from a file
+ readlink :1, // - determine where a symbolic link is pointing
+ readpipe :1, // - execute a system command and collect standard output
+ recv :1, // - receive a message over a Socket
+ redo :1, // - start this loop iteration over again
+ ref :1, // - find out the type of thing being referenced
+ rename :1, // - change a filename
+ require :1, // - load in external functions from a library at runtime
+ reset :1, // - clear all variables of a given name
+ 'return' :1, // - get out of a function early
+ reverse :1, // - flip a string or a list
+ rewinddir :1, // - reset directory handle
+ rindex :1, // - right-to-left substring search
+ rmdir :1, // - remove a directory
+ s :null, // - replace a pattern with a string
+ say :1, // - print with newline
+ scalar :1, // - force a scalar context
+ seek :1, // - reposition file pointer for random-access I/O
+ seekdir :1, // - reposition directory pointer
+ select :1, // - reset default output or do I/O multiplexing
+ semctl :1, // - SysV semaphore control operations
+ semget :1, // - get set of SysV semaphores
+ semop :1, // - SysV semaphore operations
+ send :1, // - send a message over a socket
+ setgrent :1, // - prepare group file for use
+ sethostent :1, // - prepare hosts file for use
+ setnetent :1, // - prepare networks file for use
+ setpgrp :1, // - set the process group of a process
+ setpriority :1, // - set a process's nice value
+ setprotoent :1, // - prepare protocols file for use
+ setpwent :1, // - prepare passwd file for use
+ setservent :1, // - prepare services file for use
+ setsockopt :1, // - set some socket options
+ shift :1, // - remove the first element of an array, and return it
+ shmctl :1, // - SysV shared memory operations
+ shmget :1, // - get SysV shared memory segment identifier
+ shmread :1, // - read SysV shared memory
+ shmwrite :1, // - write SysV shared memory
+ shutdown :1, // - close down just half of a socket connection
+ 'sin' :1, // - return the sine of a number
+ sleep :1, // - block for some number of seconds
+ socket :1, // - create a socket
+ socketpair :1, // - create a pair of sockets
+ 'sort' :1, // - sort a list of values
+ splice :1, // - add or remove elements anywhere in an array
+ 'split' :1, // - split up a string using a regexp delimiter
+ sprintf :1, // - formatted print into a string
+ 'sqrt' :1, // - square root function
+ srand :1, // - seed the random number generator
+ stat :1, // - get a file's status information
+ state :1, // - declare and assign a state variable (persistent lexical scoping)
+ study :1, // - optimize input data for repeated searches
+ 'sub' :1, // - declare a subroutine, possibly anonymously
+ 'substr' :1, // - get or alter a portion of a stirng
+ symlink :1, // - create a symbolic link to a file
+ syscall :1, // - execute an arbitrary system call
+ sysopen :1, // - open a file, pipe, or descriptor
+ sysread :1, // - fixed-length unbuffered input from a filehandle
+ sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
+ system :1, // - run a separate program
+ syswrite :1, // - fixed-length unbuffered output to a filehandle
+ tell :1, // - get current seekpointer on a filehandle
+ telldir :1, // - get current seekpointer on a directory handle
+ tie :1, // - bind a variable to an object class
+ tied :1, // - get a reference to the object underlying a tied variable
+ time :1, // - return number of seconds since 1970
+ times :1, // - return elapsed time for self and child processes
+ tr :null, // - transliterate a string
+ truncate :1, // - shorten a file
+ uc :1, // - return upper-case version of a string
+ ucfirst :1, // - return a string with just the next letter in upper case
+ umask :1, // - set file creation mode mask
+ undef :1, // - remove a variable or function definition
+ unlink :1, // - remove one link to a file
+ unpack :1, // - convert binary structure into normal perl variables
+ unshift :1, // - prepend more elements to the beginning of a list
+ untie :1, // - break a tie binding to a variable
+ use :1, // - load in a module at compile time
+ utime :1, // - set a file's last access and modify times
+ values :1, // - return a list of the values in a hash
+ vec :1, // - test or set particular bits in a string
+ wait :1, // - wait for any child process to die
+ waitpid :1, // - wait for a particular child process to die
+ wantarray :1, // - get void vs scalar vs list context of current subroutine call
+ warn :1, // - print debugging info
+ when :1, //
+ write :1, // - print a picture record
+ y :null}; // - transliterate a string
- var RXstyle="string-2";
- var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
+ var RXstyle="string-2";
+ var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
- function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
- state.chain=null; // 12 3tail
- state.style=null;
- state.tail=null;
- state.tokenize=function(stream,state){
- var e=false,c,i=0;
- while(c=stream.next()){
- if(c===chain[i]&&!e){
- if(chain[++i]!==undefined){
- state.chain=chain[i];
- state.style=style;
- state.tail=tail;}
- else if(tail)
- stream.eatWhile(tail);
- state.tokenize=tokenPerl;
- return style;}
- e=!e&&c=="\\";}
- return style;};
- return state.tokenize(stream,state);}
+ function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
+ state.chain=null; // 12 3tail
+ state.style=null;
+ state.tail=null;
+ state.tokenize=function(stream,state){
+ var e=false,c,i=0;
+ while(c=stream.next()){
+ if(c===chain[i]&&!e){
+ if(chain[++i]!==undefined){
+ state.chain=chain[i];
+ state.style=style;
+ state.tail=tail;}
+ else if(tail)
+ stream.eatWhile(tail);
+ state.tokenize=tokenPerl;
+ return style;}
+ e=!e&&c=="\\";}
+ return style;};
+ return state.tokenize(stream,state);}
- function tokenSOMETHING(stream,state,string){
- state.tokenize=function(stream,state){
- if(stream.string==string)
- state.tokenize=tokenPerl;
- stream.skipToEnd();
- return "string";};
- return state.tokenize(stream,state);}
+ function tokenSOMETHING(stream,state,string){
+ state.tokenize=function(stream,state){
+ if(stream.string==string)
+ state.tokenize=tokenPerl;
+ stream.skipToEnd();
+ return "string";};
+ return state.tokenize(stream,state);}
- function tokenPerl(stream,state){
- if(stream.eatSpace())
- return null;
- if(state.chain)
- return tokenChain(stream,state,state.chain,state.style,state.tail);
- if(stream.match(/^\-?[\d\.]/,false))
- if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
- return 'number';
- if(stream.match(/^<<(?=\w)/)){ // NOTE: <"],RXstyle,RXmodifiers);}
- if(/[\^'"!~\/]/.test(c)){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
- else if(c=="q"){
- c=stream.look(1);
- if(c=="("){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[")"],"string");}
- if(c=="["){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["]"],"string");}
- if(c=="{"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["}"],"string");}
- if(c=="<"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[">"],"string");}
- if(/[\^'"!~\/]/.test(c)){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[stream.eat(c)],"string");}}
- else if(c=="w"){
- c=stream.look(1);
- if(c=="("){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[")"],"bracket");}
- if(c=="["){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["]"],"bracket");}
- if(c=="{"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["}"],"bracket");}
- if(c=="<"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[">"],"bracket");}
- if(/[\^'"!~\/]/.test(c)){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[stream.eat(c)],"bracket");}}
- else if(c=="r"){
- c=stream.look(1);
- if(c=="("){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
- if(c=="["){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
- if(c=="{"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
- if(c=="<"){
- stream.eatSuffix(2);
- return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
- if(/[\^'"!~\/]/.test(c)){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
- else if(/[\^'"!~\/(\[{<]/.test(c)){
- if(c=="("){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[")"],"string");}
- if(c=="["){
- stream.eatSuffix(1);
- return tokenChain(stream,state,["]"],"string");}
- if(c=="{"){
- stream.eatSuffix(1);
- return tokenChain(stream,state,["}"],"string");}
- if(c=="<"){
- stream.eatSuffix(1);
- return tokenChain(stream,state,[">"],"string");}
- if(/[\^'"!~\/]/.test(c)){
- return tokenChain(stream,state,[stream.eat(c)],"string");}}}}
- if(ch=="m"){
- var c=stream.look(-2);
- if(!(c&&/\w/.test(c))){
- c=stream.eat(/[(\[{<\^'"!~\/]/);
- if(c){
- if(/[\^'"!~\/]/.test(c)){
- return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}
- if(c=="("){
- return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
- if(c=="["){
- return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
- if(c=="{"){
- return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
- if(c=="<"){
- return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}}
- if(ch=="s"){
- var c=/[\/>\]})\w]/.test(stream.look(-2));
- if(!c){
- c=stream.eat(/[(\[{<\^'"!~\/]/);
- if(c){
- if(c=="[")
- return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
- if(c=="{")
- return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
- if(c=="<")
- return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
- if(c=="(")
- return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
- return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
- if(ch=="y"){
- var c=/[\/>\]})\w]/.test(stream.look(-2));
- if(!c){
- c=stream.eat(/[(\[{<\^'"!~\/]/);
- if(c){
- if(c=="[")
- return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
- if(c=="{")
- return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
- if(c=="<")
- return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
- if(c=="(")
- return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
- return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
- if(ch=="t"){
- var c=/[\/>\]})\w]/.test(stream.look(-2));
- if(!c){
- c=stream.eat("r");if(c){
- c=stream.eat(/[(\[{<\^'"!~\/]/);
- if(c){
- if(c=="[")
- return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
- if(c=="{")
- return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
- if(c=="<")
- return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
- if(c=="(")
- return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
- return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}
- if(ch=="`"){
- return tokenChain(stream,state,[ch],"variable-2");}
- if(ch=="/"){
- if(!/~\s*$/.test(stream.prefix()))
- return "operator";
- else
- return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}
- if(ch=="$"){
- var p=stream.pos;
- if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
- return "variable-2";
- else
- stream.pos=p;}
- if(/[$@%]/.test(ch)){
- var p=stream.pos;
- if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
- var c=stream.current();
- if(PERL[c])
- return "variable-2";}
- stream.pos=p;}
- if(/[$@%&]/.test(ch)){
- if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
- var c=stream.current();
- if(PERL[c])
- return "variable-2";
- else
- return "variable";}}
- if(ch=="#"){
- if(stream.look(-2)!="$"){
- stream.skipToEnd();
- return "comment";}}
- if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
- var p=stream.pos;
- stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
- if(PERL[stream.current()])
- return "operator";
- else
- stream.pos=p;}
- if(ch=="_"){
- if(stream.pos==1){
- if(stream.suffix(6)=="_END__"){
- return tokenChain(stream,state,['\0'],"comment");}
- else if(stream.suffix(7)=="_DATA__"){
- return tokenChain(stream,state,['\0'],"variable-2");}
- else if(stream.suffix(7)=="_C__"){
- return tokenChain(stream,state,['\0'],"string");}}}
- if(/\w/.test(ch)){
- var p=stream.pos;
- if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
- return "string";
- else
- stream.pos=p;}
- if(/[A-Z]/.test(ch)){
- var l=stream.look(-2);
- var p=stream.pos;
- stream.eatWhile(/[A-Z_]/);
- if(/[\da-z]/.test(stream.look(0))){
- stream.pos=p;}
- else{
- var c=PERL[stream.current()];
- if(!c)
- return "meta";
- if(c[1])
- c=c[0];
- if(l!=":"){
- if(c==1)
- return "keyword";
- else if(c==2)
- return "def";
- else if(c==3)
- return "atom";
- else if(c==4)
- return "operator";
- else if(c==5)
- return "variable-2";
- else
- return "meta";}
- else
- return "meta";}}
- if(/[a-zA-Z_]/.test(ch)){
- var l=stream.look(-2);
- stream.eatWhile(/\w/);
- var c=PERL[stream.current()];
- if(!c)
- return "meta";
- if(c[1])
- c=c[0];
- if(l!=":"){
- if(c==1)
- return "keyword";
- else if(c==2)
- return "def";
- else if(c==3)
- return "atom";
- else if(c==4)
- return "operator";
- else if(c==5)
- return "variable-2";
- else
- return "meta";}
- else
- return "meta";}
- return null;}
+ function tokenPerl(stream,state){
+ if(stream.eatSpace())
+ return null;
+ if(state.chain)
+ return tokenChain(stream,state,state.chain,state.style,state.tail);
+ if(stream.match(/^\-?[\d\.]/,false))
+ if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
+ return 'number';
+ if(stream.match(/^<<(?=\w)/)){ // NOTE: <"],RXstyle,RXmodifiers);}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
+ else if(c=="q"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],"string");}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],"string");}
+ if(c=="{"){
+stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],"string");}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],"string");}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],"string");}}
+ else if(c=="w"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],"bracket");}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],"bracket");}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],"bracket");}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],"bracket");}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],"bracket");}}
+ else if(c=="r"){
+ c=stream.look(1);
+ if(c=="("){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
+ if(c=="["){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
+ if(c=="{"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
+ if(c=="<"){
+ stream.eatSuffix(2);
+ return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
+ if(/[\^'"!~\/]/.test(c)){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
+ else if(/[\^'"!~\/(\[{<]/.test(c)){
+ if(c=="("){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[")"],"string");}
+ if(c=="["){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,["]"],"string");}
+ if(c=="{"){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,["}"],"string");}
+ if(c=="<"){
+ stream.eatSuffix(1);
+ return tokenChain(stream,state,[">"],"string");}
+ if(/[\^'"!~\/]/.test(c)){
+ return tokenChain(stream,state,[stream.eat(c)],"string");}}}}
+ if(ch=="m"){
+ var c=stream.look(-2);
+ if(!(c&&/\w/.test(c))){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(/[\^'"!~\/]/.test(c)){
+ return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}
+ if(c=="("){
+ return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
+ if(c=="["){
+ return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
+ if(c=="{"){
+ return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
+ if(c=="<"){
+ return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}}
+ if(ch=="s"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
+ if(ch=="y"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
+ if(ch=="t"){
+ var c=/[\/>\]})\w]/.test(stream.look(-2));
+ if(!c){
+ c=stream.eat("r");if(c){
+ c=stream.eat(/[(\[{<\^'"!~\/]/);
+ if(c){
+ if(c=="[")
+ return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
+ if(c=="{")
+ return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
+ if(c=="<")
+ return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
+ if(c=="(")
+ return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
+ return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}
+ if(ch=="`"){
+ return tokenChain(stream,state,[ch],"variable-2");}
+ if(ch=="/"){
+ if(!/~\s*$/.test(stream.prefix()))
+ return "operator";
+ else
+ return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}
+ if(ch=="$"){
+ var p=stream.pos;
+ if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
+ return "variable-2";
+ else
+ stream.pos=p;}
+ if(/[$@%]/.test(ch)){
+ var p=stream.pos;
+ if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
+ var c=stream.current();
+ if(PERL[c])
+ return "variable-2";}
+ stream.pos=p;}
+ if(/[$@%&]/.test(ch)){
+ if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
+ var c=stream.current();
+ if(PERL[c])
+ return "variable-2";
+ else
+ return "variable";}}
+ if(ch=="#"){
+ if(stream.look(-2)!="$"){
+ stream.skipToEnd();
+ return "comment";}}
+ if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
+ var p=stream.pos;
+ stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
+ if(PERL[stream.current()])
+ return "operator";
+ else
+ stream.pos=p;}
+ if(ch=="_"){
+ if(stream.pos==1){
+ if(stream.suffix(6)=="_END__"){
+ return tokenChain(stream,state,['\0'],"comment");}
+ else if(stream.suffix(7)=="_DATA__"){
+ return tokenChain(stream,state,['\0'],"variable-2");}
+ else if(stream.suffix(7)=="_C__"){
+ return tokenChain(stream,state,['\0'],"string");}}}
+ if(/\w/.test(ch)){
+ var p=stream.pos;
+ if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
+ return "string";
+ else
+ stream.pos=p;}
+ if(/[A-Z]/.test(ch)){
+ var l=stream.look(-2);
+ var p=stream.pos;
+ stream.eatWhile(/[A-Z_]/);
+ if(/[\da-z]/.test(stream.look(0))){
+ stream.pos=p;}
+ else{
+ var c=PERL[stream.current()];
+ if(!c)
+ return "meta";
+ if(c[1])
+ c=c[0];
+ if(l!=":"){
+ if(c==1)
+ return "keyword";
+ else if(c==2)
+ return "def";
+ else if(c==3)
+ return "atom";
+ else if(c==4)
+ return "operator";
+ else if(c==5)
+ return "variable-2";
+ else
+ return "meta";}
+ else
+ return "meta";}}
+ if(/[a-zA-Z_]/.test(ch)){
+ var l=stream.look(-2);
+ stream.eatWhile(/\w/);
+ var c=PERL[stream.current()];
+ if(!c)
+ return "meta";
+ if(c[1])
+ c=c[0];
+ if(l!=":"){
+ if(c==1)
+ return "keyword";
+ else if(c==2)
+ return "def";
+ else if(c==3)
+ return "atom";
+ else if(c==4)
+ return "operator";
+ else if(c==5)
+ return "variable-2";
+ else
+ return "meta";}
+ else
+ return "meta";}
+ return null;}
- return{
- startState:function(){
- return{
- tokenize:tokenPerl,
- chain:null,
- style:null,
- tail:null};},
- token:function(stream,state){
- return (state.tokenize||tokenPerl)(stream,state);},
- electricChars:"{}"};});
+ return{
+ startState:function(){
+ return{
+ tokenize:tokenPerl,
+ chain:null,
+ style:null,
+ tail:null};},
+ token:function(stream,state){
+ return (state.tokenize||tokenPerl)(stream,state);},
+ electricChars:"{}"};});
CodeMirror.defineMIME("text/x-perl", "perl");
// it's like "peek", but need for look-ahead or look-behind if index < 0
CodeMirror.StringStream.prototype.look=function(c){
- return this.string.charAt(this.pos+(c||0));};
+ return this.string.charAt(this.pos+(c||0));};
// return a part of prefix of current stream from current position
CodeMirror.StringStream.prototype.prefix=function(c){
- if(c){
- var x=this.pos-c;
- return this.string.substr((x>=0?x:0),c);}
- else{
- return this.string.substr(0,this.pos-1);}};
+ if(c){
+ var x=this.pos-c;
+ return this.string.substr((x>=0?x:0),c);}
+ else{
+ return this.string.substr(0,this.pos-1);}};
// return a part of suffix of current stream from current position
CodeMirror.StringStream.prototype.suffix=function(c){
- var y=this.string.length;
- var x=y-this.pos+1;
- return this.string.substr(this.pos,(c&&c=(y=this.string.length-1))
- this.pos=y;
- else
- this.pos=x;};
+ var x=this.pos+c;
+ var y;
+ if(x<=0)
+ this.pos=0;
+ else if(x>=(y=this.string.length-1))
+ this.pos=y;
+ else
+ this.pos=x;};
diff --git a/gulliver/js/codemirror/mode/php/index.html b/gulliver/js/codemirror/mode/php/index.html
index 3d4c336ce..aaf51c0f5 100644
--- a/gulliver/js/codemirror/mode/php/index.html
+++ b/gulliver/js/codemirror/mode/php/index.html
@@ -1,23 +1,35 @@
-
-
-
- CodeMirror: PHP mode
-
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: PHP mode
+CodeMirror: PHP mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+PHP mode
MIME types defined: application/x-httpd-php (HTML with PHP code), text/x-php (plain, non-wrapped PHP code).
-
-
+
diff --git a/gulliver/js/codemirror/mode/php/php.js b/gulliver/js/codemirror/mode/php/php.js
index acc0053d2..946f770c9 100644
--- a/gulliver/js/codemirror/mode/php/php.js
+++ b/gulliver/js/codemirror/mode/php/php.js
@@ -11,168 +11,6 @@
return "string";
};
}
-
- var PM_keywords = function(){
- function PMkey() {return {style: "PMbuiltin"};}
- var PMfunctions = {
- "formatDate":PMkey(), "CurrentDate":PMkey(), "CurrentTime":PMkey(),
- "literalDate":PMkey(), "capitalize":PMkey(), "lowerCase":PMkey(),
- "upperCase":PMkey(), "userInfo":PMkey(), "executeQuery":PMkey(),
- "orderGrid":PMkey(), "evaluateFunction":PMkey(), "PMFTaskCase":PMkey(),
- "PMFTaskList":PMkey(), "PMFUserList":PMkey(), "PMFGroupList":PMkey(),
- "PMFRoleList":PMkey(), "PMFCaseList":PMkey(), "PMFProcessList":PMkey(),
- "PMFSendVariables":PMkey(), "PMFDerivateCase":PMkey(), "PMFNewCaseImpersonate":PMkey(),
- "PMFNewCase":PMkey(), "PMFPauseCase":PMkey(), "PMFUnpauseCase":PMkey(),
- "PMFAssignUserToGroup":PMkey(), "PMFCreateUser":PMkey(), "PMFUpdateUser":PMkey(),
- "PMFInformationUser":PMkey(), "generateCode":PMkey(), "setCaseTrackerCode":PMkey(),
- "jumping":PMkey(), "PMFRedirectToStep":PMkey(), "pauseCase":PMkey(),
- "PMFSendMessage":PMkey(), "PMFgetLabelOption":PMkey(), "PMFGenerateOutputDocument":PMkey(),
- "PMFGetUserEmailAddress":PMkey(), "PMFGetNextAssignedUser":PMkey(), "PMFDeleteCase":PMkey(),
- "PMFCancelCase":PMkey(), "PMFAddInputDocument":PMkey(), "PMFAddCaseNote":PMkey(),
- "PMFGetCaseNotes":PMkey()};
- return PMfunctions;
- }();
-
- var php_keywords = function(){
- function phpbuild() {return {style: "builtin"};}
- function phpatom() {return {style: "atom"};}
- var Phpfunctions = {
- "func_num_args":phpbuild(),"func_get_arg":phpbuild(),"func_get_args":phpbuild(),"strlen":phpbuild(),"strcmp":phpbuild(),
- "strncmp":phpbuild(),"strcasecmp":phpbuild(),"strncasecmp":phpbuild(),"each error_reporting":phpbuild(),"define":phpbuild(),
- "defined":phpbuild(),"trigger_error":phpbuild(),"user_error":phpbuild(),"set_error_handler":phpbuild(),"restore_error_handler":phpbuild(),
- "get_declared_classes":phpbuild(),"get_loaded_extensions":phpbuild(),"extension_loaded":phpbuild(),"get_extension_funcs":phpbuild(),
- "debug_backtrace":phpbuild(),"constant":phpbuild(),"bin2hex":phpbuild(),"sleep":phpbuild(),"usleep":phpbuild(),"time":phpbuild(),
- "mktime":phpbuild(),"gmmktime":phpbuild(),"strftime":phpbuild(),"gmstrftime":phpbuild(),"strtotime":phpbuild(),"date":phpbuild(),
- "gmdate":phpbuild(),"getdate":phpbuild(),"localtime":phpbuild(),"checkdate":phpbuild(),"flush":phpbuild(),"wordwrap":phpbuild(),
- "htmlspecialchars":phpbuild(),"htmlentities":phpbuild(),"html_entity_decode":phpbuild(),"md5":phpbuild(),"md5_file":phpbuild(),
- "crc32 getimagesize":phpbuild(),"image_type_to_mime_type":phpbuild(),"phpinfo":phpbuild(),"phpversion":phpbuild(),
- "phpcredits":phpbuild(),"strnatcmp":phpbuild(),"strnatcasecmp":phpbuild(),"substr_count":phpbuild(),"strspn":phpbuild(),
- "strcspn":phpbuild(),"strtok":phpbuild(),"strtoupper":phpbuild(),"strtolower":phpbuild(),"strpos":phpbuild(),
- "strrpos":phpbuild(),"strrev":phpbuild(),"hebrev":phpbuild(),"hebrevc":phpbuild(),"nl2br":phpbuild(),"basename":phpbuild(),
- "dirname":phpbuild(),"pathinfo":phpbuild(),"stripslashes":phpbuild(),"stripcslashes":phpbuild(),"strstr":phpbuild(),
- "stristr":phpbuild(),"strrchr":phpbuild(),"str_shuffle":phpbuild(),"str_word_count":phpbuild(),"strcoll":phpbuild(),
- "substr":phpbuild(),"substr_replace":phpbuild(),"quotemeta":phpbuild(),"ucfirst":phpbuild(),"ucwords":phpbuild(),
- "strtr":phpbuild(),"addslashes":phpbuild(),"addcslashes":phpbuild(),"rtrim":phpbuild(),"str_replace":phpbuild(),
- "str_repeat":phpbuild(),"count_chars":phpbuild(),"chunk_split":phpbuild(),"trim":phpbuild(),"ltrim":phpbuild(),
- "strip_tags":phpbuild(),"similar_text":phpbuild(),"explode":phpbuild(),"implode":phpbuild(),"setlocale":phpbuild(),
- "localeconv":phpbuild(),"parse_str":phpbuild(),"str_pad":phpbuild(),"chop":phpbuild(),"strchr":phpbuild(),"sprintf":phpbuild(),
- "printf":phpbuild(),"vprintf":phpbuild(),"vsprintf":phpbuild(),"sscanf":phpbuild(),"fscanf":phpbuild(),"parse_url":phpbuild(),
- "urlencode":phpbuild(),"urldecode":phpbuild(),"rawurlencode":phpbuild(),"rawurldecode":phpbuild(),"readlink":phpbuild(),
- "linkinfo":phpbuild(),"link":phpbuild(),"unlink":phpbuild(),"exec":phpbuild(),"system":phpbuild(),"escapeshellcmd":phpbuild(),
- "escapeshellarg":phpbuild(),"passthru":phpbuild(),"shell_exec":phpbuild(),"proc_open":phpbuild(),"proc_close":phpbuild(),
- "rand":phpbuild(),"srand":phpbuild(),"getrandmax":phpbuild(),"mt_rand":phpbuild(),"mt_srand":phpbuild(),
- "mt_getrandmax":phpbuild(),"base64_decode":phpbuild(),"base64_encode":phpbuild(),"abs":phpbuild(),"ceil":phpbuild(),
- "floor":phpbuild(),"round":phpbuild(),"is_finite":phpbuild(),"is_nan":phpbuild(),"is_infinite":phpbuild(),"bindec":phpbuild(),
- "hexdec":phpbuild(),"octdec":phpbuild(),"decbin":phpbuild(),"decoct":phpbuild(),"dechex":phpbuild(),"base_convert":phpbuild(),
- "number_format":phpbuild(),"fmod":phpbuild(),"ip2long":phpbuild(),"long2ip":phpbuild(),"getenv":phpbuild(),"putenv":phpbuild(),
- "getopt":phpbuild(),"microtime":phpbuild(),"gettimeofday":phpbuild(),"getrusage":phpbuild(),"uniqid":phpbuild(),
- "quoted_printable_decode":phpbuild(),"set_time_limit":phpbuild(),"get_cfg_var":phpbuild(),"magic_quotes_runtime":phpbuild(),
- "set_magic_quotes_runtime":phpbuild(),"get_magic_quotes_gpc":phpbuild(),"get_magic_quotes_runtime":phpbuild(),
- "import_request_variables":phpbuild(),"error_log":phpbuild(),"serialize":phpbuild(),"unserialize":phpbuild(),
- "memory_get_usage":phpbuild(),"var_dump":phpbuild(),"var_export":phpbuild(),"debug_zval_dump":phpbuild(),"print_r":phpbuild(),
- "highlight_file":phpbuild(),"show_source":phpbuild(),"highlight_string":phpbuild(),"ini_get":phpbuild(),"ini_get_all":phpbuild(),
- "ini_set":phpbuild(),"ini_alter":phpbuild(),"ini_restore":phpbuild(),"get_include_path":phpbuild(),"set_include_path":phpbuild(),
- "restore_include_path":phpbuild(),"setcookie":phpbuild(),"header":phpbuild(),"headers_sent":phpbuild(),
- "connection_aborted":phpbuild(),"connection_status":phpbuild(),"ignore_user_abort":phpbuild(),"parse_ini_file":phpbuild(),
- "is_uploaded_file":phpbuild(),"move_uploaded_file":phpbuild(),"intval":phpbuild(),"floatval":phpbuild(),"doubleval":phpbuild(),
- "strval":phpbuild(),"gettype":phpbuild(),"settype":phpbuild(),"is_null":phpbuild(),"is_resource":phpbuild(),"is_bool":phpbuild(),
- "is_long":phpbuild(),"is_float":phpbuild(),"is_int":phpbuild(),"is_integer":phpbuild(),"is_double":phpbuild(),
- "is_real":phpbuild(),"is_numeric":phpbuild(),"is_string":phpbuild(),"is_array":phpbuild(),"is_object":phpbuild(),
- "is_scalar":phpbuild(),"ereg":phpbuild(),"ereg_replace":phpbuild(),"eregi":phpbuild(),"eregi_replace":phpbuild(),
- "split":phpbuild(),"spliti":phpbuild(),"join":phpbuild(),"sql_regcase":phpbuild(),"dl":phpbuild(),"pclose":phpbuild(),
- "popen":phpbuild(),"readfile":phpbuild(),"rewind":phpbuild(),"rmdir":phpbuild(),"umask":phpbuild(),"fclose":phpbuild(),
- "feof":phpbuild(),"fgetc":phpbuild(),"fgets":phpbuild(),"fgetss":phpbuild(),"fread":phpbuild(),"fopen":phpbuild(),
- "fpassthru":phpbuild(),"ftruncate":phpbuild(),"fstat":phpbuild(),"fseek":phpbuild(),"ftell":phpbuild(),"fflush":phpbuild(),
- "fwrite":phpbuild(),"fputs":phpbuild(),"mkdir":phpbuild(),"rename":phpbuild(),"copy":phpbuild(),"tempnam":phpbuild(),
- "tmpfile":phpbuild(),"file":phpbuild(),"file_get_contents":phpbuild(),"stream_select":phpbuild(),
- "stream_context_create":phpbuild(),"stream_context_set_params":phpbuild(),"stream_context_set_option":phpbuild(),
- "stream_context_get_options":phpbuild(),"stream_filter_prepend":phpbuild(),"stream_filter_append":phpbuild(),
- "fgetcsv":phpbuild(),"flock":phpbuild(),"get_meta_tags":phpbuild(),"stream_set_write_buffer":phpbuild(),
- "set_file_buffer":phpbuild(),"set_socket_blocking":phpbuild(),"stream_set_blocking":phpbuild(),"socket_set_blocking":phpbuild(),
- "stream_get_meta_data":phpbuild(),"stream_register_wrapper":phpbuild(),"stream_wrapper_register":phpbuild(),
- "stream_set_timeout":phpbuild(),"socket_set_timeout":phpbuild(),"socket_get_status":phpbuild(),"realpath":phpbuild(),
- "fnmatch":phpbuild(),"fsockopen":phpbuild(),"pfsockopen":phpbuild(),"pack":phpbuild(),"unpack":phpbuild(),
- "get_browser":phpbuild(),"crypt":phpbuild(),"opendir":phpbuild(),"closedir":phpbuild(),"chdir":phpbuild(),
- "getcwd":phpbuild(),"rewinddir":phpbuild(),"readdir":phpbuild(),"dir":phpbuild(),"glob":phpbuild(),"fileatime":phpbuild(),
- "filectime":phpbuild(),"filegroup":phpbuild(),"fileinode":phpbuild(),"filemtime":phpbuild(),"fileowner":phpbuild(),
- "fileperms":phpbuild(),"filesize":phpbuild(),"filetype":phpbuild(),"file_exists":phpbuild(),"is_writable":phpbuild(),
- "is_writeable":phpbuild(),"is_readable":phpbuild(),"is_executable":phpbuild(),"is_file":phpbuild(),"is_dir":phpbuild(),
- "is_link":phpbuild(),"stat":phpbuild(),"lstat":phpbuild(),"chown":phpbuild(),"touch":phpbuild(),"clearstatcache":phpbuild(),
- "mail":phpbuild(),"ob_start":phpbuild(),"ob_flush":phpbuild(),"ob_clean":phpbuild(),"ob_end_flush":phpbuild(),
- "ob_end_clean":phpbuild(),"ob_get_flush":phpbuild(),"ob_get_clean":phpbuild(),"ob_get_length":phpbuild(),
- "ob_get_level":phpbuild(),"ob_get_status":phpbuild(),"ob_get_contents":phpbuild(),"ob_implicit_flush":phpbuild(),
- "ob_list_handlers":phpbuild(),"ksort":phpbuild(),"krsort":phpbuild(),"natsort":phpbuild(),"natcasesort":phpbuild(),
- "asort":phpbuild(),"arsort":phpbuild(),"sort":phpbuild(),"rsort":phpbuild(),"usort":phpbuild(),"uasort":phpbuild(),
- "uksort":phpbuild(),"shuffle":phpbuild(),"array_walk":phpbuild(),"count":phpbuild(),"end":phpbuild(),"prev":phpbuild(),
- "next":phpbuild(),"reset":phpbuild(),"current":phpbuild(),"key":phpbuild(),"min":phpbuild(),"max":phpbuild(),
- "in_array":phpbuild(),"array_search":phpbuild(),"extract":phpbuild(),"compact":phpbuild(),"array_fill":phpbuild(),
- "range":phpbuild(),"array_multisort":phpbuild(),"array_push":phpbuild(),"array_pop":phpbuild(),"array_shift":phpbuild(),
- "array_unshift":phpbuild(),"array_splice":phpbuild(),"array_slice":phpbuild(),"array_merge":phpbuild(),
- "array_merge_recursive":phpbuild(),"array_keys":phpbuild(),"array_values":phpbuild(),"array_count_values":phpbuild(),
- "array_reverse":phpbuild(),"array_reduce":phpbuild(),"array_pad":phpbuild(),"array_flip":phpbuild(),
- "array_change_key_case":phpbuild(),"array_rand":phpbuild(),"array_unique":phpbuild(),"array_intersect":phpbuild(),
- "array_intersect_assoc":phpbuild(),"array_diff":phpbuild(),"array_diff_assoc":phpbuild(),"array_sum":phpbuild(),
- "array_filter":phpbuild(),"array_map":phpbuild(),"array_chunk":phpbuild(),"array_key_exists":phpbuild(),"pos":phpbuild(),
- "sizeof":phpbuild(),"key_exists":phpbuild(),"assert":phpbuild(),"assert_options":phpbuild(),"version_compare":phpbuild(),
- "ftok":phpbuild(),"str_rot13":phpbuild(),"aggregate":phpbuild(),"session_name":phpbuild(),"session_module_name":phpbuild(),
- "session_save_path":phpbuild(),"session_id":phpbuild(),"session_regenerate_id":phpbuild(),"session_decode":phpbuild(),
- "session_register":phpbuild(),"session_unregister":phpbuild(),"session_is_registered":phpbuild(),"session_encode":phpbuild(),
- "session_start":phpbuild(),"session_destroy":phpbuild(),"session_unset":phpbuild(),"session_set_save_handler":phpbuild(),
- "session_cache_limiter":phpbuild(),"session_cache_expire":phpbuild(),"session_set_cookie_params":phpbuild(),
- "session_get_cookie_params":phpbuild(),"session_write_close":phpbuild(),"preg_match":phpbuild(),"preg_match_all":phpbuild(),
- "preg_replace":phpbuild(),"preg_replace_callback":phpbuild(),"preg_split":phpbuild(),"preg_quote":phpbuild(),
- "preg_grep":phpbuild(),"overload":phpbuild(),"ctype_alnum":phpbuild(),"ctype_alpha":phpbuild(),"ctype_cntrl":phpbuild(),
- "ctype_digit":phpbuild(),"ctype_lower":phpbuild(),"ctype_graph":phpbuild(),"ctype_print":phpbuild(),"ctype_punct":phpbuild(),
- "ctype_space":phpbuild(),"ctype_upper":phpbuild(),"ctype_xdigit":phpbuild(),"virtual":phpbuild(),
- "apache_request_headers":phpbuild(),"apache_note":phpbuild(),"apache_lookup_uri":phpbuild(),"apache_child_terminate":phpbuild(),
- "apache_setenv":phpbuild(),"apache_response_headers":phpbuild(),"apache_get_version":phpbuild(),
- "getallheaders":phpbuild(),"mysql_connect":phpbuild(),"mysql_pconnect":phpbuild(),"mysql_close":phpbuild(),
- "mysql_select_db":phpbuild(),"mysql_create_db":phpbuild(),"mysql_drop_db":phpbuild(),"mysql_query":phpbuild(),
- "mysql_unbuffered_query":phpbuild(),"mysql_db_query":phpbuild(),"mysql_list_dbs":phpbuild(),"mysql_list_tables":phpbuild(),
- "mysql_list_fields":phpbuild(),"mysql_list_processes":phpbuild(),"mysql_error":phpbuild(),"mysql_errno":phpbuild(),
- "mysql_affected_rows":phpbuild(),"mysql_insert_id":phpbuild(),"mysql_result":phpbuild(),"mysql_num_rows":phpbuild(),
- "mysql_num_fields":phpbuild(),"mysql_fetch_row":phpbuild(),"mysql_fetch_array":phpbuild(),"mysql_fetch_assoc":phpbuild(),
- "mysql_fetch_object":phpbuild(),"mysql_data_seek":phpbuild(),"mysql_fetch_lengths":phpbuild(),"mysql_fetch_field":phpbuild(),
- "mysql_field_seek":phpbuild(),"mysql_free_result":phpbuild(),"mysql_field_name":phpbuild(),"mysql_field_table":phpbuild(),
- "mysql_field_len":phpbuild(),"mysql_field_type":phpbuild(),"mysql_field_flags":phpbuild(),"mysql_escape_string":phpbuild(),
- "mysql_real_escape_string":phpbuild(),"mysql_stat":phpbuild(),"mysql_thread_id":phpbuild(),"mysql_client_encoding":phpbuild(),
- "mysql_get_client_info":phpbuild(),"mysql_get_host_info":phpbuild(),"mysql_get_proto_info":phpbuild(),
- "mysql_get_server_info":phpbuild(),"mysql_info":phpbuild(),"mysql":phpbuild(),"mysql_fieldname":phpbuild(),
- "mysql_fieldtable":phpbuild(),"mysql_fieldlen":phpbuild(),"mysql_fieldtype":phpbuild(),"mysql_fieldflags":phpbuild(),
- "mysql_selectdb":phpbuild(),"mysql_createdb":phpbuild(),"mysql_dropdb":phpbuild(),"mysql_freeresult":phpbuild(),
- "mysql_numfields":phpbuild(),"mysql_numrows":phpbuild(),"mysql_listdbs":phpbuild(),"mysql_listtables":phpbuild(),
- "mysql_listfields":phpbuild(),"mysql_db_name":phpbuild(),"mysql_dbname":phpbuild(),"mysql_tablename":phpbuild(),
- "mysql_table_name":phpbuild(),"pg_connect":phpbuild(),"pg_pconnect":phpbuild(),"pg_close":phpbuild(),
- "pg_connection_status":phpbuild(),"pg_connection_busy":phpbuild(),"pg_connection_reset":phpbuild(),"pg_host":phpbuild(),
- "pg_dbname":phpbuild(),"pg_port":phpbuild(),"pg_tty":phpbuild(),"pg_options":phpbuild(),"pg_ping":phpbuild(),
- "pg_query":phpbuild(),"pg_send_query":phpbuild(),"pg_cancel_query":phpbuild(),"pg_fetch_result":phpbuild(),
- "pg_fetch_row":phpbuild(),"pg_fetch_assoc":phpbuild(),"pg_fetch_array":phpbuild(),"pg_fetch_object":phpbuild(),
- "pg_fetch_all":phpbuild(),"pg_affected_rows":phpbuild(),"pg_get_result":phpbuild(),"pg_result_seek":phpbuild(),
- "pg_result_status":phpbuild(),"pg_free_result":phpbuild(),"pg_last_oid":phpbuild(),"pg_num_rows":phpbuild(),
- "pg_num_fields":phpbuild(),"pg_field_name":phpbuild(),"pg_field_num":phpbuild(),"pg_field_size":phpbuild(),
- "pg_field_type":phpbuild(),"pg_field_prtlen":phpbuild(),"pg_field_is_null":phpbuild(),"pg_get_notify":phpbuild(),
- "pg_get_pid":phpbuild(),"pg_result_error":phpbuild(),"pg_last_error":phpbuild(),"pg_last_notice":phpbuild(),
- "pg_put_line":phpbuild(),"pg_end_copy":phpbuild(),"pg_copy_to":phpbuild(),"pg_copy_from":phpbuild(),"pg_trace":phpbuild(),
- "pg_untrace":phpbuild(),"pg_lo_create":phpbuild(),"pg_lo_unlink":phpbuild(),"pg_lo_open":phpbuild(),"pg_lo_close":phpbuild(),
- "pg_lo_read":phpbuild(),"pg_lo_write":phpbuild(),"pg_lo_read_all":phpbuild(),"pg_lo_import":phpbuild(),"pg_lo_export":phpbuild(),
- "pg_lo_seek":phpbuild(),"pg_lo_tell":phpbuild(),"pg_escape_string":phpbuild(),"pg_escape_bytea":phpbuild(),
- "pg_unescape_bytea":phpbuild(),"pg_client_encoding":phpbuild(),"pg_set_client_encoding":phpbuild(),"pg_meta_data":phpbuild(),
- "pg_convert":phpbuild(),"pg_insert":phpbuild(),"pg_update":phpbuild(),"pg_delete":phpbuild(),"pg_select":phpbuild(),
- "pg_exec":phpbuild(),"pg_getlastoid":phpbuild(),"pg_cmdtuples":phpbuild(),"pg_errormessage":phpbuild(),"pg_numrows":phpbuild(),
- "pg_numfields":phpbuild(),"pg_fieldname":phpbuild(),"pg_fieldsize":phpbuild(),"pg_fieldtype":phpbuild(),"pg_fieldnum":phpbuild(),
- "pg_fieldprtlen":phpbuild(),"pg_fieldisnull":phpbuild(),"pg_freeresult":phpbuild(),"pg_result":phpbuild(),
- "pg_loreadall":phpbuild(),"pg_locreate":phpbuild(),"pg_lounlink":phpbuild(),"pg_loopen":phpbuild(),"pg_loclose":phpbuild(),
- "pg_loread":phpbuild(),"pg_lowrite":phpbuild(),"pg_loimport":phpbuild(),"pg_loexport":phpbuild(),"echo":phpbuild(),
- "print":phpbuild(),"global":phpbuild(),"static":phpbuild(),"exit":phpbuild(),"array":phpbuild(),"empty":phpbuild(),
- "eval":phpbuild(),"isset":phpbuild(),"unset":phpbuild(),"die":phpbuild(),"include":phpbuild(),"require":phpbuild(),
- "include_once":phpbuild(),"require_once":phpbuild(),
- "true":phpatom(),"false":phpatom(),"null":phpatom(),"TRUE":phpatom(),"FALSE":phpatom(),"NULL":phpatom(),
- "__CLASS__":phpatom(),"__DIR__":phpatom(),"__FILE__":phpatom(),"__LINE__":phpatom(),"__METHOD__":phpatom(),
- "__FUNCTION__":phpatom(),"__NAMESPACE__":phpatom()};
- return Phpfunctions;
- }();
-
-
var phpConfig = {
name: "clike",
keywords: keywords("abstract and array as break case catch class clone const continue declare default " +
@@ -180,8 +18,10 @@
"for foreach function global goto if implements interface instanceof namespace " +
"new or private protected public static switch throw trait try use var while xor " +
"die echo empty exit eval include include_once isset list require require_once return " +
- "print unset __halt_compiler self static parent"),
- blockKeywords: keywords("catch do else elseif for foreach if switch try while"),
+ "print unset __halt_compiler self static parent yield insteadof finally"),
+ blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"),
+ atoms: keywords("true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"),
+ builtin: keywords("func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once"),
multiLineStrings: true,
hooks: {
"$": function(stream) {
@@ -200,10 +40,6 @@
while (!stream.eol() && !stream.match("?>", false)) stream.next();
return "comment";
},
- "@": function(stream) {
- stream.eatWhile(/[\w\@@_]/);
- return "variable-3";
- },
"/": function(stream) {
if (stream.eat("/")) {
while (!stream.eol() && !stream.match("?>", false)) stream.next();
@@ -220,21 +56,15 @@
function dispatch(stream, state) {
var isPHP = state.curMode == phpMode;
- if (stream.sol() && state.pending != '"') state.pending = null;
-
+ if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null;
if (!isPHP) {
if (stream.match(/^<\?\w*/)) {
state.curMode = phpMode;
state.curState = state.php;
return "meta";
}
- if( config.PMEnabled == true) {
- state.curMode = phpMode;
- state.curState = state.php;
- return "meta";
- }
- if (state.pending == '"') {
- while (!stream.eol() && stream.next() != '"') {}
+ if (state.pending == '"' || state.pending == "'") {
+ while (!stream.eol() && stream.next() != state.pending) {}
var style = "string";
} else if (state.pending && stream.pos < state.pending.end) {
stream.pos = state.pending.end;
@@ -242,10 +72,10 @@
} else {
var style = htmlMode.token(stream, state.curState);
}
- state.pending = null;
- var cur = stream.current(), openPHP = cur.search(/<\?/);
+ if (state.pending) state.pending = null;
+ var cur = stream.current(), openPHP = cur.search(/<\?/), m;
if (openPHP != -1) {
- if (style == "string" && /\"$/.test(cur) && !/\?>/.test(cur)) state.pending = '"';
+ if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0];
else state.pending = {end: stream.pos, style: style};
stream.backUp(cur.length - openPHP);
}
@@ -255,23 +85,7 @@
state.curState = state.html;
return "meta";
} else {
- var token = phpMode.token(stream, state.curState);
- if(token == "keyword") {
- stream.eatWhile(/[\w\$_]/);
- var word = stream.current();
- known = PM_keywords[word];
- if (known) {
- return known.style;
- }else{
- known = php_keywords[word];
- if (known) {
- return known.style;
- }else{
- return "meta";
- }
- }
- }
- return token;
+ return phpMode.token(stream, state.curState);
}
}
@@ -300,30 +114,12 @@
if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
(state.curMode == phpMode && /^\?>/.test(textAfter)))
return htmlMode.indent(state.html, textAfter);
-
- var firstChar = textAfter && textAfter.charAt(0);
- var lastChar = textAfter && textAfter != "" && textAfter.charAt(textAfter.length - 1);
-
- if (state.curState.context.type == "statement") {
- if (state.curState.context.prev.type == "}") { //{
- return state.curState.context.indented;
- } else {
- if (firstChar == "}") {
- if (lastChar == "{") {
- return state.curState.context.indented - config.indentUnit;
- } else {
- return state.curState.context.indented - state.curState.context.prev.indented;
- }
- } else {
- return state.curState.context.prev.indented;
- }
- }
- } else {
- return state.curMode.indent(state.curState, textAfter);
- }
+ return state.curMode.indent(state.curState, textAfter);
},
- electricChars: "/{}:",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//",
innerMode: function(state) { return {state: state.curState, mode: state.curMode}; }
};
diff --git a/gulliver/js/codemirror/mode/pig/index.html b/gulliver/js/codemirror/mode/pig/index.html
index 1b0c60267..93744ae2d 100644
--- a/gulliver/js/codemirror/mode/pig/index.html
+++ b/gulliver/js/codemirror/mode/pig/index.html
@@ -1,17 +1,29 @@
-
-
-
- CodeMirror: Pig Latin mode
-
-
-
-
-
-
-
- CodeMirror: Pig Latin mode
+CodeMirror: Pig Latin mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Pig Latin mode
-- Apache Pig (Pig Latin Language) Demo
/*
@@ -40,3 +52,4 @@ STORE c INTO "\path\to\output";
MIME type defined: text/x-pig
(PIG code)
+
diff --git a/gulliver/js/codemirror/mode/pig/pig.js b/gulliver/js/codemirror/mode/pig/pig.js
index f8818a9b6..4b44e7ccc 100644
--- a/gulliver/js/codemirror/mode/pig/pig.js
+++ b/gulliver/js/codemirror/mode/pig/pig.js
@@ -1,171 +1,171 @@
/*
- * Pig Latin Mode for CodeMirror 2
- * @author Prasanth Jayachandran
- * @link https://github.com/prasanthj/pig-codemirror-2
+ * Pig Latin Mode for CodeMirror 2
+ * @author Prasanth Jayachandran
+ * @link https://github.com/prasanthj/pig-codemirror-2
* This implementation is adapted from PL/SQL mode in CodeMirror 2.
-*/
+ */
CodeMirror.defineMode("pig", function(_config, parserConfig) {
- var keywords = parserConfig.keywords,
- builtins = parserConfig.builtins,
- types = parserConfig.types,
- multiLineStrings = parserConfig.multiLineStrings;
-
- var isOperatorChar = /[*+\-%<>=&?:\/!|]/;
-
- function chain(stream, state, f) {
- state.tokenize = f;
- return f(stream, state);
- }
-
- var type;
- function ret(tp, style) {
- type = tp;
- return style;
- }
-
- function tokenComment(stream, state) {
- var isEnd = false;
- var ch;
- while(ch = stream.next()) {
- if(ch == "/" && isEnd) {
- state.tokenize = tokenBase;
- break;
- }
- isEnd = (ch == "*");
- }
- return ret("comment", "comment");
- }
-
- function tokenString(quote) {
- return function(stream, state) {
- var escaped = false, next, end = false;
- while((next = stream.next()) != null) {
- if (next == quote && !escaped) {
- end = true; break;
- }
- escaped = !escaped && next == "\\";
- }
- if (end || !(escaped || multiLineStrings))
- state.tokenize = tokenBase;
- return ret("string", "error");
- };
- }
-
- function tokenBase(stream, state) {
- var ch = stream.next();
-
- // is a start of string?
- if (ch == '"' || ch == "'")
- return chain(stream, state, tokenString(ch));
- // is it one of the special chars
- else if(/[\[\]{}\(\),;\.]/.test(ch))
- return ret(ch);
- // is it a number?
- else if(/\d/.test(ch)) {
- stream.eatWhile(/[\w\.]/);
- return ret("number", "number");
- }
- // multi line comment or operator
- else if (ch == "/") {
- if (stream.eat("*")) {
- return chain(stream, state, tokenComment);
- }
- else {
- stream.eatWhile(isOperatorChar);
- return ret("operator", "operator");
- }
- }
- // single line comment or operator
- else if (ch=="-") {
- if(stream.eat("-")){
- stream.skipToEnd();
- return ret("comment", "comment");
- }
- else {
- stream.eatWhile(isOperatorChar);
- return ret("operator", "operator");
- }
- }
- // is it an operator
- else if (isOperatorChar.test(ch)) {
- stream.eatWhile(isOperatorChar);
- return ret("operator", "operator");
- }
- else {
- // get the while word
- stream.eatWhile(/[\w\$_]/);
- // is it one of the listed keywords?
- if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {
- if (stream.eat(")") || stream.eat(".")) {
- //keywords can be used as variables like flatten(group), group.$0 etc..
- }
- else {
- return ("keyword", "keyword");
- }
- }
- // is it one of the builtin functions?
- if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))
- {
- return ("keyword", "variable-2");
- }
- // is it one of the listed types?
- if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))
- return ("keyword", "variable-3");
- // default is a 'variable'
- return ret("variable", "pig-word");
- }
- }
-
- // Interface
- return {
- startState: function() {
- return {
- tokenize: tokenBase,
- startOfLine: true
- };
- },
-
- token: function(stream, state) {
- if(stream.eatSpace()) return null;
- var style = state.tokenize(stream, state);
- return style;
- }
- };
+ var keywords = parserConfig.keywords,
+ builtins = parserConfig.builtins,
+ types = parserConfig.types,
+ multiLineStrings = parserConfig.multiLineStrings;
+
+ var isOperatorChar = /[*+\-%<>=&?:\/!|]/;
+
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
+
+ var type;
+ function ret(tp, style) {
+ type = tp;
+ return style;
+ }
+
+ function tokenComment(stream, state) {
+ var isEnd = false;
+ var ch;
+ while(ch = stream.next()) {
+ if(ch == "/" && isEnd) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ isEnd = (ch == "*");
+ }
+ return ret("comment", "comment");
+ }
+
+ function tokenString(quote) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while((next = stream.next()) != null) {
+ if (next == quote && !escaped) {
+ end = true; break;
+ }
+ escaped = !escaped && next == "\\";
+ }
+ if (end || !(escaped || multiLineStrings))
+ state.tokenize = tokenBase;
+ return ret("string", "error");
+ };
+ }
+
+ function tokenBase(stream, state) {
+ var ch = stream.next();
+
+ // is a start of string?
+ if (ch == '"' || ch == "'")
+ return chain(stream, state, tokenString(ch));
+ // is it one of the special chars
+ else if(/[\[\]{}\(\),;\.]/.test(ch))
+ return ret(ch);
+ // is it a number?
+ else if(/\d/.test(ch)) {
+ stream.eatWhile(/[\w\.]/);
+ return ret("number", "number");
+ }
+ // multi line comment or operator
+ else if (ch == "/") {
+ if (stream.eat("*")) {
+ return chain(stream, state, tokenComment);
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // single line comment or operator
+ else if (ch=="-") {
+ if(stream.eat("-")){
+ stream.skipToEnd();
+ return ret("comment", "comment");
+ }
+ else {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ }
+ // is it an operator
+ else if (isOperatorChar.test(ch)) {
+ stream.eatWhile(isOperatorChar);
+ return ret("operator", "operator");
+ }
+ else {
+ // get the while word
+ stream.eatWhile(/[\w\$_]/);
+ // is it one of the listed keywords?
+ if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) {
+ if (stream.eat(")") || stream.eat(".")) {
+ //keywords can be used as variables like flatten(group), group.$0 etc..
+ }
+ else {
+ return ("keyword", "keyword");
+ }
+ }
+ // is it one of the builtin functions?
+ if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase()))
+ {
+ return ("keyword", "variable-2");
+ }
+ // is it one of the listed types?
+ if (types && types.propertyIsEnumerable(stream.current().toUpperCase()))
+ return ("keyword", "variable-3");
+ // default is a 'variable'
+ return ret("variable", "pig-word");
+ }
+ }
+
+ // Interface
+ return {
+ startState: function() {
+ return {
+ tokenize: tokenBase,
+ startOfLine: true
+ };
+ },
+
+ token: function(stream, state) {
+ if(stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ }
+ };
});
(function() {
- function keywords(str) {
- var obj = {}, words = str.split(" ");
- for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
- return obj;
- }
+ function keywords(str) {
+ var obj = {}, words = str.split(" ");
+ for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+ return obj;
+ }
- // builtin funcs taken from trunk revision 1303237
- var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
- + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
- + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
- + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
- + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
- + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
- + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
- + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
- + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
- + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER ";
-
- // taken from QueryLexer.g
- var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
- + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
- + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
- + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
- + "NEQ MATCHES TRUE FALSE ";
-
- // data types
- var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP ";
-
- CodeMirror.defineMIME("text/x-pig", {
- name: "pig",
- builtins: keywords(pBuiltins),
- keywords: keywords(pKeywords),
- types: keywords(pTypes)
- });
+ // builtin funcs taken from trunk revision 1303237
+ var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
+ + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
+ + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
+ + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
+ + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
+ + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
+ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
+ + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
+ + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
+ + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER ";
+
+ // taken from QueryLexer.g
+ var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
+ + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
+ + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
+ + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
+ + "NEQ MATCHES TRUE FALSE DUMP";
+
+ // data types
+ var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP ";
+
+ CodeMirror.defineMIME("text/x-pig", {
+ name: "pig",
+ builtins: keywords(pBuiltins),
+ keywords: keywords(pKeywords),
+ types: keywords(pTypes)
+ });
}());
diff --git a/gulliver/js/codemirror/mode/properties/index.html b/gulliver/js/codemirror/mode/properties/index.html
index e21e02abd..40ee1a37b 100644
--- a/gulliver/js/codemirror/mode/properties/index.html
+++ b/gulliver/js/codemirror/mode/properties/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Properties files mode
-
-
-
-
-
-
-
- CodeMirror: Properties files mode
-
+
+CodeMirror: Properties files mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Properties files mode
+
# This is a properties file
a.key = A value
another.key = http://example.com
@@ -37,5 +50,4 @@ spaces\ in\ keys=Not very common...
MIME types defined: text/x-properties,
text/x-ini.
-
-
+
diff --git a/gulliver/js/codemirror/mode/python/LICENSE.txt b/gulliver/js/codemirror/mode/python/LICENSE.txt
deleted file mode 100644
index 918866b42..000000000
--- a/gulliver/js/codemirror/mode/python/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2010 Timothy Farrell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
\ No newline at end of file
diff --git a/gulliver/js/codemirror/mode/python/index.html b/gulliver/js/codemirror/mode/python/index.html
index 4244c6fc5..e8422fb77 100644
--- a/gulliver/js/codemirror/mode/python/index.html
+++ b/gulliver/js/codemirror/mode/python/index.html
@@ -1,18 +1,31 @@
-
-
-
- CodeMirror: Python mode
-
-
-
-
-
-
-
-
- CodeMirror: Python mode
-
+
+CodeMirror: Python mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Python mode
+
# Literals
1234
@@ -102,6 +115,34 @@ class ExampleClass(ParentClass):
self.mixin = mixin
+
+
+Cython mode
+
+
+
+import numpy as np
+cimport cython
+from libc.math cimport sqrt
+
+@cython.boundscheck(False)
+@cython.wraparound(False)
+def pairwise_cython(double[:, ::1] X):
+ cdef int M = X.shape[0]
+ cdef int N = X.shape[1]
+ cdef double tmp, d
+ cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64)
+ for i in range(M):
+ for j in range(M):
+ d = 0.0
+ for k in range(N):
+ tmp = X[i, k] - X[j, k]
+ d += tmp * tmp
+ D[i, j] = sqrt(d)
+ return np.asarray(D)
+
+
+
- Configuration Options:
+ Configuration Options for Python mode:
version - 2/3 - The version of Python to recognize. Default is 2.
singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.
+ hangingIndent - int - If you want to write long arguments to a function starting on a new line, how much that line should be indented. Defaults to one normal indentation unit.
Advanced Configuration Options:
Usefull for superset of python syntax like Enthought enaml, IPython magics and questionmark help
@@ -127,9 +179,10 @@ class ExampleClass(ParentClass):
doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default : ^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default : ^((//=)|(>>=)|(<<=)|(\\*\\*=))
identifiers - RegEx - Regular Expression for identifier, default : ^[_A-Za-z][_A-Za-z0-9]*
+ extra_keywords - list of string - List of extra words ton consider as keywords
+ extra_builtins - list of string - List of extra words ton consider as builtins
- MIME types defined: text/x-python.
-
-
+ MIME types defined: text/x-python and text/x-cython.
+
diff --git a/gulliver/js/codemirror/mode/python/python.js b/gulliver/js/codemirror/mode/python/python.js
index 951aaf819..8bea5d19d 100644
--- a/gulliver/js/codemirror/mode/python/python.js
+++ b/gulliver/js/codemirror/mode/python/python.js
@@ -4,13 +4,14 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b");
}
-
+
var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
+ var hangingIndent = parserConf.hangingIndent || parserConf.indentUnit;
var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
@@ -36,6 +37,12 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'],
'keywords': ['nonlocal', 'False', 'True', 'None']};
+ if(parserConf.extra_keywords != undefined){
+ commonkeywords = commonkeywords.concat(parserConf.extra_keywords);
+ }
+ if(parserConf.extra_builtins != undefined){
+ commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins);
+ }
if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
commonkeywords = commonkeywords.concat(py3.keywords);
commonBuiltins = commonBuiltins.concat(py3.builtins);
@@ -72,15 +79,15 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
if (stream.eatSpace()) {
return null;
}
-
+
var ch = stream.peek();
-
+
// Handle Comments
if (ch === '#') {
stream.skipToEnd();
return 'comment';
}
-
+
// Handle Number Literals
if (stream.match(/^[0-9\.]/, false)) {
var floatLiteral = false;
@@ -116,13 +123,13 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
return 'number';
}
}
-
+
// Handle Strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
}
-
+
// Handle operators and Delimiters
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
return null;
@@ -135,31 +142,34 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
if (stream.match(singleDelimiters)) {
return null;
}
-
+
if (stream.match(keywords)) {
return 'keyword';
}
-
+
if (stream.match(builtins)) {
return 'builtin';
}
-
+
if (stream.match(identifiers)) {
+ if (state.lastToken == 'def' || state.lastToken == 'class') {
+ return 'def';
+ }
return 'variable';
}
-
+
// Handle non-detected items
stream.next();
return ERRORCLASS;
}
-
+
function tokenStringFactory(delimiter) {
while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
delimiter = delimiter.substr(1);
}
var singleline = delimiter.length == 1;
var OUTCLASS = 'string';
-
+
function tokenString(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^'"\\]/);
@@ -187,7 +197,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
tokenString.isString = true;
return tokenString;
}
-
+
function indent(stream, state, type) {
type = type || 'py';
var indentUnit = 0;
@@ -202,6 +212,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
break;
}
}
+ } else if (stream.match(/\s*($|#)/, false)) {
+ // An open paren/bracket/brace with only space or comments after it
+ // on the line will indent the next line a fixed amount, to make it
+ // easier to put arguments, list items, etc. on their own lines.
+ indentUnit = stream.indentation() + hangingIndent;
} else {
indentUnit = stream.column() + stream.current().length;
}
@@ -210,7 +225,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
type: type
});
}
-
+
function dedent(stream, state, type) {
type = type || 'py';
if (state.scopes.length == 1) return;
@@ -252,24 +267,24 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
// Handle '.' connected identifiers
if (current === '.') {
style = stream.match(identifiers, false) ? null : ERRORCLASS;
- if (style === null && state.lastToken === 'meta') {
+ if (style === null && state.lastStyle === 'meta') {
// Apply 'meta' style to '.' connected identifiers when
// appropriate.
style = 'meta';
}
return style;
}
-
+
// Handle decorators
if (current === '@') {
return stream.match(identifiers, false) ? 'meta' : ERRORCLASS;
}
if ((style === 'variable' || style === 'builtin')
- && state.lastToken === 'meta') {
+ && state.lastStyle === 'meta') {
style = 'meta';
}
-
+
// Handle scope changes.
if (current === 'pass' || current === 'return') {
state.dedent += 1;
@@ -298,7 +313,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
if (state.scopes.length > 1) state.scopes.shift();
state.dedent -= 1;
}
-
+
return style;
}
@@ -307,34 +322,53 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
return {
tokenize: tokenBase,
scopes: [{offset:basecolumn || 0, type:'py'}],
+ lastStyle: null,
lastToken: null,
lambda: false,
dedent: 0
};
},
-
+
token: function(stream, state) {
var style = tokenLexer(stream, state);
-
- state.lastToken = style;
-
- if (stream.eol() && stream.lambda) {
+
+ state.lastStyle = style;
+
+ var current = stream.current();
+ if (current && style) {
+ state.lastToken = current;
+ }
+
+ if (stream.eol() && state.lambda) {
state.lambda = false;
}
-
return style;
},
-
+
indent: function(state) {
if (state.tokenize != tokenBase) {
return state.tokenize.isString ? CodeMirror.Pass : 0;
}
-
+
return state.scopes[0].offset;
- }
-
+ },
+
+ lineComment: "#",
+ fold: "indent"
};
return external;
});
CodeMirror.defineMIME("text/x-python", "python");
+
+(function() {
+ "use strict";
+ var words = function(str){return str.split(' ');};
+
+ CodeMirror.defineMIME("text/x-cython", {
+ name: "python",
+ extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
+ "extern gil include nogil property public"+
+ "readonly struct union DEF IF ELIF ELSE")
+ });
+})();
diff --git a/gulliver/js/codemirror/mode/q/index.html b/gulliver/js/codemirror/mode/q/index.html
index 303ec1d3a..78ed3d88f 100644
--- a/gulliver/js/codemirror/mode/q/index.html
+++ b/gulliver/js/codemirror/mode/q/index.html
@@ -1,17 +1,31 @@
-
-
-
- CodeMirror: Q mode
-
-
-
-
-
-
-
-
- CodeMirror: Q mode
+
+CodeMirror: Q mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Q mode
+
/ utilities to quickly load a csv file - for more exhaustive analysis of the csv contents see csvguess.q
@@ -127,5 +141,4 @@ bulkload:{[file;info]
MIME type defined: text/x-q.
-
-
+
diff --git a/gulliver/js/codemirror/mode/q/q.js b/gulliver/js/codemirror/mode/q/q.js
index 6fc4e65a9..56017e30a 100644
--- a/gulliver/js/codemirror/mode/q/q.js
+++ b/gulliver/js/codemirror/mode/q/q.js
@@ -17,7 +17,7 @@ CodeMirror.defineMode("q",function(config){
return state.tokenize=tokenBase,"builtin";
}
if(/\s/.test(c))
- return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace";
+ return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace";
if(c=='"')
return(state.tokenize=tokenString)(stream,state);
if(c=='`')
diff --git a/gulliver/js/codemirror/mode/r/LICENSE b/gulliver/js/codemirror/mode/r/LICENSE
deleted file mode 100644
index 2510ae16c..000000000
--- a/gulliver/js/codemirror/mode/r/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2011, Ubalo, Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Ubalo, Inc nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL UBALO, INC BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gulliver/js/codemirror/mode/r/index.html b/gulliver/js/codemirror/mode/r/index.html
index 12819553e..f73e13d62 100644
--- a/gulliver/js/codemirror/mode/r/index.html
+++ b/gulliver/js/codemirror/mode/r/index.html
@@ -1,23 +1,36 @@
-
-
-
- CodeMirror: R mode
-
-
-
-
-
-
-
- CodeMirror: R mode
-
+
+
+
+
+
+
+
+
+R mode
+
# Code from http://www.mayin.org/ajayshah/KB/R/
# FIRST LEARN ABOUT LISTS --
@@ -70,5 +83,4 @@ powerful <- function(x) {list(x2=x*x, x3=x*x*x, x4=x*x*x*x)}
by Ubalo , who hold
the license .
-
-
+
diff --git a/gulliver/js/codemirror/mode/r/r.js b/gulliver/js/codemirror/mode/r/r.js
index 6410efbb2..690cf4050 100644
--- a/gulliver/js/codemirror/mode/r/r.js
+++ b/gulliver/js/codemirror/mode/r/r.js
@@ -36,7 +36,11 @@ CodeMirror.defineMode("r", function(config) {
var word = stream.current();
if (atoms.propertyIsEnumerable(word)) return "atom";
if (keywords.propertyIsEnumerable(word)) {
- if (blockkeywords.propertyIsEnumerable(word)) curPunc = "block";
+ // Block keywords start new blocks, except 'else if', which only starts
+ // one new block for the 'if', no block for the 'else'.
+ if (blockkeywords.propertyIsEnumerable(word) &&
+ !stream.match(/\s*if(\s+|$)/, false))
+ curPunc = "block";
return "keyword";
}
if (builtins.propertyIsEnumerable(word)) return "builtin";
diff --git a/gulliver/js/codemirror/mode/rpm/changes/index.html b/gulliver/js/codemirror/mode/rpm/changes/index.html
index e0e2d8778..18fe7ab7b 100644
--- a/gulliver/js/codemirror/mode/rpm/changes/index.html
+++ b/gulliver/js/codemirror/mode/rpm/changes/index.html
@@ -1,17 +1,32 @@
-
-
-
- CodeMirror: RPM changes mode
+
+CodeMirror: RPM changes mode
+
+
+
-
-
- CodeMirror: RPM changes mode
-
+
+
+
+
+
+
+
+
+
+RPM changes mode
+
-------------------------------------------------------------------
Tue Oct 18 13:58:40 UTC 2011 - misterx@example.com
@@ -49,5 +64,4 @@ Wed Oct 5 14:34:10 UTC 2011 - misterx@example.com
MIME types defined: text/x-rpm-changes.
-
-
+
diff --git a/gulliver/js/codemirror/mode/rpm/spec/index.html b/gulliver/js/codemirror/mode/rpm/spec/index.html
index 8be98b63e..127b72ee9 100644
--- a/gulliver/js/codemirror/mode/rpm/spec/index.html
+++ b/gulliver/js/codemirror/mode/rpm/spec/index.html
@@ -1,17 +1,32 @@
-
-
-
- CodeMirror: RPM spec mode
+
+CodeMirror: RPM spec mode
+
+
+
-
-
- CodeMirror: RPM spec mode
+
+
+
+
+
+
+
+
+
+RPM spec mode
#
@@ -95,5 +110,5 @@ find %{buildroot} -type f -name '*.la' -exec rm -f {} ';'
MIME types defined: text/x-rpm-spec.
-
-
+
+
diff --git a/gulliver/js/codemirror/mode/rpm/spec/spec.js b/gulliver/js/codemirror/mode/rpm/spec/spec.js
index 9f339c21b..0fab6c489 100644
--- a/gulliver/js/codemirror/mode/rpm/spec/spec.js
+++ b/gulliver/js/codemirror/mode/rpm/spec/spec.js
@@ -4,7 +4,7 @@ CodeMirror.defineMode("spec", function() {
var arch = /^(i386|i586|i686|x86_64|ppc64|ppc|ia64|s390x|s390|sparc64|sparcv9|sparc|noarch|alphaev6|alpha|hppa|mipsel)/;
var preamble = /^(Name|Version|Release|License|Summary|Url|Group|Source|BuildArch|BuildRequires|BuildRoot|AutoReqProv|Provides|Requires(\(\w+\))?|Obsoletes|Conflicts|Recommends|Source\d*|Patch\d*|ExclusiveArch|NoSource|Supplements):/;
- var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preun|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/;
+ var section = /^%(debug_package|package|description|prep|build|install|files|clean|changelog|preinstall|preun|postinstall|postun|pre|post|triggerin|triggerun|pretrans|posttrans|verifyscript|check|triggerpostun|triggerprein|trigger)/;
var control_flow_complex = /^%(ifnarch|ifarch|if)/; // rpm control flow macros
var control_flow_simple = /^%(else|endif)/; // rpm control flow macros
var operators = /^(\!|\?|\<\=|\<|\>\=|\>|\=\=|\&\&|\|\|)/; // operators in control flow macros
diff --git a/gulliver/js/codemirror/mode/rst/LICENSE.txt b/gulliver/js/codemirror/mode/rst/LICENSE.txt
deleted file mode 100644
index 39484fabb..000000000
--- a/gulliver/js/codemirror/mode/rst/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2013 Hasan Karahan
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
\ No newline at end of file
diff --git a/gulliver/js/codemirror/mode/rst/index.html b/gulliver/js/codemirror/mode/rst/index.html
index b3ab64b80..78030ebe9 100644
--- a/gulliver/js/codemirror/mode/rst/index.html
+++ b/gulliver/js/codemirror/mode/rst/index.html
@@ -1,17 +1,29 @@
-
-
-
- CodeMirror: reStructuredText mode
-
-
-
-
-
-
-
- CodeMirror: reStructuredText mode
+CodeMirror: reStructuredText mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+reStructuredText mode
.. This is an excerpt from Sphinx documentation: http://sphinx.pocoo.org/_sources/rest.txt
@@ -519,6 +531,4 @@ There are some problems one commonly runs into while authoring reST documents:
MIME types defined: text/x-rst.
-
-
-
+
diff --git a/gulliver/js/codemirror/mode/rst/rst.js b/gulliver/js/codemirror/mode/rst/rst.js
index 5fed967a6..75563ba98 100644
--- a/gulliver/js/codemirror/mode/rst/rst.js
+++ b/gulliver/js/codemirror/mode/rst/rst.js
@@ -36,9 +36,11 @@ CodeMirror.defineMode('rst-base', function (config) {
var TAIL = "(?:\\s*|\\W|$)",
rx_TAIL = new RegExp(format('^{0}', TAIL));
- var NAME = "(?:[^\\W\\d_](?:[\\w\\+\\.\\-:]*[^\\W_])?)",
+ var NAME =
+ "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)",
rx_NAME = new RegExp(format('^{0}', NAME));
- var NAME_WWS = "(?:[^\\W\\d_](?:[\\w\\s\\+\\.\\-:]*[^\\W_])?)";
+ var NAME_WWS =
+ "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)";
var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);
var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)";
@@ -122,9 +124,7 @@ CodeMirror.defineMode('rst-base', function (config) {
token = 'keyword';
if (stream.current().match(/^(?:math|latex)/)) {
- state.tmp = {
- mode: mode_stex, local: mode_stex.startState()
- };
+ state.tmp_stex = true;
}
break;
case 2:
@@ -133,6 +133,12 @@ CodeMirror.defineMode('rst-base', function (config) {
token = 'meta';
break;
case 3:
+ if (state.tmp_stex) {
+ state.tmp_stex = undefined; state.tmp = {
+ mode: mode_stex, local: mode_stex.startState()
+ };
+ }
+
if (state.tmp) {
if (stream.peek() == '`') {
change(state, to_normal, context(rx_role_pre, 4));
@@ -343,24 +349,24 @@ CodeMirror.defineMode('rst-base', function (config) {
change(state, to_explicit, context(rx_directive, 2));
assert(stream.match(rx_directive_tail));
token = 'meta';
- break;
- default:
+
if (stream.match(/^latex\s*$/) || state.tmp_stex) {
- state.tmp_stex = undefined;
- change(state, to_mode, {
+ state.tmp_stex = undefined; change(state, to_mode, {
mode: mode_stex, local: mode_stex.startState()
});
- } else if (stream.match(/^python\s*$/) || state.tmp_py) {
- state.tmp_py = undefined;
- change(state, to_mode, {
+ }
+ break;
+ case 2:
+ change(state, to_explicit, context(rx_directive, 3));
+ if (stream.match(/^python\s*$/) || state.tmp_py) {
+ state.tmp_py = undefined; change(state, to_mode, {
mode: mode_python, local: mode_python.startState()
});
}
-
- else {
- change(state, to_normal);
- assert(stream.current() == '');
- }
+ break;
+ default:
+ change(state, to_normal);
+ assert(stream.current() == '');
}
} else if (phase(state) == rx_link || stream.match(rx_link, false)) {
@@ -435,12 +441,7 @@ CodeMirror.defineMode('rst-base', function (config) {
return null;
}
- try {
- return state.ctx.mode.token(stream, state.ctx.local);
- } catch (ex) {
- change(state, to_normal);
- return null;
- }
+ return state.ctx.mode.token(stream, state.ctx.local);
}
change(state, to_normal);
@@ -480,7 +481,9 @@ CodeMirror.defineMode('rst-base', function (config) {
},
innerMode: function (state) {
- return {state: state.ctx.local, mode: state.ctx.mode};
+ return state.tmp ? {state: state.tmp.local, mode: state.tmp.mode}
+ : state.ctx ? {state: state.ctx.local, mode: state.ctx.mode}
+ : null;
},
token: function (stream, state) {
@@ -494,13 +497,6 @@ CodeMirror.defineMode('rst-base', function (config) {
CodeMirror.defineMode('rst', function (config, options) {
- var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://";
- var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})";
- var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*";
- var rx_uri = new RegExp("^" +
- rx_uri_protocol + rx_uri_domain + rx_uri_path
- );
-
var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/;
var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/;
@@ -509,25 +505,39 @@ CodeMirror.defineMode('rst', function (config, options) {
var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
+ var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://";
+ var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})";
+ var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*";
+ var rx_uri = new RegExp("^" +
+ rx_uri_protocol + rx_uri_domain + rx_uri_path
+ );
+
var overlay = {
token: function (stream) {
- if (stream.match(rx_uri)) return 'link';
- if (stream.match(rx_strong)) return 'strong';
- if (stream.match(rx_emphasis)) return 'em';
- if (stream.match(rx_literal)) return 'string-2';
- if (stream.match(rx_number)) return 'number';
- if (stream.match(rx_positive)) return 'positive';
- if (stream.match(rx_negative)) return 'negative';
+ if (stream.match(rx_strong) && stream.match (/\W+|$/, false))
+ return 'strong';
+ if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false))
+ return 'em';
+ if (stream.match(rx_literal) && stream.match (/\W+|$/, false))
+ return 'string-2';
+ if (stream.match(rx_number))
+ return 'number';
+ if (stream.match(rx_positive))
+ return 'positive';
+ if (stream.match(rx_negative))
+ return 'negative';
+ if (stream.match(rx_uri))
+ return 'link';
while (stream.next() != null) {
- if (stream.match(rx_uri, false)) break;
if (stream.match(rx_strong, false)) break;
if (stream.match(rx_emphasis, false)) break;
if (stream.match(rx_literal, false)) break;
if (stream.match(rx_number, false)) break;
if (stream.match(rx_positive, false)) break;
if (stream.match(rx_negative, false)) break;
+ if (stream.match(rx_uri, false)) break;
}
return null;
diff --git a/gulliver/js/codemirror/mode/ruby/LICENSE b/gulliver/js/codemirror/mode/ruby/LICENSE
deleted file mode 100644
index ac09fc403..000000000
--- a/gulliver/js/codemirror/mode/ruby/LICENSE
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2011, Ubalo, Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Ubalo, Inc. nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL UBALO, INC BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gulliver/js/codemirror/mode/ruby/index.html b/gulliver/js/codemirror/mode/ruby/index.html
index 64cfe5ef3..2b3e1a3eb 100644
--- a/gulliver/js/codemirror/mode/ruby/index.html
+++ b/gulliver/js/codemirror/mode/ruby/index.html
@@ -1,21 +1,34 @@
-
-
-
- CodeMirror: Ruby mode
-
-
-
-
-
-
-
-
- CodeMirror: Ruby mode
-
+
+
+
+
+
+
+
+
+Ruby mode
+
# Code from http://sandbox.mc.edu/~bennet/ruby/code/poly_rb.html
#
# This program evaluates polynomials. It first asks for the coefficients
@@ -169,5 +182,4 @@ end
by Ubalo , who hold
the license .
-
-
+
diff --git a/gulliver/js/codemirror/mode/ruby/ruby.js b/gulliver/js/codemirror/mode/ruby/ruby.js
index d106a542d..1cdc9a4e4 100644
--- a/gulliver/js/codemirror/mode/ruby/ruby.js
+++ b/gulliver/js/codemirror/mode/ruby/ruby.js
@@ -10,9 +10,9 @@ CodeMirror.defineMode("ruby", function(config) {
"redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
"until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
"caller", "lambda", "proc", "public", "protected", "private", "require", "load",
- "require_relative", "extend", "autoload"
+ "require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__"
]);
- var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then",
+ var indentWords = wordObj(["def", "class", "case", "for", "while", "module", "then",
"catch", "loop", "proc", "begin"]);
var dedentWords = wordObj(["end", "until"]);
var matching = {"[": "]", "{": "}", "(": ")"};
@@ -31,14 +31,16 @@ CodeMirror.defineMode("ruby", function(config) {
}
if (stream.eatSpace()) return null;
var ch = stream.next(), m;
- if (ch == "`" || ch == "'" || ch == '"' ||
- (ch == "/" && !stream.eol() && stream.peek() != " ")) {
+ if (ch == "`" || ch == "'" || ch == '"') {
return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
+ } else if (ch == "/" && !stream.eol() && stream.peek() != " ") {
+ return chain(readQuoted(ch, "string-2", true), stream, state);
} else if (ch == "%") {
- var style, embed = false;
+ var style = "string", embed = true;
if (stream.eat("s")) style = "atom";
- else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; }
- else if (stream.eat(/[wxqr]/)) style = "string";
+ else if (stream.eat(/[WQ]/)) style = "string";
+ else if (stream.eat(/[r]/)) style = "string-2";
+ else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; }
var delim = stream.eat(/[^\w\s]/);
if (!delim) return "operator";
if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
@@ -64,18 +66,42 @@ CodeMirror.defineMode("ruby", function(config) {
} else if (ch == ":") {
if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
- stream.eatWhile(/[\w\?]/);
- return "atom";
- } else if (ch == "@") {
+
+ // :> :>> :< :<< are valid symbols
+ if (stream.eat(/[\<\>]/)) {
+ stream.eat(/[\<\>]/);
+ return "atom";
+ }
+
+ // :+ :- :/ :* :| :& :! are valid symbols
+ if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) {
+ return "atom";
+ }
+
+ // Symbols can't start by a digit
+ if (stream.eat(/[a-zA-Z$@_]/)) {
+ stream.eatWhile(/[\w]/);
+ // Only one ? ! = is allowed and only as the last character
+ stream.eat(/[\?\!\=]/);
+ return "atom";
+ }
+ return "operator";
+ } else if (ch == "@" && stream.match(/^@?[a-zA-Z_]/)) {
stream.eat("@");
- stream.eatWhile(/[\w\?]/);
+ stream.eatWhile(/[\w]/);
return "variable-2";
} else if (ch == "$") {
- stream.next();
- stream.eatWhile(/[\w\?]/);
+ if (stream.eat(/[a-zA-Z_]/)) {
+ stream.eatWhile(/[\w]/);
+ } else if (stream.eat(/\d/)) {
+ stream.eat(/\d/);
+ } else {
+ stream.next(); // Must be a special global like $: or $!
+ }
return "variable-3";
- } else if (/\w/.test(ch)) {
- stream.eatWhile(/[\w\?]/);
+ } else if (/[a-zA-Z_]/.test(ch)) {
+ stream.eatWhile(/[\w]/);
+ stream.eat(/[\?\!]/);
if (stream.eat(":")) return "atom";
return "ident";
} else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
@@ -109,17 +135,42 @@ CodeMirror.defineMode("ruby", function(config) {
return tokenBase(stream, state);
};
}
+ function tokenBaseOnce() {
+ var alreadyCalled = false;
+ return function(stream, state) {
+ if (alreadyCalled) {
+ state.tokenize.pop();
+ return state.tokenize[state.tokenize.length-1](stream, state);
+ }
+ alreadyCalled = true;
+ return tokenBase(stream, state);
+ };
+ }
function readQuoted(quote, style, embed, unescaped) {
return function(stream, state) {
var escaped = false, ch;
+
+ if (state.context.type === 'read-quoted-paused') {
+ state.context = state.context.prev;
+ stream.eat("}");
+ }
+
while ((ch = stream.next()) != null) {
if (ch == quote && (unescaped || !escaped)) {
state.tokenize.pop();
break;
}
- if (embed && ch == "#" && !escaped && stream.eat("{")) {
- state.tokenize.push(tokenBaseUntilBrace(arguments.callee));
- break;
+ if (embed && ch == "#" && !escaped) {
+ if (stream.eat("{")) {
+ if (quote == "}") {
+ state.context = {prev: state.context, type: 'read-quoted-paused'};
+ }
+ state.tokenize.push(tokenBaseUntilBrace());
+ break;
+ } else if (/[@\$]/.test(stream.peek())) {
+ state.tokenize.push(tokenBaseOnce());
+ break;
+ }
}
escaped = !escaped && ch == "\\";
}
@@ -163,6 +214,8 @@ CodeMirror.defineMode("ruby", function(config) {
else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent";
else if ((word == "if" || word == "unless") && stream.column() == stream.indentation())
kwtype = "indent";
+ else if (word == "do" && state.context.indented < state.indented)
+ kwtype = "indent";
}
if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style;
if (curPunc == "|") state.varList = !state.varList;
@@ -186,8 +239,9 @@ CodeMirror.defineMode("ruby", function(config) {
return ct.indented + (closing ? 0 : config.indentUnit) +
(state.continuedLine ? config.indentUnit : 0);
},
- electricChars: "}de" // enD and rescuE
+ electricChars: "}de", // enD and rescuE
+ lineComment: "#"
};
});
diff --git a/gulliver/js/codemirror/mode/rust/index.html b/gulliver/js/codemirror/mode/rust/index.html
index a6d47fe84..b0b4c2416 100644
--- a/gulliver/js/codemirror/mode/rust/index.html
+++ b/gulliver/js/codemirror/mode/rust/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: Rust mode
-
-
-
-
-
-
-
- CodeMirror: Rust mode
+
+CodeMirror: Rust mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Rust mode
+
// Demo code.
@@ -44,5 +58,4 @@ fn check_crate(x: int) {
MIME types defined: text/x-rustsrc.
-
-
+
diff --git a/gulliver/js/codemirror/mode/rust/rust.js b/gulliver/js/codemirror/mode/rust/rust.js
index ea3005c36..c7530b6cc 100644
--- a/gulliver/js/codemirror/mode/rust/rust.js
+++ b/gulliver/js/codemirror/mode/rust/rust.js
@@ -425,7 +425,11 @@ CodeMirror.defineMode("rust", function() {
return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit));
},
- electricChars: "{}"
+ electricChars: "{}",
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: "//",
+ fold: "brace"
};
});
diff --git a/gulliver/js/codemirror/mode/sass/index.html b/gulliver/js/codemirror/mode/sass/index.html
index 3af7bff9e..66d467784 100644
--- a/gulliver/js/codemirror/mode/sass/index.html
+++ b/gulliver/js/codemirror/mode/sass/index.html
@@ -1,18 +1,31 @@
-
-
-
- CodeMirror: Sass mode
-
-
-
-
-
-
-
-
- CodeMirror: Sass mode
- // Variable Definitions
+
+CodeMirror: Sass mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sass mode
+// Variable Definitions
$page-width: 800px
$sidebar-width: 200px
@@ -50,5 +63,4 @@ body
MIME types defined: text/x-sass.
-
-
+
diff --git a/gulliver/js/codemirror/mode/sass/sass.js b/gulliver/js/codemirror/mode/sass/sass.js
index 9aed75a1a..9c9a0dae0 100644
--- a/gulliver/js/codemirror/mode/sass/sass.js
+++ b/gulliver/js/codemirror/mode/sass/sass.js
@@ -3,24 +3,13 @@ CodeMirror.defineMode("sass", function(config) {
return new RegExp("^" + words.join("|"));
};
- var tags = ["&", "a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"];
var keywords = ["true", "false", "null", "auto"];
var keywordsRegexp = new RegExp("^" + keywords.join("|"));
var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"];
var opRegexp = tokenRegexp(operators);
- function htmlTag(val){
- for(var i=0; i
-
-
-
- CodeMirror: Scheme mode
-
-
-
-
-
-
-
- CodeMirror: Scheme mode
-
+
+CodeMirror: Scheme mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Scheme mode
+
; See if the input starts with a given symbol.
(define (match-symbol input pattern)
(cond ((null? (remain input)) #f)
@@ -61,5 +74,4 @@
MIME types defined: text/x-scheme.
-
-
+
diff --git a/gulliver/js/codemirror/mode/scheme/scheme.js b/gulliver/js/codemirror/mode/scheme/scheme.js
index 2ed0a24cd..c5990ae92 100644
--- a/gulliver/js/codemirror/mode/scheme/scheme.js
+++ b/gulliver/js/codemirror/mode/scheme/scheme.js
@@ -223,7 +223,9 @@ CodeMirror.defineMode("scheme", function () {
indent: function (state) {
if (state.indentStack == null) return state.indentation;
return state.indentStack.indent;
- }
+ },
+
+ lineComment: ";;"
};
});
diff --git a/gulliver/js/codemirror/mode/shell/index.html b/gulliver/js/codemirror/mode/shell/index.html
index 9a2ef7c4c..cf415e832 100644
--- a/gulliver/js/codemirror/mode/shell/index.html
+++ b/gulliver/js/codemirror/mode/shell/index.html
@@ -1,19 +1,33 @@
-
+
CodeMirror: Shell mode
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+Shell mode
-CodeMirror: Shell mode
#!/bin/bash
@@ -49,3 +63,4 @@ exit 0
MIME types defined: text/x-sh.
+
diff --git a/gulliver/js/codemirror/mode/shell/shell.js b/gulliver/js/codemirror/mode/shell/shell.js
index 9ce139b41..abfd21445 100644
--- a/gulliver/js/codemirror/mode/shell/shell.js
+++ b/gulliver/js/codemirror/mode/shell/shell.js
@@ -57,7 +57,7 @@ CodeMirror.defineMode('shell', function() {
return 'number';
}
}
- stream.eatWhile(/\w/);
+ stream.eatWhile(/[\w-]/);
var cur = stream.current();
if (stream.peek() === '=' && /\w+/.test(cur)) return 'def';
return words.hasOwnProperty(cur) ? words[cur] : null;
@@ -114,5 +114,5 @@ CodeMirror.defineMode('shell', function() {
}
};
});
-
+
CodeMirror.defineMIME('text/x-sh', 'shell');
diff --git a/gulliver/js/codemirror/mode/sieve/LICENSE b/gulliver/js/codemirror/mode/sieve/LICENSE
deleted file mode 100644
index 8a74612cb..000000000
--- a/gulliver/js/codemirror/mode/sieve/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2012 Thomas Schmid
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
diff --git a/gulliver/js/codemirror/mode/sieve/index.html b/gulliver/js/codemirror/mode/sieve/index.html
index 8b549815c..9d814a9d5 100644
--- a/gulliver/js/codemirror/mode/sieve/index.html
+++ b/gulliver/js/codemirror/mode/sieve/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Sieve (RFC5228) mode
-
-
-
-
-
-
-
- CodeMirror: Sieve (RFC5228) mode
-
+
+CodeMirror: Sieve (RFC5228) mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Sieve (RFC5228) mode
+
#
# Example Sieve Filter
# Declare any optional features or extension used by the script
@@ -77,5 +90,4 @@ else
MIME types defined: application/sieve.
-
-
+
diff --git a/gulliver/js/codemirror/mode/sieve/sieve.js b/gulliver/js/codemirror/mode/sieve/sieve.js
index b1bba53e0..8ca2a4cb8 100644
--- a/gulliver/js/codemirror/mode/sieve/sieve.js
+++ b/gulliver/js/codemirror/mode/sieve/sieve.js
@@ -31,7 +31,7 @@ CodeMirror.defineMode("sieve", function(config) {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
-
+
if (ch == "(") {
state._indent.push("(");
// add virtual angel wings so that editor behaves...
@@ -44,24 +44,24 @@ CodeMirror.defineMode("sieve", function(config) {
state._indent.push("{");
return null;
}
-
+
if (ch == ")") {
state._indent.pop();
- state._indent.pop();
+ state._indent.pop();
}
if (ch === "}") {
state._indent.pop();
return null;
}
-
+
if (ch == ",")
return null;
-
+
if (ch == ";")
return null;
-
-
+
+
if (/[{}\(\),;]/.test(ch))
return null;
@@ -97,7 +97,7 @@ CodeMirror.defineMode("sieve", function(config) {
if (atoms.propertyIsEnumerable(cur))
return "atom";
-
+
return null;
}
@@ -169,10 +169,10 @@ CodeMirror.defineMode("sieve", function(config) {
var length = state._indent.length;
if (_textAfter && (_textAfter[0] == "}"))
length--;
-
+
if (length <0)
length = 0;
-
+
return length * indentUnit;
},
diff --git a/gulliver/js/codemirror/mode/smalltalk/index.html b/gulliver/js/codemirror/mode/smalltalk/index.html
index b7aebdb7f..0d2b172e1 100644
--- a/gulliver/js/codemirror/mode/smalltalk/index.html
+++ b/gulliver/js/codemirror/mode/smalltalk/index.html
@@ -1,22 +1,34 @@
-
-
-
- CodeMirror: Smalltalk mode
-
-
-
-
-
-
-
-
- CodeMirror: Smalltalk mode
+
+
+
+
+
+
+
+Smalltalk mode
"
This is a test of the Smalltalk code
@@ -53,5 +65,4 @@ MyCounter registerAsApplication: 'mycounter'
Simple Smalltalk mode.
MIME types defined: text/x-stsrc.
-
-
+
diff --git a/gulliver/js/codemirror/mode/smalltalk/smalltalk.js b/gulliver/js/codemirror/mode/smalltalk/smalltalk.js
index 33ea11eae..86f749b31 100644
--- a/gulliver/js/codemirror/mode/smalltalk/smalltalk.js
+++ b/gulliver/js/codemirror/mode/smalltalk/smalltalk.js
@@ -1,139 +1,153 @@
CodeMirror.defineMode('smalltalk', function(config) {
- var specialChars = /[+\-/\\*~<>=@%|&?!.:;^]/;
- var keywords = /true|false|nil|self|super|thisContext/;
+ var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/;
+ var keywords = /true|false|nil|self|super|thisContext/;
- var Context = function(tokenizer, parent) {
- this.next = tokenizer;
- this.parent = parent;
- };
+ var Context = function(tokenizer, parent) {
+ this.next = tokenizer;
+ this.parent = parent;
+ };
- var Token = function(name, context, eos) {
- this.name = name;
- this.context = context;
- this.eos = eos;
- };
+ var Token = function(name, context, eos) {
+ this.name = name;
+ this.context = context;
+ this.eos = eos;
+ };
- var State = function() {
- this.context = new Context(next, null);
- this.expectVariable = true;
- this.indentation = 0;
- this.userIndentationDelta = 0;
- };
+ var State = function() {
+ this.context = new Context(next, null);
+ this.expectVariable = true;
+ this.indentation = 0;
+ this.userIndentationDelta = 0;
+ };
- State.prototype.userIndent = function(indentation) {
- this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
- };
+ State.prototype.userIndent = function(indentation) {
+ this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
+ };
- var next = function(stream, context, state) {
- var token = new Token(null, context, false);
- var aChar = stream.next();
+ var next = function(stream, context, state) {
+ var token = new Token(null, context, false);
+ var aChar = stream.next();
- if (aChar === '"') {
- token = nextComment(stream, new Context(nextComment, context));
+ if (aChar === '"') {
+ token = nextComment(stream, new Context(nextComment, context));
- } else if (aChar === '\'') {
- token = nextString(stream, new Context(nextString, context));
+ } else if (aChar === '\'') {
+ token = nextString(stream, new Context(nextString, context));
- } else if (aChar === '#') {
- stream.eatWhile(/[^ .]/);
- token.name = 'string-2';
+ } else if (aChar === '#') {
+ if (stream.peek() === '\'') {
+ stream.next();
+ token = nextSymbol(stream, new Context(nextSymbol, context));
+ } else {
+ if (stream.eatWhile(/[^ .{}\[\]()]/))
+ token.name = 'string-2';
+ else
+ token.name = 'meta';
+ }
- } else if (aChar === '$') {
- stream.eatWhile(/[^ ]/);
- token.name = 'string-2';
+ } else if (aChar === '$') {
+ if (stream.next() === '<') {
+ stream.eatWhile(/[^ >]/);
+ stream.next();
+ }
+ token.name = 'string-2';
- } else if (aChar === '|' && state.expectVariable) {
- token.context = new Context(nextTemporaries, context);
+ } else if (aChar === '|' && state.expectVariable) {
+ token.context = new Context(nextTemporaries, context);
- } else if (/[\[\]{}()]/.test(aChar)) {
- token.name = 'bracket';
- token.eos = /[\[{(]/.test(aChar);
+ } else if (/[\[\]{}()]/.test(aChar)) {
+ token.name = 'bracket';
+ token.eos = /[\[{(]/.test(aChar);
- if (aChar === '[') {
- state.indentation++;
- } else if (aChar === ']') {
- state.indentation = Math.max(0, state.indentation - 1);
- }
+ if (aChar === '[') {
+ state.indentation++;
+ } else if (aChar === ']') {
+ state.indentation = Math.max(0, state.indentation - 1);
+ }
- } else if (specialChars.test(aChar)) {
- stream.eatWhile(specialChars);
- token.name = 'operator';
- token.eos = aChar !== ';'; // ; cascaded message expression
+ } else if (specialChars.test(aChar)) {
+ stream.eatWhile(specialChars);
+ token.name = 'operator';
+ token.eos = aChar !== ';'; // ; cascaded message expression
- } else if (/\d/.test(aChar)) {
- stream.eatWhile(/[\w\d]/);
- token.name = 'number';
+ } else if (/\d/.test(aChar)) {
+ stream.eatWhile(/[\w\d]/);
+ token.name = 'number';
- } else if (/[\w_]/.test(aChar)) {
- stream.eatWhile(/[\w\d_]/);
- token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
+ } else if (/[\w_]/.test(aChar)) {
+ stream.eatWhile(/[\w\d_]/);
+ token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
- } else {
- token.eos = state.expectVariable;
- }
+ } else {
+ token.eos = state.expectVariable;
+ }
- return token;
- };
+ return token;
+ };
- var nextComment = function(stream, context) {
- stream.eatWhile(/[^"]/);
- return new Token('comment', stream.eat('"') ? context.parent : context, true);
- };
+ var nextComment = function(stream, context) {
+ stream.eatWhile(/[^"]/);
+ return new Token('comment', stream.eat('"') ? context.parent : context, true);
+ };
- var nextString = function(stream, context) {
- stream.eatWhile(/[^']/);
- return new Token('string', stream.eat('\'') ? context.parent : context, false);
- };
+ var nextString = function(stream, context) {
+ stream.eatWhile(/[^']/);
+ return new Token('string', stream.eat('\'') ? context.parent : context, false);
+ };
- var nextTemporaries = function(stream, context) {
- var token = new Token(null, context, false);
- var aChar = stream.next();
+ var nextSymbol = function(stream, context) {
+ stream.eatWhile(/[^']/);
+ return new Token('string-2', stream.eat('\'') ? context.parent : context, false);
+ };
- if (aChar === '|') {
- token.context = context.parent;
- token.eos = true;
+ var nextTemporaries = function(stream, context) {
+ var token = new Token(null, context, false);
+ var aChar = stream.next();
- } else {
- stream.eatWhile(/[^|]/);
- token.name = 'variable';
- }
+ if (aChar === '|') {
+ token.context = context.parent;
+ token.eos = true;
- return token;
- };
+ } else {
+ stream.eatWhile(/[^|]/);
+ token.name = 'variable';
+ }
- return {
- startState: function() {
- return new State;
- },
+ return token;
+ };
- token: function(stream, state) {
- state.userIndent(stream.indentation());
+ return {
+ startState: function() {
+ return new State;
+ },
- if (stream.eatSpace()) {
- return null;
- }
+ token: function(stream, state) {
+ state.userIndent(stream.indentation());
- var token = state.context.next(stream, state.context, state);
- state.context = token.context;
- state.expectVariable = token.eos;
+ if (stream.eatSpace()) {
+ return null;
+ }
- state.lastToken = token;
- return token.name;
- },
+ var token = state.context.next(stream, state.context, state);
+ state.context = token.context;
+ state.expectVariable = token.eos;
- blankLine: function(state) {
- state.userIndent(0);
- },
+ return token.name;
+ },
- indent: function(state, textAfter) {
- var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
- return (state.indentation + i) * config.indentUnit;
- },
+ blankLine: function(state) {
+ state.userIndent(0);
+ },
- electricChars: ']'
- };
+ indent: function(state, textAfter) {
+ var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
+ return (state.indentation + i) * config.indentUnit;
+ },
+
+ electricChars: ']'
+ };
});
-CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});
\ No newline at end of file
+CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});
diff --git a/gulliver/js/codemirror/mode/smarty/index.html b/gulliver/js/codemirror/mode/smarty/index.html
index 6b7debedc..d458aef0f 100644
--- a/gulliver/js/codemirror/mode/smarty/index.html
+++ b/gulliver/js/codemirror/mode/smarty/index.html
@@ -1,18 +1,30 @@
-
-
-
- CodeMirror: Smarty mode
-
-
-
-
-
-
-
- CodeMirror: Smarty mode
-
+CodeMirror: Smarty mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Smarty mode
+
{extends file="parent.tpl"}
{include file="template.tpl"}
@@ -43,6 +55,7 @@
+ Smarty 2, custom delimiters
{--extends file="parent.tpl"--}
{--include file="template.tpl"--}
@@ -76,8 +89,48 @@
});
- A plain text/Smarty mode which allows for custom delimiter tags (defaults to { and } ).
+
+
+ Smarty 3
+
+
+Nested tags {$foo={counter one=1 two={inception}}+3} are now valid in Smarty 3.
+
+
+
+{assign var=foo value=[1,2,3]}
+{assign var=foo value=['y'=>'yellow','b'=>'blue']}
+{assign var=foo value=[1,[9,8],3]}
+
+{$foo=$bar+2} {* a comment *}
+{$foo.bar=1} {* another comment *}
+{$foo = myfunct(($x+$y)*3)}
+{$foo = strlen($bar)}
+{$foo.bar.baz=1}, {$foo[]=1}
+
+Smarty "dot" syntax (note: embedded {} are used to address ambiguities):
+
+{$foo.a.b.c} => $foo['a']['b']['c']
+{$foo.a.$b.c} => $foo['a'][$b]['c']
+{$foo.a.{$b+4}.c} => $foo['a'][$b+4]['c']
+{$foo.a.{$b.c}} => $foo['a'][$b['c']]
+
+{$object->method1($x)->method2($y)}
+
+
+
+
+ A plain text/Smarty version 2 or 3 mode, which allows for custom delimiter tags.
MIME types defined: text/x-smarty
-
-
+
diff --git a/gulliver/js/codemirror/mode/smarty/smarty.js b/gulliver/js/codemirror/mode/smarty/smarty.js
index 9ee1e4851..826c2b966 100644
--- a/gulliver/js/codemirror/mode/smarty/smarty.js
+++ b/gulliver/js/codemirror/mode/smarty/smarty.js
@@ -1,140 +1,197 @@
+/**
+ * Smarty 2 and 3 mode.
+ */
CodeMirror.defineMode("smarty", function(config) {
- var keyFuncs = ["debug", "extends", "function", "include", "literal"];
+ "use strict";
+
+ // our default settings; check to see if they're overridden
+ var settings = {
+ rightDelimiter: '}',
+ leftDelimiter: '{',
+ smartyVersion: 2 // for backward compatibility
+ };
+ if (config.hasOwnProperty("leftDelimiter")) {
+ settings.leftDelimiter = config.leftDelimiter;
+ }
+ if (config.hasOwnProperty("rightDelimiter")) {
+ settings.rightDelimiter = config.rightDelimiter;
+ }
+ if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) {
+ settings.smartyVersion = 3;
+ }
+
+ var keyFunctions = ["debug", "extends", "function", "include", "literal"];
var last;
var regs = {
operatorChars: /[+\-*&%=<>!?]/,
- validIdentifier: /[a-zA-Z0-9\_]/,
- stringChar: /[\'\"]/
+ validIdentifier: /[a-zA-Z0-9_]/,
+ stringChar: /['"]/
};
- var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{";
- var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}";
- function ret(style, lst) { last = lst; return style; }
-
- function tokenizer(stream, state) {
- function chain(parser) {
+ var helpers = {
+ cont: function(style, lastType) {
+ last = lastType;
+ return style;
+ },
+ chain: function(stream, state, parser) {
state.tokenize = parser;
return parser(stream, state);
}
+ };
- if (stream.match(leftDelim, true)) {
- if (stream.eat("*")) {
- return chain(inBlock("comment", "*" + rightDelim));
- }
- else {
- state.tokenize = inSmarty;
- return "tag";
- }
- }
- else {
- // I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char
- stream.next();
- return null;
- }
- }
- function inSmarty(stream, state) {
- if (stream.match(rightDelim, true)) {
- state.tokenize = tokenizer;
- return ret("tag", null);
- }
+ // our various parsers
+ var parsers = {
- var ch = stream.next();
- if (ch == "$") {
- stream.eatWhile(regs.validIdentifier);
- return ret("variable-2", "variable");
- }
- else if (ch == ".") {
- return ret("operator", "property");
- }
- else if (regs.stringChar.test(ch)) {
- state.tokenize = inAttribute(ch);
- return ret("string", "string");
- }
- else if (regs.operatorChars.test(ch)) {
- stream.eatWhile(regs.operatorChars);
- return ret("operator", "operator");
- }
- else if (ch == "[" || ch == "]") {
- return ret("bracket", "bracket");
- }
- else if (/\d/.test(ch)) {
- stream.eatWhile(/\d/);
- return ret("number", "number");
- }
- else {
- if (state.last == "variable") {
- if (ch == "@") {
- stream.eatWhile(regs.validIdentifier);
- return ret("property", "property");
+ // the main tokenizer
+ tokenizer: function(stream, state) {
+ if (stream.match(settings.leftDelimiter, true)) {
+ if (stream.eat("*")) {
+ return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter));
+ } else {
+ // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode
+ state.depth++;
+ var isEol = stream.eol();
+ var isFollowedByWhitespace = /\s/.test(stream.peek());
+ if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) {
+ state.depth--;
+ return null;
+ } else {
+ state.tokenize = parsers.smarty;
+ last = "startTag";
+ return "tag";
+ }
}
- else if (ch == "|") {
- stream.eatWhile(regs.validIdentifier);
- return ret("qualifier", "modifier");
- }
- }
- else if (state.last == "whitespace") {
- stream.eatWhile(regs.validIdentifier);
- return ret("attribute", "modifier");
- }
- else if (state.last == "property") {
- stream.eatWhile(regs.validIdentifier);
- return ret("property", null);
- }
- else if (/\s/.test(ch)) {
- last = "whitespace";
+ } else {
+ stream.next();
return null;
}
+ },
- var str = "";
- if (ch != "/") {
- str += ch;
- }
- var c = "";
- while ((c = stream.eat(regs.validIdentifier))) {
- str += c;
- }
- var i, j;
- for (i=0, j=keyFuncs.length; i
-
-
-
- CodeMirror: SPARQL mode
-
-
-
-
-
-
-
-
- CodeMirror: SPARQL mode
-
+
+CodeMirror: SPARQL mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+SPARQL mode
+
PREFIX a: <http://www.w3.org/2000/10/annotation-ns#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
@@ -38,5 +51,4 @@ WHERE {
MIME types defined: application/x-sparql-query.
-
-
+
diff --git a/gulliver/js/codemirror/mode/sparql/sparql.js b/gulliver/js/codemirror/mode/sparql/sparql.js
index 0b367b2a8..0329057f6 100644
--- a/gulliver/js/codemirror/mode/sparql/sparql.js
+++ b/gulliver/js/codemirror/mode/sparql/sparql.js
@@ -6,10 +6,12 @@ CodeMirror.defineMode("sparql", function(config) {
return new RegExp("^(?:" + words.join("|") + ")$", "i");
}
var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
- "isblank", "isliteral", "union", "a"]);
+ "isblank", "isliteral", "a"]);
var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
"ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
- "graph", "by", "asc", "desc"]);
+ "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group",
+ "minus", "in", "not", "service", "silent", "using", "insert", "delete", "union",
+ "data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]);
var operatorChars = /[*+\-<>=&|]/;
function tokenBase(stream, state) {
@@ -117,7 +119,7 @@ CodeMirror.defineMode("sparql", function(config) {
state.context.col = stream.column();
}
}
-
+
return style;
},
diff --git a/gulliver/js/codemirror/mode/sql/index.html b/gulliver/js/codemirror/mode/sql/index.html
index 7ec938a12..e6882d79c 100644
--- a/gulliver/js/codemirror/mode/sql/index.html
+++ b/gulliver/js/codemirror/mode/sql/index.html
@@ -1,50 +1,43 @@
-
-
-
- SQL Mode for CodeMirror
-
-
-
-
-
-
-
-
-
-
- SQL Mode for CodeMirror
-
+
+SQL Mode for CodeMirror
+
-- SQL Mode for CodeMirror
SELECT SQL_NO_CACHE DISTINCT
@var1 AS `val1`, @'val2', @global.'sql_mode',
1.1 AS `float_val`, .14 AS `another_float`, 0.09e3 AS `int_with_esp`,
0xFA5 AS `hex`, x'fa5' AS `hex2`, 0b101 AS `bin`, b'101' AS `bin2`,
DATE '1994-01-01' AS `sql_date`, { T "1994-01-01" } AS `odbc_date`,
- 'myString', UNKNOWN
+ 'my string', _utf8'your string', N'her string',
+ TRUE, FALSE, UNKNOWN
FROM DUAL
-- space needed after '--'
# 1 line comment
@@ -57,12 +50,26 @@ SELECT SQL_NO_CACHE DISTINCT
text/x-sql ,
text/x-mysql ,
text/x-mariadb ,
- text/x-plsql .
+ text/x-cassandra ,
+ text/x-plsql ,
+ text/x-mssql .
-
- Tests:
- normal ,
- verbose .
-
-
-
+
+
+
diff --git a/gulliver/js/codemirror/mode/sql/sql.js b/gulliver/js/codemirror/mode/sql/sql.js
index 510110b30..903fa6740 100644
--- a/gulliver/js/codemirror/mode/sql/sql.js
+++ b/gulliver/js/codemirror/mode/sql/sql.js
@@ -9,7 +9,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
support = parserConfig.support || {},
hooks = parserConfig.hooks || {},
dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true};
-
+
function tokenBase(stream, state) {
var ch = stream.next();
@@ -19,43 +19,64 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
if (result !== false) return result;
}
- if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
- || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/)) {
+ if (support.hexNumber == true &&
+ ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
+ || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
// hex
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
return "number";
- } else if (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
- || (ch == "0" && stream.match(/^b[01]+/))) {
+ } else if (support.binaryNumber == true &&
+ (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
+ || (ch == "0" && stream.match(/^b[01]+/)))) {
// bitstring
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html
return "number";
} else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
// numbers
- stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
+ stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
+ support.decimallessFloat == true && stream.eat('.');
return "number";
} else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
// placeholders
return "variable-3";
- } else if (ch == '"' || ch == "'") {
+ } else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
// strings
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
state.tokenize = tokenLiteral(ch);
return state.tokenize(stream, state);
+ } else if ((((support.nCharCast == true && (ch == "n" || ch == "N"))
+ || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
+ && (stream.peek() == "'" || stream.peek() == '"'))) {
+ // charset casting: _utf8'str', N'str', n'str'
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
+ return "keyword";
} else if (/^[\(\),\;\[\]]/.test(ch)) {
// no highlightning
return null;
- } else if (ch == "#" || (ch == "-" && stream.eat("-") && stream.eat(" "))) {
+ } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
+ // 1-line comment
+ stream.skipToEnd();
+ return "comment";
+ } else if ((support.commentHash && ch == "#")
+ || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
// 1-line comments
- stream.skipToEnd();
+ // ref: https://kb.askmonty.org/en/comment-syntax/
+ stream.skipToEnd();
return "comment";
} else if (ch == "/" && stream.eat("*")) {
// multi-line comments
+ // ref: https://kb.askmonty.org/en/comment-syntax/
state.tokenize = tokenComment;
return state.tokenize(stream, state);
} else if (ch == ".") {
// .1 for 0.1
- if (stream.match(/^[0-9eE]+/) && support.zerolessFloat == true) {
+ if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
return "number";
}
// .table_name (ODBC)
- if (stream.match(/^[a-zA-Z_]+/) && support.ODBCdotTable == true) {
+ // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
+ if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {
return "variable-2";
}
} else if (operatorChars.test(ch)) {
@@ -65,11 +86,13 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
} else if (ch == '{' &&
(stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
// dates (weird ODBC syntax)
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
return "number";
} else {
stream.eatWhile(/^[_\w\d]/);
var word = stream.current().toLowerCase();
// dates (standard SQL syntax)
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
return "number";
if (atoms.hasOwnProperty(word)) return "atom";
@@ -85,11 +108,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
- if (ch == quote && !escaped) {
- state.tokenize = tokenBase;
- break;
- }
- escaped = !escaped && ch == "\\";
+ if (ch == quote && !escaped) {
+ state.tokenize = tokenBase;
+ break;
+ }
+ escaped = !escaped && ch == "\\";
}
return "string";
};
@@ -97,14 +120,14 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
function tokenComment(stream, state) {
while (true) {
if (stream.skipTo("*")) {
- stream.next();
- if (stream.eat("/")) {
- state.tokenize = tokenBase;
- break;
- }
+ stream.next();
+ if (stream.eat("/")) {
+ state.tokenize = tokenBase;
+ break;
+ }
} else {
- stream.skipToEnd();
- break;
+ stream.skipToEnd();
+ break;
}
}
return "comment";
@@ -131,8 +154,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
token: function(stream, state) {
if (stream.sol()) {
- if (state.context && state.context.align == null)
- state.context.align = false;
+ if (state.context && state.context.align == null)
+ state.context.align = false;
}
if (stream.eatSpace()) return null;
@@ -140,7 +163,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
if (style == "comment") return style;
if (state.context && state.context.align == null)
- state.context.align = true;
+ state.context.align = true;
var tok = stream.current();
if (tok == "(")
@@ -154,22 +177,28 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
indent: function(state, textAfter) {
var cx = state.context;
- if (!cx) return CodeMirror.Pass;
- if (cx.align) return cx.col + (textAfter.charAt(0) == cx.type ? 0 : 1);
- else return cx.indent + config.indentUnit;
- }
+ if (!cx) return 0;
+ var closing = textAfter.charAt(0) == cx.type;
+ if (cx.align) return cx.col + (closing ? 0 : 1);
+ else return cx.indent + (closing ? 0 : config.indentUnit);
+ },
+
+ blockCommentStart: "/*",
+ blockCommentEnd: "*/",
+ lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null
};
});
(function() {
"use strict";
-
+
// `identifier`
function hookIdentifier(stream) {
- var escaped = false, ch;
+ // MySQL/MariaDB identifiers
+ // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
+ var ch;
while ((ch = stream.next()) != null) {
- if (ch == "`" && !escaped) return "variable-2";
- escaped = !escaped && ch == "`";
+ if (ch == "`" && !stream.eat("`")) return "variable-2";
}
return null;
}
@@ -177,7 +206,9 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
// variable token
function hookVar(stream) {
// variables
- // @@ and prefix
+ // @@prefix.varName @varName
+ // varName can be quoted with ` or ' or "
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
if (stream.eat("@")) {
stream.match(/^session\./);
stream.match(/^local\./);
@@ -201,18 +232,27 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
// short client keyword token
function hookClient(stream) {
+ // \N means NULL
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html
+ if (stream.eat("N")) {
+ return "atom";
+ }
// \g, etc
- return stream.match(/^[a-zA-Z]\b/) ? "variable-2" : null;
+ // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html
+ return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
}
+ // these keywords are used by all SQL dialects (however, a mode can still overwrite it)
var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where ";
+ // turn a space-separated list into an array
function set(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
+ // A generic SQL Mode. It's not a standard, it just try to support what is generally supported
CodeMirror.defineMIME("text/x-sql", {
name: "sql",
keywords: set(sqlKeywords + "begin"),
@@ -220,18 +260,31 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
atoms: set("false true null unknown"),
operatorChars: /^[*+\-%<>!=]/,
dateSQL: set("date time timestamp"),
- support: set("ODBCdotTable")
+ support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
+ });
+
+ CodeMirror.defineMIME("text/x-mssql", {
+ name: "sql",
+ client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
+ keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered"),
+ builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "),
+ atoms: set("false true null unknown"),
+ operatorChars: /^[*+\-%<>!=]/,
+ dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"),
+ hooks: {
+ "@": hookVar
+ }
});
CodeMirror.defineMIME("text/x-mysql", {
name: "sql",
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
- keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
- builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
+ keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
+ builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
atoms: set("false true null unknown"),
operatorChars: /^[*+\-%<>!=&|^]/,
dateSQL: set("date time timestamp"),
- support: set("ODBCdotTable zerolessFloat"),
+ support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
hooks: {
"@": hookVar,
"`": hookIdentifier,
@@ -242,12 +295,12 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
CodeMirror.defineMIME("text/x-mariadb", {
name: "sql",
client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"),
- keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
- builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
+ keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"),
+ builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"),
atoms: set("false true null unknown"),
operatorChars: /^[*+\-%<>!=&|^]/,
dateSQL: set("date time timestamp"),
- support: set("ODBCdotTable zerolessFloat"),
+ support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"),
hooks: {
"@": hookVar,
"`": hookIdentifier,
@@ -255,14 +308,59 @@ CodeMirror.defineMode("sql", function(config, parserConfig) {
}
});
+ // the query language used by Apache Cassandra is called CQL, but this mime type
+ // is called Cassandra to avoid confusion with Contextual Query Language
+ CodeMirror.defineMIME("text/x-cassandra", {
+ name: "sql",
+ client: { },
+ keywords: set("use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum"),
+ builtin: set("ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint"),
+ atoms: set("false true"),
+ operatorChars: /^[<>=]/,
+ dateSQL: { },
+ support: set("commentSlashSlash decimallessFloat"),
+ hooks: { }
+ });
+
// this is based on Peter Raganitsch's 'plsql' mode
CodeMirror.defineMIME("text/x-plsql", {
name: "sql",
client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"),
keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"),
- functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"),
- builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"),
+ builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv varchar varchar2 variance varying vsize xml"),
operatorChars: /^[*+\-%<>!=~]/,
- dateSQL: set("date time timestamp")
+ dateSQL: set("date time timestamp"),
+ support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber")
});
}());
+
+/*
+ How Properties of Mime Types are used by SQL Mode
+ =================================================
+
+ keywords:
+ A list of keywords you want to be highlighted.
+ functions:
+ A list of function names you want to be highlighted.
+ builtin:
+ A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
+ operatorChars:
+ All characters that must be handled as operators.
+ client:
+ Commands parsed and executed by the client (not the server).
+ support:
+ A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.
+ * ODBCdotTable: .tableName
+ * zerolessFloat: .1
+ * doubleQuote
+ * nCharCast: N'string'
+ * charsetCast: _utf8'string'
+ * commentHash: use # char for comments
+ * commentSlashSlash: use // for comments
+ * commentSpaceRequired: require a space after -- for comments
+ atoms:
+ Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:
+ UNKNOWN, INFINITY, UNDERFLOW, NaN...
+ dateSQL:
+ Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.
+*/
diff --git a/gulliver/js/codemirror/mode/stex/index.html b/gulliver/js/codemirror/mode/stex/index.html
index 2dafe6981..28b8f64be 100644
--- a/gulliver/js/codemirror/mode/stex/index.html
+++ b/gulliver/js/codemirror/mode/stex/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: sTeX mode
-
-
-
-
-
-
-
- CodeMirror: sTeX mode
-
+
+CodeMirror: sTeX mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+sTeX mode
+
\begin{module}[id=bbt-size]
\importmodule[balanced-binary-trees]{balanced-binary-trees}
\importmodule[\KWARCslides{dmath/en/cardinality}]{cardinality}
@@ -94,5 +107,4 @@
Parsing/Highlighting Tests: normal , verbose .
-
-
+
diff --git a/gulliver/js/codemirror/mode/stex/stex.js b/gulliver/js/codemirror/mode/stex/stex.js
index 318b63acd..ca04c24f2 100644
--- a/gulliver/js/codemirror/mode/stex/stex.js
+++ b/gulliver/js/codemirror/mode/stex/stex.js
@@ -95,7 +95,7 @@ CodeMirror.defineMode("stex", function() {
}
// white space control characters
- if (source.match(/^\\[,;!\/]/)) {
+ if (source.match(/^\\[,;!\/\\]/)) {
return "tag";
}
diff --git a/gulliver/js/codemirror/mode/stex/test.js b/gulliver/js/codemirror/mode/stex/test.js
index 727a7db07..ab629e81e 100644
--- a/gulliver/js/codemirror/mode/stex/test.js
+++ b/gulliver/js/codemirror/mode/stex/test.js
@@ -114,4 +114,7 @@
MT("mathWithComment",
"[keyword $][variable-2 x] [comment % $]",
"[variable-2 y][keyword $] other text");
+
+ MT("lineBreakArgument",
+ "[tag \\\\][bracket [[][atom 1cm][bracket ]]]");
})();
diff --git a/gulliver/js/codemirror/mode/tcl/index.html b/gulliver/js/codemirror/mode/tcl/index.html
index e2e42a04b..2c0d1a2de 100644
--- a/gulliver/js/codemirror/mode/tcl/index.html
+++ b/gulliver/js/codemirror/mode/tcl/index.html
@@ -1,17 +1,31 @@
-
-
-
- CodeMirror: Tcl mode
-
-
-
-
-
-
-
- CodeMirror: Tcl mode
-
+
+CodeMirror: Tcl mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Tcl mode
+
##############################################################################################
## ## whois.tcl for eggdrop by Ford_Lawnmower irc.geekshed.net #Script-Help ## ##
##############################################################################################
@@ -119,11 +133,11 @@ Ford_Lawnmower irc.GeekShed.net #Script-Help"
theme: "night",
lineNumbers: true,
indentUnit: 2,
+ scrollPastEnd: true,
mode: "text/x-tcl"
});
MIME types defined: text/x-tcl.
-
-
+
diff --git a/gulliver/js/codemirror/mode/tcl/tcl.js b/gulliver/js/codemirror/mode/tcl/tcl.js
index 58ca709e4..ed2c69721 100644
--- a/gulliver/js/codemirror/mode/tcl/tcl.js
+++ b/gulliver/js/codemirror/mode/tcl/tcl.js
@@ -56,7 +56,7 @@ CodeMirror.defineMode("tcl", function() {
else if (ch == "$") {
stream.eatWhile(/[$_a-z0-9A-Z\.{:]/);
stream.eatWhile(/}/);
- state.beforeParams = true;
+ state.beforeParams = true;
return "builtin";
}
else if (isOperatorChar.test(ch)) {
diff --git a/gulliver/js/codemirror/mode/tiddlywiki/index.html b/gulliver/js/codemirror/mode/tiddlywiki/index.html
index 848f33a59..fc8f5d392 100644
--- a/gulliver/js/codemirror/mode/tiddlywiki/index.html
+++ b/gulliver/js/codemirror/mode/tiddlywiki/index.html
@@ -1,18 +1,32 @@
-
-
-
- CodeMirror: TiddlyWiki mode
-
-
-
-
-
-
-
-
-
- CodeMirror: TiddlyWiki mode
+
+CodeMirror: TiddlyWiki mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+TiddlyWiki mode
+
!TiddlyWiki Formatting
@@ -138,5 +152,4 @@ cf. [[TiddlyWiki.com|http://www.tiddlywiki.com/#EmbeddedImages]]
TiddlyWiki mode supports a single configuration.
MIME types defined: text/x-tiddlywiki.
-
-
+
diff --git a/gulliver/js/codemirror/mode/tiddlywiki/tiddlywiki.js b/gulliver/js/codemirror/mode/tiddlywiki/tiddlywiki.js
index 0d506ee60..24a24786b 100644
--- a/gulliver/js/codemirror/mode/tiddlywiki/tiddlywiki.js
+++ b/gulliver/js/codemirror/mode/tiddlywiki/tiddlywiki.js
@@ -1,352 +1,352 @@
/***
-|''Name''|tiddlywiki.js|
-|''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|
-|''Author''|PMario|
-|''Version''|0.1.7|
-|''Status''|''stable''|
-|''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
-|''Documentation''|http://codemirror.tiddlyspace.com/|
-|''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
-|''CoreVersion''|2.5.0|
-|''Requires''|codemirror.js|
-|''Keywords''|syntax highlighting color code mirror codemirror|
-! Info
-CoreVersion parameter is needed for TiddlyWiki only!
+ |''Name''|tiddlywiki.js|
+ |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|
+ |''Author''|PMario|
+ |''Version''|0.1.7|
+ |''Status''|''stable''|
+ |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
+ |''Documentation''|http://codemirror.tiddlyspace.com/|
+ |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
+ |''CoreVersion''|2.5.0|
+ |''Requires''|codemirror.js|
+ |''Keywords''|syntax highlighting color code mirror codemirror|
+ ! Info
+ CoreVersion parameter is needed for TiddlyWiki only!
***/
//{{{
CodeMirror.defineMode("tiddlywiki", function () {
- // Tokenizer
- var textwords = {};
+ // Tokenizer
+ var textwords = {};
- var keywords = function () {
- function kw(type) {
- return { type: type, style: "macro"};
- }
- return {
- "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
- "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
- "permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
- "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'),
- "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'),
- "tiddler": kw('tiddler'), "timeline": kw('timeline'),
- "today": kw('today'), "version": kw('version'), "option": kw('option'),
+ var keywords = function () {
+ function kw(type) {
+ return { type: type, style: "macro"};
+ }
+ return {
+ "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
+ "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
+ "permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
+ "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'),
+ "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'),
+ "tiddler": kw('tiddler'), "timeline": kw('timeline'),
+ "today": kw('today'), "version": kw('version'), "option": kw('option'),
- "with": kw('with'),
- "filter": kw('filter')
- };
- }();
+ "with": kw('with'),
+ "filter": kw('filter')
+ };
+ }();
- var isSpaceName = /[\w_\-]/i,
- reHR = /^\-\-\-\-+$/, //
- reWikiCommentStart = /^\/\*\*\*$/, // /***
- reWikiCommentStop = /^\*\*\*\/$/, // ***/
- reBlockQuote = /^<<<$/,
+ var isSpaceName = /[\w_\-]/i,
+ reHR = /^\-\-\-\-+$/, //
+ reWikiCommentStart = /^\/\*\*\*$/, // /***
+ reWikiCommentStop = /^\*\*\*\/$/, // ***/
+ reBlockQuote = /^<<<$/,
- reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start
- reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop
- reXmlCodeStart = /^$/, // xml block start
- reXmlCodeStop = /^$/, // xml stop
+ reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start
+ reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop
+ reXmlCodeStart = /^$/, // xml block start
+ reXmlCodeStop = /^$/, // xml stop
- reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start
- reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop
+ reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start
+ reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop
- reUntilCodeStop = /.*?\}\}\}/;
+ reUntilCodeStop = /.*?\}\}\}/;
- function chain(stream, state, f) {
- state.tokenize = f;
- return f(stream, state);
- }
+ function chain(stream, state, f) {
+ state.tokenize = f;
+ return f(stream, state);
+ }
- // Used as scratch variables to communicate multiple values without
- // consing up tons of objects.
- var type, content;
+ // Used as scratch variables to communicate multiple values without
+ // consing up tons of objects.
+ var type, content;
- function ret(tp, style, cont) {
- type = tp;
- content = cont;
- return style;
- }
+ function ret(tp, style, cont) {
+ type = tp;
+ content = cont;
+ return style;
+ }
- function jsTokenBase(stream, state) {
- var sol = stream.sol(), ch;
-
- state.block = false; // indicates the start of a code block.
+ function jsTokenBase(stream, state) {
+ var sol = stream.sol(), ch;
- ch = stream.peek(); // don't eat, to make matching simpler
-
- // check start of blocks
- if (sol && /[<\/\*{}\-]/.test(ch)) {
- if (stream.match(reCodeBlockStart)) {
- state.block = true;
- return chain(stream, state, twTokenCode);
- }
- if (stream.match(reBlockQuote)) {
- return ret('quote', 'quote');
- }
- if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
- return ret('code', 'comment');
- }
- if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
- return ret('code', 'comment');
- }
- if (stream.match(reHR)) {
- return ret('hr', 'hr');
- }
- } // sol
- ch = stream.next();
+ state.block = false; // indicates the start of a code block.
- if (sol && /[\/\*!#;:>|]/.test(ch)) {
- if (ch == "!") { // tw header
- stream.skipToEnd();
- return ret("header", "header");
- }
- if (ch == "*") { // tw list
- stream.eatWhile('*');
- return ret("list", "comment");
- }
- if (ch == "#") { // tw numbered list
- stream.eatWhile('#');
- return ret("list", "comment");
- }
- if (ch == ";") { // definition list, term
- stream.eatWhile(';');
- return ret("list", "comment");
- }
- if (ch == ":") { // definition list, description
- stream.eatWhile(':');
- return ret("list", "comment");
- }
- if (ch == ">") { // single line quote
- stream.eatWhile(">");
- return ret("quote", "quote");
- }
- if (ch == '|') {
- return ret('table', 'header');
- }
- }
+ ch = stream.peek(); // don't eat, to make matching simpler
- if (ch == '{' && stream.match(/\{\{/)) {
- return chain(stream, state, twTokenCode);
- }
+ // check start of blocks
+ if (sol && /[<\/\*{}\-]/.test(ch)) {
+ if (stream.match(reCodeBlockStart)) {
+ state.block = true;
+ return chain(stream, state, twTokenCode);
+ }
+ if (stream.match(reBlockQuote)) {
+ return ret('quote', 'quote');
+ }
+ if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
+ return ret('code', 'comment');
+ }
+ if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
+ return ret('code', 'comment');
+ }
+ if (stream.match(reHR)) {
+ return ret('hr', 'hr');
+ }
+ } // sol
+ ch = stream.next();
- // rudimentary html:// file:// link matching. TW knows much more ...
- if (/[hf]/i.test(ch)) {
- if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
- return ret("link", "link");
- }
- }
- // just a little string indicator, don't want to have the whole string covered
- if (ch == '"') {
- return ret('string', 'string');
- }
- if (ch == '~') { // _no_ CamelCase indicator should be bold
- return ret('text', 'brace');
- }
- if (/[\[\]]/.test(ch)) { // check for [[..]]
- if (stream.peek() == ch) {
- stream.next();
- return ret('brace', 'brace');
- }
- }
- if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
- stream.eatWhile(isSpaceName);
- return ret("link", "link");
- }
- if (/\d/.test(ch)) { // numbers
- stream.eatWhile(/\d/);
- return ret("number", "number");
- }
- if (ch == "/") { // tw invisible comment
- if (stream.eat("%")) {
- return chain(stream, state, twTokenComment);
- }
- else if (stream.eat("/")) { //
- return chain(stream, state, twTokenEm);
- }
- }
- if (ch == "_") { // tw underline
- if (stream.eat("_")) {
- return chain(stream, state, twTokenUnderline);
- }
- }
- // strikethrough and mdash handling
- if (ch == "-") {
- if (stream.eat("-")) {
- // if strikethrough looks ugly, change CSS.
- if (stream.peek() != ' ')
- return chain(stream, state, twTokenStrike);
- // mdash
- if (stream.peek() == ' ')
- return ret('text', 'brace');
- }
- }
- if (ch == "'") { // tw bold
- if (stream.eat("'")) {
- return chain(stream, state, twTokenStrong);
- }
- }
- if (ch == "<") { // tw macro
- if (stream.eat("<")) {
- return chain(stream, state, twTokenMacro);
- }
- }
- else {
- return ret(ch);
- }
+ if (sol && /[\/\*!#;:>|]/.test(ch)) {
+ if (ch == "!") { // tw header
+ stream.skipToEnd();
+ return ret("header", "header");
+ }
+ if (ch == "*") { // tw list
+ stream.eatWhile('*');
+ return ret("list", "comment");
+ }
+ if (ch == "#") { // tw numbered list
+ stream.eatWhile('#');
+ return ret("list", "comment");
+ }
+ if (ch == ";") { // definition list, term
+ stream.eatWhile(';');
+ return ret("list", "comment");
+ }
+ if (ch == ":") { // definition list, description
+ stream.eatWhile(':');
+ return ret("list", "comment");
+ }
+ if (ch == ">") { // single line quote
+ stream.eatWhile(">");
+ return ret("quote", "quote");
+ }
+ if (ch == '|') {
+ return ret('table', 'header');
+ }
+ }
- // core macro handling
- stream.eatWhile(/[\w\$_]/);
- var word = stream.current(),
- known = textwords.propertyIsEnumerable(word) && textwords[word];
+ if (ch == '{' && stream.match(/\{\{/)) {
+ return chain(stream, state, twTokenCode);
+ }
- return known ? ret(known.type, known.style, word) : ret("text", null, word);
+ // rudimentary html:// file:// link matching. TW knows much more ...
+ if (/[hf]/i.test(ch)) {
+ if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
+ return ret("link", "link");
+ }
+ }
+ // just a little string indicator, don't want to have the whole string covered
+ if (ch == '"') {
+ return ret('string', 'string');
+ }
+ if (ch == '~') { // _no_ CamelCase indicator should be bold
+ return ret('text', 'brace');
+ }
+ if (/[\[\]]/.test(ch)) { // check for [[..]]
+ if (stream.peek() == ch) {
+ stream.next();
+ return ret('brace', 'brace');
+ }
+ }
+ if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting
+ stream.eatWhile(isSpaceName);
+ return ret("link", "link");
+ }
+ if (/\d/.test(ch)) { // numbers
+ stream.eatWhile(/\d/);
+ return ret("number", "number");
+ }
+ if (ch == "/") { // tw invisible comment
+ if (stream.eat("%")) {
+ return chain(stream, state, twTokenComment);
+ }
+ else if (stream.eat("/")) { //
+ return chain(stream, state, twTokenEm);
+ }
+ }
+ if (ch == "_") { // tw underline
+ if (stream.eat("_")) {
+ return chain(stream, state, twTokenUnderline);
+ }
+ }
+ // strikethrough and mdash handling
+ if (ch == "-") {
+ if (stream.eat("-")) {
+ // if strikethrough looks ugly, change CSS.
+ if (stream.peek() != ' ')
+ return chain(stream, state, twTokenStrike);
+ // mdash
+ if (stream.peek() == ' ')
+ return ret('text', 'brace');
+ }
+ }
+ if (ch == "'") { // tw bold
+ if (stream.eat("'")) {
+ return chain(stream, state, twTokenStrong);
+ }
+ }
+ if (ch == "<") { // tw macro
+ if (stream.eat("<")) {
+ return chain(stream, state, twTokenMacro);
+ }
+ }
+ else {
+ return ret(ch);
+ }
- } // jsTokenBase()
+ // core macro handling
+ stream.eatWhile(/[\w\$_]/);
+ var word = stream.current(),
+ known = textwords.propertyIsEnumerable(word) && textwords[word];
- // tw invisible comment
- function twTokenComment(stream, state) {
- var maybeEnd = false,
- ch;
- while (ch = stream.next()) {
- if (ch == "/" && maybeEnd) {
- state.tokenize = jsTokenBase;
- break;
- }
- maybeEnd = (ch == "%");
- }
- return ret("comment", "comment");
- }
+ return known ? ret(known.type, known.style, word) : ret("text", null, word);
- // tw strong / bold
- function twTokenStrong(stream, state) {
- var maybeEnd = false,
- ch;
- while (ch = stream.next()) {
- if (ch == "'" && maybeEnd) {
- state.tokenize = jsTokenBase;
- break;
- }
- maybeEnd = (ch == "'");
- }
- return ret("text", "strong");
- }
+ } // jsTokenBase()
- // tw code
- function twTokenCode(stream, state) {
- var ch, sb = state.block;
-
- if (sb && stream.current()) {
- return ret("code", "comment");
- }
+ // tw invisible comment
+ function twTokenComment(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "%");
+ }
+ return ret("comment", "comment");
+ }
- if (!sb && stream.match(reUntilCodeStop)) {
- state.tokenize = jsTokenBase;
- return ret("code", "comment");
- }
+ // tw strong / bold
+ function twTokenStrong(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "'" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "'");
+ }
+ return ret("text", "strong");
+ }
- if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
- state.tokenize = jsTokenBase;
- return ret("code", "comment");
- }
+ // tw code
+ function twTokenCode(stream, state) {
+ var ch, sb = state.block;
- ch = stream.next();
- return (sb) ? ret("code", "comment") : ret("code", "comment");
- }
+ if (sb && stream.current()) {
+ return ret("code", "comment");
+ }
- // tw em / italic
- function twTokenEm(stream, state) {
- var maybeEnd = false,
- ch;
- while (ch = stream.next()) {
- if (ch == "/" && maybeEnd) {
- state.tokenize = jsTokenBase;
- break;
- }
- maybeEnd = (ch == "/");
- }
- return ret("text", "em");
- }
+ if (!sb && stream.match(reUntilCodeStop)) {
+ state.tokenize = jsTokenBase;
+ return ret("code", "comment");
+ }
- // tw underlined text
- function twTokenUnderline(stream, state) {
- var maybeEnd = false,
- ch;
- while (ch = stream.next()) {
- if (ch == "_" && maybeEnd) {
- state.tokenize = jsTokenBase;
- break;
- }
- maybeEnd = (ch == "_");
- }
- return ret("text", "underlined");
- }
+ if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
+ state.tokenize = jsTokenBase;
+ return ret("code", "comment");
+ }
- // tw strike through text looks ugly
- // change CSS if needed
- function twTokenStrike(stream, state) {
- var maybeEnd = false, ch;
-
- while (ch = stream.next()) {
- if (ch == "-" && maybeEnd) {
- state.tokenize = jsTokenBase;
- break;
- }
- maybeEnd = (ch == "-");
- }
- return ret("text", "strikethrough");
- }
+ ch = stream.next();
+ return (sb) ? ret("code", "comment") : ret("code", "comment");
+ }
- // macro
- function twTokenMacro(stream, state) {
- var ch, word, known;
+ // tw em / italic
+ function twTokenEm(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "/" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "/");
+ }
+ return ret("text", "em");
+ }
- if (stream.current() == '<<') {
- return ret('brace', 'macro');
- }
+ // tw underlined text
+ function twTokenUnderline(stream, state) {
+ var maybeEnd = false,
+ ch;
+ while (ch = stream.next()) {
+ if (ch == "_" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "_");
+ }
+ return ret("text", "underlined");
+ }
- ch = stream.next();
- if (!ch) {
- state.tokenize = jsTokenBase;
- return ret(ch);
- }
- if (ch == ">") {
- if (stream.peek() == '>') {
- stream.next();
- state.tokenize = jsTokenBase;
- return ret("brace", "macro");
- }
- }
+ // tw strike through text looks ugly
+ // change CSS if needed
+ function twTokenStrike(stream, state) {
+ var maybeEnd = false, ch;
- stream.eatWhile(/[\w\$_]/);
- word = stream.current();
- known = keywords.propertyIsEnumerable(word) && keywords[word];
+ while (ch = stream.next()) {
+ if (ch == "-" && maybeEnd) {
+ state.tokenize = jsTokenBase;
+ break;
+ }
+ maybeEnd = (ch == "-");
+ }
+ return ret("text", "strikethrough");
+ }
- if (known) {
- return ret(known.type, known.style, word);
- }
- else {
- return ret("macro", null, word);
- }
- }
+ // macro
+ function twTokenMacro(stream, state) {
+ var ch, word, known;
- // Interface
- return {
- startState: function () {
- return {
- tokenize: jsTokenBase,
- indented: 0,
- level: 0
- };
- },
+ if (stream.current() == '<<') {
+ return ret('brace', 'macro');
+ }
- token: function (stream, state) {
- if (stream.eatSpace()) return null;
- var style = state.tokenize(stream, state);
- return style;
- },
+ ch = stream.next();
+ if (!ch) {
+ state.tokenize = jsTokenBase;
+ return ret(ch);
+ }
+ if (ch == ">") {
+ if (stream.peek() == '>') {
+ stream.next();
+ state.tokenize = jsTokenBase;
+ return ret("brace", "macro");
+ }
+ }
- electricChars: ""
- };
+ stream.eatWhile(/[\w\$_]/);
+ word = stream.current();
+ known = keywords.propertyIsEnumerable(word) && keywords[word];
+
+ if (known) {
+ return ret(known.type, known.style, word);
+ }
+ else {
+ return ret("macro", null, word);
+ }
+ }
+
+ // Interface
+ return {
+ startState: function () {
+ return {
+ tokenize: jsTokenBase,
+ indented: 0,
+ level: 0
+ };
+ },
+
+ token: function (stream, state) {
+ if (stream.eatSpace()) return null;
+ var style = state.tokenize(stream, state);
+ return style;
+ },
+
+ electricChars: ""
+ };
});
CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
diff --git a/gulliver/js/codemirror/mode/tiki/index.html b/gulliver/js/codemirror/mode/tiki/index.html
index 7b85a44a7..5315dbfcd 100644
--- a/gulliver/js/codemirror/mode/tiki/index.html
+++ b/gulliver/js/codemirror/mode/tiki/index.html
@@ -1,16 +1,31 @@
-
-
-
- CodeMirror: Tiki wiki mode
-
-
-
-
-
-
-
-
- CodeMirror: Tiki wiki mode
+
+
+CodeMirror: Tiki wiki mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Tiki wiki mode
+
Headings
@@ -77,5 +92,4 @@ Plugin (inline):
});
-
-
+
diff --git a/gulliver/js/codemirror/mode/tiki/tiki.js b/gulliver/js/codemirror/mode/tiki/tiki.js
index 81e87ab21..e789163dc 100644
--- a/gulliver/js/codemirror/mode/tiki/tiki.js
+++ b/gulliver/js/codemirror/mode/tiki/tiki.js
@@ -1,309 +1,308 @@
CodeMirror.defineMode('tiki', function(config) {
- function inBlock(style, terminator, returnTokenizer) {
- return function(stream, state) {
- while (!stream.eol()) {
- if (stream.match(terminator)) {
- state.tokenize = inText;
- break;
- }
- stream.next();
- }
-
- if (returnTokenizer) state.tokenize = returnTokenizer;
-
- return style;
- };
- }
-
- function inLine(style) {
- return function(stream, state) {
- while(!stream.eol()) {
- stream.next();
- }
- state.tokenize = inText;
- return style;
- };
- }
-
- function inText(stream, state) {
- function chain(parser) {
- state.tokenize = parser;
- return parser(stream, state);
- }
-
- var sol = stream.sol();
- var ch = stream.next();
-
- //non start of line
- switch (ch) { //switch is generally much faster than if, so it is used here
- case "{": //plugin
- stream.eat("/");
- stream.eatSpace();
- var tagName = "";
- var c;
- while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c;
- state.tokenize = inPlugin;
- return "tag";
- break;
- case "_": //bold
- if (stream.eat("_")) {
- return chain(inBlock("strong", "__", inText));
- }
- break;
- case "'": //italics
- if (stream.eat("'")) {
- // Italic text
- return chain(inBlock("em", "''", inText));
- }
- break;
- case "(":// Wiki Link
- if (stream.eat("(")) {
- return chain(inBlock("variable-2", "))", inText));
- }
- break;
- case "[":// Weblink
- return chain(inBlock("variable-3", "]", inText));
- break;
- case "|": //table
- if (stream.eat("|")) {
- return chain(inBlock("comment", "||"));
- }
- break;
- case "-":
- if (stream.eat("=")) {//titleBar
- return chain(inBlock("header string", "=-", inText));
- } else if (stream.eat("-")) {//deleted
- return chain(inBlock("error tw-deleted", "--", inText));
- }
- break;
- case "=": //underline
- if (stream.match("==")) {
- return chain(inBlock("tw-underline", "===", inText));
- }
- break;
- case ":":
- if (stream.eat(":")) {
- return chain(inBlock("comment", "::"));
- }
- break;
- case "^": //box
- return chain(inBlock("tw-box", "^"));
- break;
- case "~": //np
- if (stream.match("np~")) {
- return chain(inBlock("meta", "~/np~"));
- }
- break;
- }
-
- //start of line types
- if (sol) {
- switch (ch) {
- case "!": //header at start of line
- if (stream.match('!!!!!')) {
- return chain(inLine("header string"));
- } else if (stream.match('!!!!')) {
- return chain(inLine("header string"));
- } else if (stream.match('!!!')) {
- return chain(inLine("header string"));
- } else if (stream.match('!!')) {
- return chain(inLine("header string"));
- } else {
- return chain(inLine("header string"));
- }
- break;
- case "*": //unordered list line item, or at start of line
- case "#": //ordered list line item, or at start of line
- case "+": //ordered list line item, or at start of line
- return chain(inLine("tw-listitem bracket"));
- break;
- }
- }
-
- //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
- return null;
- }
-
- var indentUnit = config.indentUnit;
+ function inBlock(style, terminator, returnTokenizer) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.match(terminator)) {
+ state.tokenize = inText;
+ break;
+ }
+ stream.next();
+ }
- // Return variables for tokenizers
- var pluginName, type;
- function inPlugin(stream, state) {
- var ch = stream.next();
- var peek = stream.peek();
-
- if (ch == "}") {
- state.tokenize = inText;
- //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
- return "tag";
- } else if (ch == "(" || ch == ")") {
- return "bracket";
- } else if (ch == "=") {
- type = "equals";
-
- if (peek == ">") {
- ch = stream.next();
- peek = stream.peek();
- }
-
- //here we detect values directly after equal character with no quotes
- if (!/[\'\"]/.test(peek)) {
- state.tokenize = inAttributeNoQuote();
- }
- //end detect values
-
- return "operator";
- } else if (/[\'\"]/.test(ch)) {
- state.tokenize = inAttribute(ch);
- return state.tokenize(stream, state);
- } else {
- stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
- return "keyword";
- }
- }
+ if (returnTokenizer) state.tokenize = returnTokenizer;
- function inAttribute(quote) {
- return function(stream, state) {
- while (!stream.eol()) {
- if (stream.next() == quote) {
- state.tokenize = inPlugin;
- break;
- }
- }
- return "string";
- };
- }
-
- function inAttributeNoQuote() {
- return function(stream, state) {
- while (!stream.eol()) {
- var ch = stream.next();
- var peek = stream.peek();
- if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
- state.tokenize = inPlugin;
- break;
- }
- }
- return "string";
- };
- }
+ return style;
+ };
+ }
- var curState, setStyle;
- function pass() {
- for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
- }
-
- function cont() {
- pass.apply(null, arguments);
- return true;
- }
+ function inLine(style) {
+ return function(stream, state) {
+ while(!stream.eol()) {
+ stream.next();
+ }
+ state.tokenize = inText;
+ return style;
+ };
+ }
- function pushContext(pluginName, startOfLine) {
- var noIndent = curState.context && curState.context.noIndent;
- curState.context = {
- prev: curState.context,
- pluginName: pluginName,
- indent: curState.indented,
- startOfLine: startOfLine,
- noIndent: noIndent
- };
- }
-
- function popContext() {
- if (curState.context) curState.context = curState.context.prev;
- }
+ function inText(stream, state) {
+ function chain(parser) {
+ state.tokenize = parser;
+ return parser(stream, state);
+ }
- function element(type) {
- if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
- else if (type == "closePlugin") {
- var err = false;
- if (curState.context) {
- err = curState.context.pluginName != pluginName;
- popContext();
- } else {
- err = true;
- }
- if (err) setStyle = "error";
- return cont(endcloseplugin(err));
- }
- else if (type == "string") {
- if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
- if (curState.tokenize == inText) popContext();
- return cont();
- }
- else return cont();
- }
-
- function endplugin(startOfLine) {
- return function(type) {
- if (
- type == "selfclosePlugin" ||
- type == "endPlugin"
- )
- return cont();
- if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
- return cont();
- };
- }
-
- function endcloseplugin(err) {
- return function(type) {
- if (err) setStyle = "error";
- if (type == "endPlugin") return cont();
- return pass();
- };
- }
+ var sol = stream.sol();
+ var ch = stream.next();
- function attributes(type) {
- if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
- if (type == "equals") return cont(attvalue, attributes);
- return pass();
- }
- function attvalue(type) {
- if (type == "keyword") {setStyle = "string"; return cont();}
- if (type == "string") return cont(attvaluemaybe);
- return pass();
- }
- function attvaluemaybe(type) {
- if (type == "string") return cont(attvaluemaybe);
- else return pass();
- }
- return {
- startState: function() {
- return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
- },
- token: function(stream, state) {
- if (stream.sol()) {
- state.startOfLine = true;
- state.indented = stream.indentation();
- }
- if (stream.eatSpace()) return null;
+ //non start of line
+ switch (ch) { //switch is generally much faster than if, so it is used here
+ case "{": //plugin
+ stream.eat("/");
+ stream.eatSpace();
+ var tagName = "";
+ var c;
+ while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c;
+ state.tokenize = inPlugin;
+ return "tag";
+ break;
+ case "_": //bold
+ if (stream.eat("_")) {
+ return chain(inBlock("strong", "__", inText));
+ }
+ break;
+ case "'": //italics
+ if (stream.eat("'")) {
+ // Italic text
+ return chain(inBlock("em", "''", inText));
+ }
+ break;
+ case "(":// Wiki Link
+ if (stream.eat("(")) {
+ return chain(inBlock("variable-2", "))", inText));
+ }
+ break;
+ case "[":// Weblink
+ return chain(inBlock("variable-3", "]", inText));
+ break;
+ case "|": //table
+ if (stream.eat("|")) {
+ return chain(inBlock("comment", "||"));
+ }
+ break;
+ case "-":
+ if (stream.eat("=")) {//titleBar
+ return chain(inBlock("header string", "=-", inText));
+ } else if (stream.eat("-")) {//deleted
+ return chain(inBlock("error tw-deleted", "--", inText));
+ }
+ break;
+ case "=": //underline
+ if (stream.match("==")) {
+ return chain(inBlock("tw-underline", "===", inText));
+ }
+ break;
+ case ":":
+ if (stream.eat(":")) {
+ return chain(inBlock("comment", "::"));
+ }
+ break;
+ case "^": //box
+ return chain(inBlock("tw-box", "^"));
+ break;
+ case "~": //np
+ if (stream.match("np~")) {
+ return chain(inBlock("meta", "~/np~"));
+ }
+ break;
+ }
- setStyle = type = pluginName = null;
- var style = state.tokenize(stream, state);
- if ((style || type) && style != "comment") {
- curState = state;
- while (true) {
- var comb = state.cc.pop() || element;
- if (comb(type || style)) break;
- }
- }
- state.startOfLine = false;
- return setStyle || style;
- },
- indent: function(state, textAfter) {
- var context = state.context;
- if (context && context.noIndent) return 0;
- if (context && /^{\//.test(textAfter))
- context = context.prev;
- while (context && !context.startOfLine)
- context = context.prev;
- if (context) return context.indent + indentUnit;
- else return 0;
- },
- electricChars: "/"
- };
+ //start of line types
+ if (sol) {
+ switch (ch) {
+ case "!": //header at start of line
+ if (stream.match('!!!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!!')) {
+ return chain(inLine("header string"));
+ } else if (stream.match('!!')) {
+ return chain(inLine("header string"));
+ } else {
+ return chain(inLine("header string"));
+ }
+ break;
+ case "*": //unordered list line item, or at start of line
+ case "#": //ordered list line item, or at start of line
+ case "+": //ordered list line item, or at start of line
+ return chain(inLine("tw-listitem bracket"));
+ break;
+ }
+ }
+
+ //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
+ return null;
+ }
+
+ var indentUnit = config.indentUnit;
+
+ // Return variables for tokenizers
+ var pluginName, type;
+ function inPlugin(stream, state) {
+ var ch = stream.next();
+ var peek = stream.peek();
+
+ if (ch == "}") {
+ state.tokenize = inText;
+ //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
+ return "tag";
+ } else if (ch == "(" || ch == ")") {
+ return "bracket";
+ } else if (ch == "=") {
+ type = "equals";
+
+ if (peek == ">") {
+ ch = stream.next();
+ peek = stream.peek();
+ }
+
+ //here we detect values directly after equal character with no quotes
+ if (!/[\'\"]/.test(peek)) {
+ state.tokenize = inAttributeNoQuote();
+ }
+ //end detect values
+
+ return "operator";
+ } else if (/[\'\"]/.test(ch)) {
+ state.tokenize = inAttribute(ch);
+ return state.tokenize(stream, state);
+ } else {
+ stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
+ return "keyword";
+ }
+ }
+
+ function inAttribute(quote) {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ if (stream.next() == quote) {
+ state.tokenize = inPlugin;
+ break;
+ }
+ }
+ return "string";
+ };
+ }
+
+ function inAttributeNoQuote() {
+ return function(stream, state) {
+ while (!stream.eol()) {
+ var ch = stream.next();
+ var peek = stream.peek();
+ if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
+ state.tokenize = inPlugin;
+ break;
+ }
+ }
+ return "string";
+};
+ }
+
+var curState, setStyle;
+function pass() {
+ for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
+}
+
+function cont() {
+ pass.apply(null, arguments);
+ return true;
+}
+
+function pushContext(pluginName, startOfLine) {
+ var noIndent = curState.context && curState.context.noIndent;
+ curState.context = {
+ prev: curState.context,
+ pluginName: pluginName,
+ indent: curState.indented,
+ startOfLine: startOfLine,
+ noIndent: noIndent
+ };
+}
+
+function popContext() {
+ if (curState.context) curState.context = curState.context.prev;
+}
+
+function element(type) {
+ if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
+ else if (type == "closePlugin") {
+ var err = false;
+ if (curState.context) {
+ err = curState.context.pluginName != pluginName;
+ popContext();
+ } else {
+ err = true;
+ }
+ if (err) setStyle = "error";
+ return cont(endcloseplugin(err));
+ }
+ else if (type == "string") {
+ if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
+ if (curState.tokenize == inText) popContext();
+ return cont();
+ }
+ else return cont();
+}
+
+function endplugin(startOfLine) {
+ return function(type) {
+ if (
+ type == "selfclosePlugin" ||
+ type == "endPlugin"
+ )
+ return cont();
+ if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
+ return cont();
+ };
+}
+
+function endcloseplugin(err) {
+ return function(type) {
+ if (err) setStyle = "error";
+ if (type == "endPlugin") return cont();
+ return pass();
+ };
+}
+
+function attributes(type) {
+ if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
+ if (type == "equals") return cont(attvalue, attributes);
+ return pass();
+}
+function attvalue(type) {
+ if (type == "keyword") {setStyle = "string"; return cont();}
+ if (type == "string") return cont(attvaluemaybe);
+ return pass();
+}
+function attvaluemaybe(type) {
+ if (type == "string") return cont(attvaluemaybe);
+ else return pass();
+}
+return {
+ startState: function() {
+ return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
+ },
+ token: function(stream, state) {
+ if (stream.sol()) {
+ state.startOfLine = true;
+ state.indented = stream.indentation();
+ }
+ if (stream.eatSpace()) return null;
+
+ setStyle = type = pluginName = null;
+ var style = state.tokenize(stream, state);
+ if ((style || type) && style != "comment") {
+ curState = state;
+ while (true) {
+ var comb = state.cc.pop() || element;
+ if (comb(type || style)) break;
+ }
+ }
+ state.startOfLine = false;
+ return setStyle || style;
+ },
+ indent: function(state, textAfter) {
+ var context = state.context;
+ if (context && context.noIndent) return 0;
+ if (context && /^{\//.test(textAfter))
+ context = context.prev;
+ while (context && !context.startOfLine)
+ context = context.prev;
+ if (context) return context.indent + indentUnit;
+ else return 0;
+ },
+ electricChars: "/"
+ };
});
-//I figure, why not
CodeMirror.defineMIME("text/tiki", "tiki");
diff --git a/gulliver/js/codemirror/mode/turtle/index.html b/gulliver/js/codemirror/mode/turtle/index.html
index 5e56e5755..74b5f896d 100644
--- a/gulliver/js/codemirror/mode/turtle/index.html
+++ b/gulliver/js/codemirror/mode/turtle/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: Turtle mode
-
-
-
-
-
-
-
- CodeMirror: Turtle mode
-
+
+CodeMirror: Turtle mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Turtle mode
+
@prefix foaf: .
@prefix geo: .
@prefix rdf: .
@@ -35,5 +48,4 @@
MIME types defined: text/turtle.
-
-
+
diff --git a/gulliver/js/codemirror/mode/turtle/turtle.js b/gulliver/js/codemirror/mode/turtle/turtle.js
index 5c7c28eb0..e118bfbce 100644
--- a/gulliver/js/codemirror/mode/turtle/turtle.js
+++ b/gulliver/js/codemirror/mode/turtle/turtle.js
@@ -33,23 +33,23 @@ CodeMirror.defineMode("turtle", function(config) {
return null;
}
else if (ch == ":") {
- return "operator";
- } else {
+ return "operator";
+ } else {
stream.eatWhile(/[_\w\d]/);
if(stream.peek() == ":") {
return "variable-3";
} else {
- var word = stream.current();
-
- if(keywords.test(word)) {
- return "meta";
- }
-
- if(ch >= "A" && ch <= "Z") {
- return "comment";
- } else {
- return "keyword";
- }
+ var word = stream.current();
+
+ if(keywords.test(word)) {
+ return "meta";
+ }
+
+ if(ch >= "A" && ch <= "Z") {
+ return "comment";
+ } else {
+ return "keyword";
+ }
}
var word = stream.current();
if (ops.test(word))
@@ -119,7 +119,7 @@ CodeMirror.defineMode("turtle", function(config) {
state.context.col = stream.column();
}
}
-
+
return style;
},
diff --git a/gulliver/js/codemirror/mode/vb/LICENSE.txt b/gulliver/js/codemirror/mode/vb/LICENSE.txt
deleted file mode 100644
index 60839703a..000000000
--- a/gulliver/js/codemirror/mode/vb/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2012 Codility Limited, 107 Cheapside, London EC2V 6DN, UK
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
diff --git a/gulliver/js/codemirror/mode/vb/index.html b/gulliver/js/codemirror/mode/vb/index.html
index 74dd5e816..42c3e5261 100644
--- a/gulliver/js/codemirror/mode/vb/index.html
+++ b/gulliver/js/codemirror/mode/vb/index.html
@@ -1,21 +1,36 @@
-
-
-
- CodeMirror: VB.NET mode
-
-
-
-
-
-
-
-
-
- CodeMirror: VB.NET mode
+
+
+
+
+
+
+
+
+
+VB.NET mode
+
-
MIME type defined: text/x-vb.
-
+
diff --git a/gulliver/js/codemirror/mode/vb/vb.js b/gulliver/js/codemirror/mode/vb/vb.js
index 764c07101..27b227195 100644
--- a/gulliver/js/codemirror/mode/vb/vb.js
+++ b/gulliver/js/codemirror/mode/vb/vb.js
@@ -1,10 +1,10 @@
CodeMirror.defineMode("vb", function(conf, parserConf) {
var ERRORCLASS = 'error';
-
+
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
}
-
+
var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]");
var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
@@ -15,9 +15,9 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try'];
var middleKeywords = ['else','elseif','case', 'catch'];
var endKeywords = ['next','loop'];
-
+
var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']);
- var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until',
+ var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until',
'goto', 'byval','byref','new','handles','property', 'return',
'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false'];
var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single'];
@@ -34,13 +34,13 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
var indentInfo = null;
-
+
function indent(_stream, state) {
state.currentIndent++;
}
-
+
function dedent(_stream, state) {
state.currentIndent--;
}
@@ -49,16 +49,16 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
if (stream.eatSpace()) {
return null;
}
-
+
var ch = stream.peek();
-
+
// Handle Comments
if (ch === "'") {
stream.skipToEnd();
return 'comment';
}
-
-
+
+
// Handle Number Literals
if (stream.match(/^((&H)|(&O))?[0-9\.a-f]/i, false)) {
var floatLiteral = false;
@@ -66,7 +66,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; }
else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; }
else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; }
-
+
if (floatLiteral) {
// Float literals may be "imaginary"
stream.eat(/J/i);
@@ -93,13 +93,13 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
return 'number';
}
}
-
+
// Handle Strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
}
-
+
// Handle operators and Delimiters
if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
return null;
@@ -137,28 +137,28 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
dedent(stream,state);
return 'keyword';
}
-
+
if (stream.match(types)) {
return 'keyword';
}
-
+
if (stream.match(keywords)) {
return 'keyword';
}
-
+
if (stream.match(identifiers)) {
return 'variable';
}
-
+
// Handle non-detected items
stream.next();
return ERRORCLASS;
}
-
+
function tokenStringFactory(delimiter) {
var singleline = delimiter.length == 1;
var OUTCLASS = 'string';
-
+
return function(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^'"]/);
@@ -179,7 +179,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
return OUTCLASS;
};
}
-
+
function tokenLexer(stream, state) {
var style = state.tokenize(stream, state);
@@ -195,8 +195,8 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
return ERRORCLASS;
}
}
-
-
+
+
var delimiter_index = '[({'.indexOf(current);
if (delimiter_index !== -1) {
indent(stream, state );
@@ -212,7 +212,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
return ERRORCLASS;
}
}
-
+
return style;
}
@@ -229,7 +229,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
};
},
-
+
token: function(stream, state) {
if (stream.sol()) {
state.currentIndent += state.nextLineIndent;
@@ -237,24 +237,23 @@ CodeMirror.defineMode("vb", function(conf, parserConf) {
state.doInCurrentLine = 0;
}
var style = tokenLexer(stream, state);
-
+
state.lastToken = {style:style, content: stream.current()};
-
-
-
+
+
+
return style;
},
-
+
indent: function(state, textAfter) {
var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
if(state.currentIndent < 0) return 0;
return state.currentIndent * conf.indentUnit;
}
-
+
};
return external;
});
CodeMirror.defineMIME("text/x-vb", "vb");
-
diff --git a/gulliver/js/codemirror/mode/vbscript/index.html b/gulliver/js/codemirror/mode/vbscript/index.html
index 8c86f9ef9..9b506b798 100644
--- a/gulliver/js/codemirror/mode/vbscript/index.html
+++ b/gulliver/js/codemirror/mode/vbscript/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: VBScript mode
-
-
-
-
-
-
-
- CodeMirror: VBScript mode
+
+CodeMirror: VBScript mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+VBScript mode
+
' Pete Guhl
@@ -32,11 +46,10 @@ End If
MIME types defined: text/vbscript.
-
-
-
+
diff --git a/gulliver/js/codemirror/mode/vbscript/vbscript.js b/gulliver/js/codemirror/mode/vbscript/vbscript.js
index 65d6c2127..0a97fb640 100644
--- a/gulliver/js/codemirror/mode/vbscript/vbscript.js
+++ b/gulliver/js/codemirror/mode/vbscript/vbscript.js
@@ -1,26 +1,334 @@
-CodeMirror.defineMode("vbscript", function() {
- var regexVBScriptKeyword = /^(?:Call|Case|CDate|Clear|CInt|CLng|Const|CStr|Description|Dim|Do|Each|Else|ElseIf|End|Err|Error|Exit|False|For|Function|If|LCase|Loop|LTrim|Next|Nothing|Now|Number|On|Preserve|Quit|ReDim|Resume|RTrim|Select|Set|Sub|Then|To|Trim|True|UBound|UCase|Until|VbCr|VbCrLf|VbLf|VbTab)$/im;
+/*
+For extra ASP classic objects, initialize CodeMirror instance with this option:
+ isASP: true
- return {
- token: function(stream) {
- if (stream.eatSpace()) return null;
- var ch = stream.next();
- if (ch == "'") {
- stream.skipToEnd();
- return "comment";
- }
- if (ch == '"') {
- stream.skipTo('"');
- return "string";
- }
+E.G.:
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ lineNumbers: true,
+ isASP: true
+ });
+*/
+CodeMirror.defineMode("vbscript", function(conf, parserConf) {
+ var ERRORCLASS = 'error';
- if (/\w/.test(ch)) {
- stream.eatWhile(/\w/);
- if (regexVBScriptKeyword.test(stream.current())) return "keyword";
- }
- return null;
+ function wordRegexp(words) {
+ return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
}
- };
+
+ var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]");
+ var doubleOperators = new RegExp("^((<>)|(<=)|(>=))");
+ var singleDelimiters = new RegExp('^[\\.,]');
+ var brakets = new RegExp('^[\\(\\)]');
+ var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*");
+
+ var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for'];
+ var middleKeywords = ['else','elseif','case'];
+ var endKeywords = ['next','loop','wend'];
+
+ var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']);
+ var commonkeywords = ['dim', 'redim', 'then', 'until', 'randomize',
+ 'byval','byref','new','property', 'exit', 'in',
+ 'const','private', 'public',
+ 'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me'];
+
+ //This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx
+ var atomWords = ['true', 'false', 'nothing', 'empty', 'null'];
+ //This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx
+ var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart',
+ 'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject',
+ 'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left',
+ 'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round',
+ 'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp',
+ 'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year'];
+
+ //This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx
+ var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare',
+ 'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek',
+ 'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError',
+ 'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2',
+ 'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo',
+ 'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse',
+ 'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray'];
+ //This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx
+ var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp'];
+ var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count'];
+ var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit'];
+
+ var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application'];
+ var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response
+ 'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request
+ 'contents', 'staticobjects', //application
+ 'codepage', 'lcid', 'sessionid', 'timeout', //session
+ 'scripttimeout']; //server
+ var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response
+ 'binaryread', //request
+ 'remove', 'removeall', 'lock', 'unlock', //application
+ 'abandon', //session
+ 'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server
+
+ var knownWords = knownMethods.concat(knownProperties);
+
+ builtinObjsWords = builtinObjsWords.concat(builtinConsts);
+
+ if (conf.isASP){
+ builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords);
+ knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties);
+ };
+
+ var keywords = wordRegexp(commonkeywords);
+ var atoms = wordRegexp(atomWords);
+ var builtinFuncs = wordRegexp(builtinFuncsWords);
+ var builtinObjs = wordRegexp(builtinObjsWords);
+ var known = wordRegexp(knownWords);
+ var stringPrefixes = '"';
+
+ var opening = wordRegexp(openingKeywords);
+ var middle = wordRegexp(middleKeywords);
+ var closing = wordRegexp(endKeywords);
+ var doubleClosing = wordRegexp(['end']);
+ var doOpening = wordRegexp(['do']);
+ var noIndentWords = wordRegexp(['on error resume next', 'exit']);
+ var comment = wordRegexp(['rem']);
+
+
+ function indent(_stream, state) {
+ state.currentIndent++;
+ }
+
+ function dedent(_stream, state) {
+ state.currentIndent--;
+ }
+ // tokenizers
+ function tokenBase(stream, state) {
+ if (stream.eatSpace()) {
+ return 'space';
+ //return null;
+ }
+
+ var ch = stream.peek();
+
+ // Handle Comments
+ if (ch === "'") {
+ stream.skipToEnd();
+ return 'comment';
+ }
+ if (stream.match(comment)){
+ stream.skipToEnd();
+ return 'comment';
+ }
+
+
+ // Handle Number Literals
+ if (stream.match(/^((&H)|(&O))?[0-9\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i, false)) {
+ var floatLiteral = false;
+ // Floats
+ if (stream.match(/^\d*\.\d+/i)) { floatLiteral = true; }
+ else if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
+ else if (stream.match(/^\.\d+/)) { floatLiteral = true; }
+
+ if (floatLiteral) {
+ // Float literals may be "imaginary"
+ stream.eat(/J/i);
+ return 'number';
+ }
+ // Integers
+ var intLiteral = false;
+ // Hex
+ if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }
+ // Octal
+ else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
+ // Decimal
+ else if (stream.match(/^[1-9]\d*F?/)) {
+ // Decimal literals may be "imaginary"
+ stream.eat(/J/i);
+ // TODO - Can you have imaginary longs?
+ intLiteral = true;
+ }
+ // Zero by itself with no other piece of number.
+ else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
+ if (intLiteral) {
+ // Integer literals may be "long"
+ stream.eat(/L/i);
+ return 'number';
+ }
+ }
+
+ // Handle Strings
+ if (stream.match(stringPrefixes)) {
+ state.tokenize = tokenStringFactory(stream.current());
+ return state.tokenize(stream, state);
+ }
+
+ // Handle operators and Delimiters
+ if (stream.match(doubleOperators)
+ || stream.match(singleOperators)
+ || stream.match(wordOperators)) {
+ return 'operator';
+ }
+ if (stream.match(singleDelimiters)) {
+ return null;
+ }
+
+ if (stream.match(brakets)) {
+ return "bracket";
+ }
+
+ if (stream.match(noIndentWords)) {
+ state.doInCurrentLine = true;
+
+ return 'keyword';
+ }
+
+ if (stream.match(doOpening)) {
+ indent(stream,state);
+ state.doInCurrentLine = true;
+
+ return 'keyword';
+ }
+ if (stream.match(opening)) {
+ if (! state.doInCurrentLine)
+ indent(stream,state);
+ else
+ state.doInCurrentLine = false;
+
+ return 'keyword';
+ }
+ if (stream.match(middle)) {
+ return 'keyword';
+ }
+
+
+ if (stream.match(doubleClosing)) {
+ dedent(stream,state);
+ dedent(stream,state);
+
+ return 'keyword';
+ }
+ if (stream.match(closing)) {
+ if (! state.doInCurrentLine)
+ dedent(stream,state);
+ else
+ state.doInCurrentLine = false;
+
+ return 'keyword';
+ }
+
+ if (stream.match(keywords)) {
+ return 'keyword';
+ }
+
+ if (stream.match(atoms)) {
+ return 'atom';
+ }
+
+ if (stream.match(known)) {
+ return 'variable-2';
+ }
+
+ if (stream.match(builtinFuncs)) {
+ return 'builtin';
+ }
+
+ if (stream.match(builtinObjs)){
+ return 'variable-2';
+ }
+
+ if (stream.match(identifiers)) {
+ return 'variable';
+ }
+
+ // Handle non-detected items
+ stream.next();
+ return ERRORCLASS;
+ }
+
+ function tokenStringFactory(delimiter) {
+ var singleline = delimiter.length == 1;
+ var OUTCLASS = 'string';
+
+ return function(stream, state) {
+ while (!stream.eol()) {
+ stream.eatWhile(/[^'"]/);
+ if (stream.match(delimiter)) {
+ state.tokenize = tokenBase;
+ return OUTCLASS;
+ } else {
+ stream.eat(/['"]/);
+ }
+ }
+ if (singleline) {
+ if (parserConf.singleLineStringErrors) {
+ return ERRORCLASS;
+ } else {
+ state.tokenize = tokenBase;
+ }
+ }
+ return OUTCLASS;
+ };
+ }
+
+
+ function tokenLexer(stream, state) {
+ var style = state.tokenize(stream, state);
+ var current = stream.current();
+
+ // Handle '.' connected identifiers
+ if (current === '.') {
+ style = state.tokenize(stream, state);
+
+ current = stream.current();
+ if (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword'){//|| knownWords.indexOf(current.substring(1)) > -1) {
+ if (style === 'builtin' || style === 'keyword') style='variable';
+ if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2';
+
+ return style;
+ } else {
+ return ERRORCLASS;
+ }
+ }
+
+ return style;
+ }
+
+ var external = {
+ electricChars:"dDpPtTfFeE ",
+ startState: function() {
+ return {
+ tokenize: tokenBase,
+ lastToken: null,
+ currentIndent: 0,
+ nextLineIndent: 0,
+ doInCurrentLine: false,
+ ignoreKeyword: false
+
+
+ };
+ },
+
+ token: function(stream, state) {
+ if (stream.sol()) {
+ state.currentIndent += state.nextLineIndent;
+ state.nextLineIndent = 0;
+ state.doInCurrentLine = 0;
+ }
+ var style = tokenLexer(stream, state);
+
+ state.lastToken = {style:style, content: stream.current()};
+
+ if (style==='space') style=null;
+
+ return style;
+ },
+
+ indent: function(state, textAfter) {
+ var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
+ if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
+ if(state.currentIndent < 0) return 0;
+ return state.currentIndent * conf.indentUnit;
+ }
+
+ };
+ return external;
});
CodeMirror.defineMIME("text/vbscript", "vbscript");
diff --git a/gulliver/js/codemirror/mode/velocity/index.html b/gulliver/js/codemirror/mode/velocity/index.html
index fb59cb590..023542d1d 100644
--- a/gulliver/js/codemirror/mode/velocity/index.html
+++ b/gulliver/js/codemirror/mode/velocity/index.html
@@ -1,18 +1,31 @@
-
-
-
- CodeMirror: Velocity mode
-
-
-
-
-
-
-
-
- CodeMirror: Velocity mode
-
+
+CodeMirror: Velocity mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Velocity mode
+
## Velocity Code Demo
#*
based on PL/SQL mode by Peter Raganitsch, adapted to Velocity by Steve O'Hara ( http://www.pivotal-solutions.co.uk )
@@ -62,13 +75,17 @@
$someObject.getValues("this is a string split
across lines")
+$someObject("This plus $something in the middle").method(7567).property
+
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
$something
+ $bodyContent
#end
#end
#tablerows("red" ["dadsdf","dsa"])
+#@tablerows("red" ["dadsdf","dsa"]) some body content #end
Variable reference: #set( $monkey = $bill )
String literal: #set( $monkey.Friend = 'monica' )
@@ -99,5 +116,4 @@ Addition: #set( $value = $foo + 1 )
MIME types defined: text/velocity.
-
-
+
diff --git a/gulliver/js/codemirror/mode/velocity/velocity.js b/gulliver/js/codemirror/mode/velocity/velocity.js
index 43a97ba67..968d8799e 100644
--- a/gulliver/js/codemirror/mode/velocity/velocity.js
+++ b/gulliver/js/codemirror/mode/velocity/velocity.js
@@ -9,7 +9,7 @@ CodeMirror.defineMode("velocity", function() {
"#{end} #{else} #{break} #{stop}");
var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " +
"#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}");
- var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent $velocityCount");
+ var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent");
var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
function chain(stream, state, f) {
@@ -20,30 +20,50 @@ CodeMirror.defineMode("velocity", function() {
var beforeParams = state.beforeParams;
state.beforeParams = false;
var ch = stream.next();
- // start of string?
- if ((ch == '"' || ch == "'") && state.inParams)
+ // start of unparsed string?
+ if ((ch == "'") && state.inParams) {
+ state.lastTokenWasBuiltin = false;
return chain(stream, state, tokenString(ch));
+ }
+ // start of parsed string?
+ else if ((ch == '"')) {
+ state.lastTokenWasBuiltin = false;
+ if (state.inString) {
+ state.inString = false;
+ return "string";
+ }
+ else if (state.inParams)
+ return chain(stream, state, tokenString(ch));
+ }
// is it one of the special signs []{}().,;? Seperator?
else if (/[\[\]{}\(\),;\.]/.test(ch)) {
- if (ch == "(" && beforeParams) state.inParams = true;
- else if (ch == ")") state.inParams = false;
+ if (ch == "(" && beforeParams)
+ state.inParams = true;
+ else if (ch == ")") {
+ state.inParams = false;
+ state.lastTokenWasBuiltin = true;
+ }
return null;
}
// start of a number value?
else if (/\d/.test(ch)) {
+ state.lastTokenWasBuiltin = false;
stream.eatWhile(/[\w\.]/);
return "number";
}
// multi line comment?
else if (ch == "#" && stream.eat("*")) {
+ state.lastTokenWasBuiltin = false;
return chain(stream, state, tokenComment);
}
// unparsed content?
else if (ch == "#" && stream.match(/ *\[ *\[/)) {
+ state.lastTokenWasBuiltin = false;
return chain(stream, state, tokenUnparsed);
}
// single line comment?
else if (ch == "#" && stream.eat("#")) {
+ state.lastTokenWasBuiltin = false;
stream.skipToEnd();
return "comment";
}
@@ -51,33 +71,44 @@ CodeMirror.defineMode("velocity", function() {
else if (ch == "$") {
stream.eatWhile(/[\w\d\$_\.{}]/);
// is it one of the specials?
- if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) {
+ if (specials && specials.propertyIsEnumerable(stream.current())) {
return "keyword";
}
else {
+ state.lastTokenWasBuiltin = true;
state.beforeParams = true;
return "builtin";
}
}
// is it a operator?
else if (isOperatorChar.test(ch)) {
+ state.lastTokenWasBuiltin = false;
stream.eatWhile(isOperatorChar);
return "operator";
}
else {
// get the whole word
- stream.eatWhile(/[\w\$_{}]/);
- var word = stream.current().toLowerCase();
+ stream.eatWhile(/[\w\$_{}@]/);
+ var word = stream.current();
// is it one of the listed keywords?
if (keywords && keywords.propertyIsEnumerable(word))
return "keyword";
// is it one of the listed functions?
if (functions && functions.propertyIsEnumerable(word) ||
- stream.current().match(/^#[a-z0-9_]+ *$/i) && stream.peek()=="(") {
+ (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") &&
+ !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) {
state.beforeParams = true;
+ state.lastTokenWasBuiltin = false;
return "keyword";
}
+ if (state.inString) {
+ state.lastTokenWasBuiltin = false;
+ return "string";
+ }
+ if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin)
+ return "builtin";
// default: just a "word"
+ state.lastTokenWasBuiltin = false;
return null;
}
}
@@ -86,7 +117,12 @@ CodeMirror.defineMode("velocity", function() {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
- if (next == quote && !escaped) {
+ if ((next == quote) && !escaped) {
+ end = true;
+ break;
+ }
+ if (quote=='"' && stream.peek() == '$' && !escaped) {
+ state.inString = true;
end = true;
break;
}
@@ -130,14 +166,20 @@ CodeMirror.defineMode("velocity", function() {
return {
tokenize: tokenBase,
beforeParams: false,
- inParams: false
+ inParams: false,
+ inString: false,
+ lastTokenWasBuiltin: false
};
},
token: function(stream, state) {
if (stream.eatSpace()) return null;
return state.tokenize(stream, state);
- }
+ },
+ blockCommentStart: "#*",
+ blockCommentEnd: "*#",
+ lineComment: "##",
+ fold: "velocity"
};
});
diff --git a/gulliver/js/codemirror/mode/verilog/index.html b/gulliver/js/codemirror/mode/verilog/index.html
index f7c88c623..cc7105644 100644
--- a/gulliver/js/codemirror/mode/verilog/index.html
+++ b/gulliver/js/codemirror/mode/verilog/index.html
@@ -1,17 +1,29 @@
-
-
-
- CodeMirror: Verilog mode
-
-
-
-
-
-
-
- CodeMirror: Verilog mode
+CodeMirror: Verilog mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Verilog mode
/* Verilog demo code */
@@ -117,5 +129,4 @@ endmodule
object whose property names are the keywords in the language.
MIME types defined: text/x-verilog (Verilog code).
-
-
+
diff --git a/gulliver/js/codemirror/mode/xml/index.html b/gulliver/js/codemirror/mode/xml/index.html
index 9628d954c..873099aab 100644
--- a/gulliver/js/codemirror/mode/xml/index.html
+++ b/gulliver/js/codemirror/mode/xml/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: XML mode
-
-
-
-
-
-
-
- CodeMirror: XML mode
-
+
+CodeMirror: XML mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+XML mode
+
<html style="color: green">
<!-- this is a comment -->
<head>
@@ -41,5 +54,4 @@
MIME types defined: application/xml, text/html.
-
-
+
diff --git a/gulliver/js/codemirror/mode/xml/xml.js b/gulliver/js/codemirror/mode/xml/xml.js
index a68b03384..96b51ff97 100644
--- a/gulliver/js/codemirror/mode/xml/xml.js
+++ b/gulliver/js/codemirror/mode/xml/xml.js
@@ -1,6 +1,7 @@
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
+ var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag || true;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
@@ -44,7 +45,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
- var tagName, type;
+ var tagName, type, setStyle;
function inText(stream, state) {
function chain(parser) {
@@ -58,35 +59,33 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
- }
- else if (stream.match("--")) return chain(inBlock("comment", "-->"));
- else if (stream.match("DOCTYPE", true, true)) {
+ } else if (stream.match("--")) {
+ return chain(inBlock("comment", "-->"));
+ } else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
+ } else {
+ return null;
}
- else return null;
- }
- else if (stream.eat("?")) {
+ } else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
- }
- else {
+ } else {
var isClose = stream.eat("/");
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
- if (!tagName) return "error";
+ if (!tagName) return "tag error";
type = isClose ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag";
}
- }
- else if (ch == "&") {
+ } else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
- ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
+ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
@@ -94,8 +93,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
- }
- else {
+ } else {
stream.eatWhile(/[^&<]/);
return null;
}
@@ -107,23 +105,27 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag";
- }
- else if (ch == "=") {
+ } else if (ch == "=") {
type = "equals";
return null;
- }
- else if (/[\'\"]/.test(ch)) {
+ } else if (ch == "<") {
+ state.tokenize = inText;
+ state.state = baseState;
+ state.tagName = state.tagStart = null;
+ var next = state.tokenize(stream, state);
+ return next ? next + " error" : "error";
+ } else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
+ state.stringStartCol = stream.column();
return state.tokenize(stream, state);
- }
- else {
+ } else {
stream.eatWhile(/[^\s\u00a0=<>\"\']/);
return "word";
}
}
function inAttribute(quote) {
- return function(stream, state) {
+ var closure = function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
@@ -132,6 +134,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
}
return "string";
};
+ closure.isInAttribute = true;
+ return closure;
}
function inBlock(style, terminator) {
@@ -167,146 +171,143 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
};
}
- var curState, curStream, setStyle;
- function pass() {
- for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
+ function Context(state, tagName, startOfLine) {
+ this.prev = state.context;
+ this.tagName = tagName;
+ this.indent = state.indented;
+ this.startOfLine = startOfLine;
+ if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
+ this.noIndent = true;
}
- function cont() {
- pass.apply(null, arguments);
- return true;
+ function popContext(state) {
+ if (state.context) state.context = state.context.prev;
+ }
+ function maybePopContext(state, nextTagName) {
+ var parentTagName;
+ while (true) {
+ if (!state.context) {
+ return;
+ }
+ parentTagName = state.context.tagName.toLowerCase();
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
+ return;
+ }
+ popContext(state);
+ }
}
- function pushContext(tagName, startOfLine) {
- var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
- curState.context = {
- prev: curState.context,
- tagName: tagName,
- indent: curState.indented,
- startOfLine: startOfLine,
- noIndent: noIndent
- };
- }
- function popContext() {
- if (curState.context) curState.context = curState.context.prev;
- }
-
- function element(type) {
+ function baseState(type, stream, state) {
if (type == "openTag") {
- curState.tagName = tagName;
- curState.tagStart = curStream.column();
- return cont(attributes, endtag(curState.startOfLine));
+ state.tagName = tagName;
+ state.tagStart = stream.column();
+ return attrState;
} else if (type == "closeTag") {
var err = false;
- if (curState.context) {
- if (curState.context.tagName != tagName) {
- if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
- popContext();
- }
- err = !curState.context || curState.context.tagName != tagName;
+ if (state.context) {
+ if (state.context.tagName != tagName) {
+ if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName.toLowerCase()))
+ popContext(state);
+ err = !state.context || state.context.tagName != tagName;
}
} else {
err = true;
}
if (err) setStyle = "error";
- return cont(endclosetag(err));
+ return err ? closeStateErr : closeState;
+ } else {
+ return baseState;
}
- return cont();
}
- function endtag(startOfLine) {
- return function(type) {
- var tagName = curState.tagName;
- curState.tagName = curState.tagStart = null;
- if (type == "selfcloseTag" ||
- (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
- maybePopContext(tagName.toLowerCase());
- return cont();
- }
- if (type == "endTag") {
- maybePopContext(tagName.toLowerCase());
- pushContext(tagName, startOfLine);
- return cont();
- }
- return cont();
- };
- }
- function endclosetag(err) {
- return function(type) {
- if (err) setStyle = "error";
- if (type == "endTag") { popContext(); return cont(); }
+ function closeState(type, _stream, state) {
+ if (type != "endTag") {
setStyle = "error";
- return cont(arguments.callee);
- };
- }
- function maybePopContext(nextTagName) {
- var parentTagName;
- while (true) {
- if (!curState.context) {
- return;
- }
- parentTagName = curState.context.tagName.toLowerCase();
- if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
- !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
- return;
- }
- popContext();
+ return closeState;
}
+ popContext(state);
+ return baseState;
+ }
+ function closeStateErr(type, stream, state) {
+ setStyle = "error";
+ return closeState(type, stream, state);
}
- function attributes(type) {
- if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
- if (type == "endTag" || type == "selfcloseTag") return pass();
+ function attrState(type, _stream, state) {
+ if (type == "word") {
+ setStyle = "attribute";
+ return attrEqState;
+ } else if (type == "endTag" || type == "selfcloseTag") {
+ var tagName = state.tagName, tagStart = state.tagStart;
+ state.tagName = state.tagStart = null;
+ if (type == "selfcloseTag" ||
+ Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase())) {
+ maybePopContext(state, tagName.toLowerCase());
+ } else {
+ maybePopContext(state, tagName.toLowerCase());
+ state.context = new Context(state, tagName, tagStart == state.indented);
+ }
+ return baseState;
+ }
setStyle = "error";
- return cont(attributes);
+ return attrState;
}
- function attribute(type) {
- if (type == "equals") return cont(attvalue, attributes);
+ function attrEqState(type, stream, state) {
+ if (type == "equals") return attrValueState;
if (!Kludges.allowMissing) setStyle = "error";
- else if (type == "word") setStyle = "attribute";
- return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
+ return attrState(type, stream, state);
}
- function attvalue(type) {
- if (type == "string") return cont(attvaluemaybe);
- if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
+ function attrValueState(type, stream, state) {
+ if (type == "string") return attrContinuedState;
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
setStyle = "error";
- return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
+ return attrState(type, stream, state);
}
- function attvaluemaybe(type) {
- if (type == "string") return cont(attvaluemaybe);
- else return pass();
+ function attrContinuedState(type, stream, state) {
+ if (type == "string") return attrContinuedState;
+ return attrState(type, stream, state);
}
return {
startState: function() {
- return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
+ return {tokenize: inText,
+ state: baseState,
+ indented: 0,
+ tagName: null, tagStart: null,
+ context: null};
},
token: function(stream, state) {
- if (!state.tagName && stream.sol()) {
- state.startOfLine = true;
+ if (!state.tagName && stream.sol())
state.indented = stream.indentation();
- }
- if (stream.eatSpace()) return null;
- setStyle = type = tagName = null;
+ if (stream.eatSpace()) return null;
+ tagName = type = null;
var style = state.tokenize(stream, state);
- state.type = type;
if ((style || type) && style != "comment") {
- curState = state; curStream = stream;
- while (true) {
- var comb = state.cc.pop() || element;
- if (comb(type || style)) break;
- }
+ setStyle = null;
+ state.state = state.state(type || style, stream, state);
+ if (setStyle)
+ style = setStyle == "error" ? style + " error" : setStyle;
}
- state.startOfLine = false;
- return setStyle || style;
+ return style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
- if ((state.tokenize != inTag && state.tokenize != inText) ||
- context && context.noIndent)
+ // Indent multi-line strings (e.g. css).
+ if (state.tokenize.isInAttribute) {
+ return state.stringStartCol + 1;
+ }
+ if (context && context.noIndent) return CodeMirror.Pass;
+ if (state.tokenize != inTag && state.tokenize != inText)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
- if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor;
+ // Indent the starts of attribute names.
+ if (state.tagName) {
+ if (multilineTagIndentPastTag)
+ return state.tagStart + state.tagName.length + 2;
+ else
+ return state.tagStart + indentUnit * multilineTagIndentFactor;
+ }
if (alignCDATA && /",
- configuration: parserConfig.htmlMode ? "html" : "xml"
+ configuration: parserConfig.htmlMode ? "html" : "xml",
+ helperType: parserConfig.htmlMode ? "html" : "xml"
};
});
diff --git a/gulliver/js/codemirror/mode/xquery/LICENSE b/gulliver/js/codemirror/mode/xquery/LICENSE
deleted file mode 100644
index 2a2d47be5..000000000
--- a/gulliver/js/codemirror/mode/xquery/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (C) 2011 by MarkLogic Corporation
-Author: Mike Brevoort
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
\ No newline at end of file
diff --git a/gulliver/js/codemirror/mode/xquery/index.html b/gulliver/js/codemirror/mode/xquery/index.html
index 27acb8978..3baf5e3e3 100644
--- a/gulliver/js/codemirror/mode/xquery/index.html
+++ b/gulliver/js/codemirror/mode/xquery/index.html
@@ -1,46 +1,36 @@
-
-
-
-
-
- CodeMirror: XQuery mode
-
-
-
-
-
-
-
-
- CodeMirror: XQuery mode
+
+
+
+
+
+
+
+
+
+XQuery mode
+
@@ -217,5 +207,4 @@ declare function json:serialize($x as element()) as xs:string {
Mike Brevoort .
-
-
+
diff --git a/gulliver/js/codemirror/mode/xquery/xquery.js b/gulliver/js/codemirror/mode/xquery/xquery.js
index d5c859e00..be1798463 100644
--- a/gulliver/js/codemirror/mode/xquery/xquery.js
+++ b/gulliver/js/codemirror/mode/xquery/xquery.js
@@ -1,25 +1,3 @@
-/*
-Copyright (C) 2011 by MarkLogic Corporation
-Author: Mike Brevoort
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-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.
-*/
CodeMirror.defineMode("xquery", function() {
// The keywords object is set to the result of this self executing
@@ -35,18 +13,18 @@ CodeMirror.defineMode("xquery", function() {
, atom = {type: "atom", style: "atom"}
, punctuation = {type: "punctuation", style: null}
, qualifier = {type: "axis_specifier", style: "qualifier"};
-
+
// kwObj is what is return from this function at the end
var kwObj = {
'if': A, 'switch': A, 'while': A, 'for': A,
'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B,
- 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,
- 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,
+ 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,
+ 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,
',': punctuation,
'null': atom, 'fn:false()': atom, 'fn:true()': atom
};
-
- // a list of 'basic' keywords. For each add a property to kwObj with the value of
+
+ // a list of 'basic' keywords. For each add a property to kwObj with the value of
// {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"}
var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before',
'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self',
@@ -57,20 +35,20 @@ CodeMirror.defineMode("xquery", function() {
'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where',
'xquery', 'empty-sequence'];
for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);};
-
- // a list of types. For each add a property to kwObj with the value of
+
+ // a list of types. For each add a property to kwObj with the value of
// {type: "atom", style: "atom"}
- var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',
- 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',
+ var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',
+ 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',
'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration'];
for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};
-
+
// each operator will add a property to kwObj with value of {type: "operator", style: "keyword"}
var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-'];
for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;};
-
+
// each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"}
- var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::",
+ var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::",
"ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"];
for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; };
@@ -80,42 +58,42 @@ CodeMirror.defineMode("xquery", function() {
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
-
+
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
-
+
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
-
+
// the primary mode tokenizer
function tokenBase(stream, state) {
- var ch = stream.next(),
+ var ch = stream.next(),
mightBeFunction = false,
isEQName = isEQNameAhead(stream);
-
+
// an XML tag (if not in some sub, chained tokenizer)
if (ch == "<") {
if(stream.match("!--", true))
return chain(stream, state, tokenXMLComment);
-
+
if(stream.match("![CDATA", false)) {
state.tokenize = tokenCDATA;
return ret("tag", "tag");
}
-
+
if(stream.match("?", false)) {
return chain(stream, state, tokenPreProcessing);
}
-
+
var isclose = stream.eat("/");
stream.eatSpace();
var tagName = "", c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
-
+
return chain(stream, state, tokenTag(tagName, isclose));
}
// start code block
@@ -136,7 +114,7 @@ CodeMirror.defineMode("xquery", function() {
popStateStack(state);
return ret("tag", "tag");
}
- else
+ else
return ret("word", "variable");
}
// if a number
@@ -186,13 +164,13 @@ CodeMirror.defineMode("xquery", function() {
// if there's a EQName ahead, consume the rest of the string portion, it's likely a function
if(isEQName && ch === '\"') while(stream.next() !== '"'){}
if(isEQName && ch === '\'') while(stream.next() !== '\''){}
-
+
// gobble up a word if the character is not known
if(!known) stream.eatWhile(/[\w\$_-]/);
-
+
// gobble a colon in the case that is a lib func type call fn:doc
var foundColon = stream.eat(":");
-
+
// if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier
// which should get matched as a keyword
if(!stream.eat(":") && foundColon) {
@@ -205,27 +183,27 @@ CodeMirror.defineMode("xquery", function() {
// is the word a keyword?
var word = stream.current();
known = keywords.propertyIsEnumerable(word) && keywords[word];
-
- // if we think it's a function call but not yet known,
+
+ // if we think it's a function call but not yet known,
// set style to variable for now for lack of something better
if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"};
-
+
// if the previous word was element, attribute, axis specifier, this word should be the name of that
if(isInXmlConstructor(state)) {
popStateStack(state);
return ret("word", "variable", word);
}
- // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and
+ // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and
// push the stack so we know to look for it on the next word
if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"});
-
+
// if the word is known, return the details of that else just call this a generic 'word'
return known ? ret(known.type, known.style, word) :
ret("word", "variable", word);
}
}
- // handle comments, including nested
+ // handle comments, including nested
function tokenComment(stream, state) {
var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;
while (ch = stream.next()) {
@@ -243,7 +221,7 @@ CodeMirror.defineMode("xquery", function() {
maybeEnd = (ch == ":");
maybeNested = (ch == "(");
}
-
+
return ret("comment", "comment");
}
@@ -264,10 +242,10 @@ CodeMirror.defineMode("xquery", function() {
// if we're in a string and in an XML block, allow an embedded code block
if(stream.match("{", false) && isInXmlAttributeBlock(state)) {
state.tokenize = tokenBase;
- return ret("string", "string");
+ return ret("string", "string");
}
-
+
while (ch = stream.next()) {
if (ch == quote) {
popStateStack(state);
@@ -278,16 +256,16 @@ CodeMirror.defineMode("xquery", function() {
// if we're in a string and in an XML block, allow an embedded code block in an attribute
if(stream.match("{", false) && isInXmlAttributeBlock(state)) {
state.tokenize = tokenBase;
- return ret("string", "string");
+ return ret("string", "string");
}
}
}
-
+
return ret("string", "string");
};
}
-
+
// tokenizer for variables
function tokenVariable(stream, state) {
var isVariableChar = /[\w\$_-]/;
@@ -304,7 +282,7 @@ CodeMirror.defineMode("xquery", function() {
state.tokenize = tokenBase;
return ret("variable", "variable");
}
-
+
// tokenizer for XML tags
function tokenTag(name, isclose) {
return function(stream, state) {
@@ -322,7 +300,7 @@ CodeMirror.defineMode("xquery", function() {
return ret("tag", "tag");
}
else {
- state.tokenize = tokenBase;
+ state.tokenize = tokenBase;
}
return ret("tag", "tag");
};
@@ -331,7 +309,7 @@ CodeMirror.defineMode("xquery", function() {
// tokenizer for XML attributes
function tokenAttribute(stream, state) {
var ch = stream.next();
-
+
if(ch == "/" && stream.eat(">")) {
if(isInXmlAttributeBlock(state)) popStateStack(state);
if(isInXmlBlock(state)) popStateStack(state);
@@ -347,8 +325,8 @@ CodeMirror.defineMode("xquery", function() {
if (ch == '"' || ch == "'")
return chain(stream, state, tokenString(ch, tokenAttribute));
- if(!isInXmlAttributeBlock(state))
- pushStateStack(state, { type: "attribute", name: name, tokenize: tokenAttribute});
+ if(!isInXmlAttributeBlock(state))
+ pushStateStack(state, { type: "attribute", tokenize: tokenAttribute});
stream.eat(/[a-zA-Z_:]/);
stream.eatWhile(/[-a-zA-Z0-9_:.]/);
@@ -357,18 +335,18 @@ CodeMirror.defineMode("xquery", function() {
// the case where the attribute has not value and the tag was closed
if(stream.match(">", false) || stream.match("/", false)) {
popStateStack(state);
- state.tokenize = tokenBase;
+ state.tokenize = tokenBase;
}
return ret("attribute", "attribute");
}
-
- // handle comments, including nested
+
+ // handle comments, including nested
function tokenXMLComment(stream, state) {
var ch;
while (ch = stream.next()) {
if (ch == "-" && stream.match("->", true)) {
- state.tokenize = tokenBase;
+ state.tokenize = tokenBase;
return ret("comment", "comment");
}
}
@@ -380,7 +358,7 @@ CodeMirror.defineMode("xquery", function() {
var ch;
while (ch = stream.next()) {
if (ch == "]" && stream.match("]", true)) {
- state.tokenize = tokenBase;
+ state.tokenize = tokenBase;
return ret("comment", "comment");
}
}
@@ -391,20 +369,20 @@ CodeMirror.defineMode("xquery", function() {
var ch;
while (ch = stream.next()) {
if (ch == "?" && stream.match(">", true)) {
- state.tokenize = tokenBase;
+ state.tokenize = tokenBase;
return ret("comment", "comment meta");
}
}
}
-
-
+
+
// functions to test the current context of the state
function isInXmlBlock(state) { return isIn(state, "tag"); }
function isInXmlAttributeBlock(state) { return isIn(state, "attribute"); }
function isInXmlConstructor(state) { return isIn(state, "xmlconstructor"); }
function isInString(state) { return isIn(state, "string"); }
- function isEQNameAhead(stream) {
+ function isEQNameAhead(stream) {
// assume we've already eaten a quote (")
if(stream.current() === '"')
return stream.match(/^[^\"]+\"\:/, false);
@@ -413,21 +391,21 @@ CodeMirror.defineMode("xquery", function() {
else
return false;
}
-
+
function isIn(state, type) {
- return (state.stack.length && state.stack[state.stack.length - 1].type == type);
+ return (state.stack.length && state.stack[state.stack.length - 1].type == type);
}
-
+
function pushStateStack(state, newState) {
state.stack.push(newState);
}
-
+
function popStateStack(state) {
state.stack.pop();
var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize;
state.tokenize = reinstateTokenize || tokenBase;
}
-
+
// the interface for the mode API
return {
startState: function() {
@@ -442,7 +420,11 @@ CodeMirror.defineMode("xquery", function() {
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
return style;
- }
+ },
+
+ blockCommentStart: "(:",
+ blockCommentEnd: ":)"
+
};
});
diff --git a/gulliver/js/codemirror/mode/yaml/index.html b/gulliver/js/codemirror/mode/yaml/index.html
index 65e1ea73f..bbb40a3c7 100644
--- a/gulliver/js/codemirror/mode/yaml/index.html
+++ b/gulliver/js/codemirror/mode/yaml/index.html
@@ -1,17 +1,30 @@
-
-
-
- CodeMirror: YAML mode
-
-
-
-
-
-
-
- CodeMirror: YAML mode
-
+
+CodeMirror: YAML mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+YAML mode
+
--- # Favorite movies
- Casablanca
- North by Northwest
@@ -64,5 +77,4 @@ specialDelivery: >
MIME types defined: text/x-yaml.
-
-
+
diff --git a/gulliver/js/codemirror/mode/yaml/yaml.js b/gulliver/js/codemirror/mode/yaml/yaml.js
index 59e2641a0..efacd7d56 100644
--- a/gulliver/js/codemirror/mode/yaml/yaml.js
+++ b/gulliver/js/codemirror/mode/yaml/yaml.js
@@ -1,95 +1,97 @@
CodeMirror.defineMode("yaml", function() {
-
- var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
- var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
-
- return {
- token: function(stream, state) {
- var ch = stream.peek();
- var esc = state.escaped;
- state.escaped = false;
- /* comments */
- if (ch == "#") { stream.skipToEnd(); return "comment"; }
- if (state.literal && stream.indentation() > state.keyCol) {
- stream.skipToEnd(); return "string";
- } else if (state.literal) { state.literal = false; }
- if (stream.sol()) {
- state.keyCol = 0;
- state.pair = false;
- state.pairStart = false;
- /* document start */
- if(stream.match(/---/)) { return "def"; }
- /* document end */
- if (stream.match(/\.\.\./)) { return "def"; }
- /* array list item */
- if (stream.match(/\s*-\s+/)) { return 'meta'; }
- }
- /* pairs (associative arrays) -> key */
- if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) {
- state.pair = true;
- state.keyCol = stream.indentation();
- return "atom";
- }
- if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
-
- /* inline pairs/lists */
- if (stream.match(/^(\{|\}|\[|\])/)) {
- if (ch == '{')
- state.inlinePairs++;
- else if (ch == '}')
- state.inlinePairs--;
- else if (ch == '[')
- state.inlineList++;
- else
- state.inlineList--;
- return 'meta';
- }
-
- /* list seperator */
- if (state.inlineList > 0 && !esc && ch == ',') {
- stream.next();
- return 'meta';
- }
- /* pairs seperator */
- if (state.inlinePairs > 0 && !esc && ch == ',') {
- state.keyCol = 0;
- state.pair = false;
- state.pairStart = false;
- stream.next();
- return 'meta';
- }
-
- /* start of value of a pair */
- if (state.pairStart) {
- /* block literals */
- if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
- /* references */
- if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
- /* numbers */
- if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
- if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
- /* keywords */
- if (stream.match(keywordRegex)) { return 'keyword'; }
- }
- /* nothing found, continue */
- state.pairStart = false;
- state.escaped = (ch == '\\');
- stream.next();
- return null;
- },
- startState: function() {
- return {
- pair: false,
- pairStart: false,
- keyCol: 0,
- inlinePairs: 0,
- inlineList: 0,
- literal: false,
- escaped: false
- };
- }
- };
+ var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
+ var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
+
+ return {
+ token: function(stream, state) {
+ var ch = stream.peek();
+ var esc = state.escaped;
+ state.escaped = false;
+ /* comments */
+ if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) {
+ stream.skipToEnd(); return "comment";
+ }
+ if (state.literal && stream.indentation() > state.keyCol) {
+ stream.skipToEnd(); return "string";
+ } else if (state.literal) { state.literal = false; }
+ if (stream.sol()) {
+ state.keyCol = 0;
+ state.pair = false;
+ state.pairStart = false;
+ /* document start */
+ if(stream.match(/---/)) { return "def"; }
+ /* document end */
+ if (stream.match(/\.\.\./)) { return "def"; }
+ /* array list item */
+ if (stream.match(/\s*-\s+/)) { return 'meta'; }
+ }
+ /* inline pairs/lists */
+ if (stream.match(/^(\{|\}|\[|\])/)) {
+ if (ch == '{')
+ state.inlinePairs++;
+ else if (ch == '}')
+ state.inlinePairs--;
+ else if (ch == '[')
+ state.inlineList++;
+ else
+ state.inlineList--;
+ return 'meta';
+ }
+
+ /* list seperator */
+ if (state.inlineList > 0 && !esc && ch == ',') {
+ stream.next();
+ return 'meta';
+ }
+ /* pairs seperator */
+ if (state.inlinePairs > 0 && !esc && ch == ',') {
+ state.keyCol = 0;
+ state.pair = false;
+ state.pairStart = false;
+ stream.next();
+ return 'meta';
+ }
+
+ /* start of value of a pair */
+ if (state.pairStart) {
+ /* block literals */
+ if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
+ /* references */
+ if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
+ /* numbers */
+ if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
+ if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
+ /* keywords */
+ if (stream.match(keywordRegex)) { return 'keyword'; }
+ }
+
+ /* pairs (associative arrays) -> key */
+ if (!state.pair && stream.match(/^\s*\S+(?=\s*:($|\s))/i)) {
+ state.pair = true;
+ state.keyCol = stream.indentation();
+ return "atom";
+ }
+ if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
+
+ /* nothing found, continue */
+ state.pairStart = false;
+ state.escaped = (ch == '\\');
+ stream.next();
+ return null;
+ },
+ startState: function() {
+ return {
+ pair: false,
+ pairStart: false,
+ keyCol: 0,
+ inlinePairs: 0,
+ inlineList: 0,
+ literal: false,
+ escaped: false
+ };
+ }
+ };
});
CodeMirror.defineMIME("text/x-yaml", "yaml");
diff --git a/gulliver/js/codemirror/mode/z80/index.html b/gulliver/js/codemirror/mode/z80/index.html
index 133c870e3..b63c9621a 100644
--- a/gulliver/js/codemirror/mode/z80/index.html
+++ b/gulliver/js/codemirror/mode/z80/index.html
@@ -1,16 +1,30 @@
-
-
-
- CodeMirror: Z80 assembly mode
-
-
-
-
-
-
-
- CodeMirror: Z80 assembly mode
+
+CodeMirror: Z80 assembly mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Z80 assembly mode
+
#include "ti83plus.inc"
@@ -35,5 +49,4 @@ Message:
MIME type defined: text/x-z80.
-
-
+
diff --git a/gulliver/js/codemirror/mode/z80/z80.js b/gulliver/js/codemirror/mode/z80/z80.js
index c026790dc..ff43d32b5 100644
--- a/gulliver/js/codemirror/mode/z80/z80.js
+++ b/gulliver/js/codemirror/mode/z80/z80.js
@@ -1,113 +1,85 @@
-CodeMirror.defineMode('z80', function()
-{
- var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i;
- var keywords2 = /^(call|j[pr]|ret[in]?)\b/i;
- var keywords3 = /^b_?(call|jump)\b/i;
- var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i;
- var variables2 = /^(n?[zc]|p[oe]?|m)\b/i;
- var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i;
- var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+)\b/i;
-
- return {startState: function()
- {
- return {context: 0};
- }, token: function(stream, state)
- {
- if (!stream.column())
- state.context = 0;
-
- if (stream.eatSpace())
- return null;
-
- var w;
-
- if (stream.eatWhile(/\w/))
- {
- w = stream.current();
-
- if (stream.indentation())
- {
- if (state.context == 1 && variables1.test(w))
- return 'variable-2';
-
- if (state.context == 2 && variables2.test(w))
- return 'variable-3';
-
- if (keywords1.test(w))
- {
- state.context = 1;
- return 'keyword';
- }
- else if (keywords2.test(w))
- {
- state.context = 2;
- return 'keyword';
- }
- else if (keywords3.test(w))
- {
- state.context = 3;
- return 'keyword';
- }
-
- if (errors.test(w))
- return 'error';
- }
- else if (numbers.test(w))
- {
- return 'number';
- }
- else
- {
- return null;
- }
- }
- else if (stream.eat(';'))
- {
- stream.skipToEnd();
- return 'comment';
- }
- else if (stream.eat('"'))
- {
- while (w = stream.next())
- {
- if (w == '"')
- break;
-
- if (w == '\\')
- stream.next();
- }
-
- return 'string';
- }
- else if (stream.eat('\''))
- {
- if (stream.match(/\\?.'/))
- return 'number';
- }
- else if (stream.eat('.') || stream.sol() && stream.eat('#'))
- {
- state.context = 4;
-
- if (stream.eatWhile(/\w/))
- return 'def';
- }
- else if (stream.eat('$'))
- {
- if (stream.eatWhile(/[\da-f]/i))
- return 'number';
- }
- else if (stream.eat('%'))
- {
- if (stream.eatWhile(/[01]/))
- return 'number';
- }
- else
- {
- stream.next();
- }
-
- return null;
- }};
+CodeMirror.defineMode('z80', function() {
+ var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i;
+ var keywords2 = /^(call|j[pr]|ret[in]?)\b/i;
+ var keywords3 = /^b_?(call|jump)\b/i;
+ var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i;
+ var variables2 = /^(n?[zc]|p[oe]?|m)\b/i;
+ var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i;
+ var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+)\b/i;
+
+ return {
+ startState: function() {
+ return {context: 0};
+ },
+ token: function(stream, state) {
+ if (!stream.column())
+ state.context = 0;
+
+ if (stream.eatSpace())
+ return null;
+
+ var w;
+
+ if (stream.eatWhile(/\w/)) {
+ w = stream.current();
+
+ if (stream.indentation()) {
+ if (state.context == 1 && variables1.test(w))
+ return 'variable-2';
+
+ if (state.context == 2 && variables2.test(w))
+ return 'variable-3';
+
+ if (keywords1.test(w)) {
+ state.context = 1;
+ return 'keyword';
+ } else if (keywords2.test(w)) {
+ state.context = 2;
+ return 'keyword';
+ } else if (keywords3.test(w)) {
+ state.context = 3;
+ return 'keyword';
+ }
+
+ if (errors.test(w))
+ return 'error';
+ } else if (numbers.test(w)) {
+ return 'number';
+ } else {
+ return null;
+ }
+ } else if (stream.eat(';')) {
+ stream.skipToEnd();
+ return 'comment';
+ } else if (stream.eat('"')) {
+ while (w = stream.next()) {
+ if (w == '"')
+ break;
+
+ if (w == '\\')
+ stream.next();
+ }
+ return 'string';
+ } else if (stream.eat('\'')) {
+ if (stream.match(/\\?.'/))
+ return 'number';
+ } else if (stream.eat('.') || stream.sol() && stream.eat('#')) {
+ state.context = 4;
+
+ if (stream.eatWhile(/\w/))
+ return 'def';
+ } else if (stream.eat('$')) {
+ if (stream.eatWhile(/[\da-f]/i))
+ return 'number';
+ } else if (stream.eat('%')) {
+ if (stream.eatWhile(/[01]/))
+ return 'number';
+ } else {
+ stream.next();
+ }
+ return null;
+ }
+ };
});
CodeMirror.defineMIME("text/x-z80", "z80");
diff --git a/gulliver/js/codemirror/package.json b/gulliver/js/codemirror/package.json
index c9fa671da..326b95890 100644
--- a/gulliver/js/codemirror/package.json
+++ b/gulliver/js/codemirror/package.json
@@ -1,21 +1,20 @@
{
"name": "codemirror",
- "version":"3.11.00",
+ "version":"3.21.0",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"licenses": [{"type": "MIT",
"url": "http://codemirror.net/LICENSE"}],
"directories": {"lib": "./lib"},
"scripts": {"test": "node ./test/run.js"},
- "devDependencies": {"node-static": "0.6.0"},
+ "devDependencies": {"node-static": "0.6.0",
+ "phantomjs": "1.9.2-5"},
"bugs": "http://github.com/marijnh/CodeMirror/issues",
"keywords": ["JavaScript", "CodeMirror", "Editor"],
"homepage": "http://codemirror.net",
"maintainers":[{"name": "Marijn Haverbeke",
"email": "marijnh@gmail.com",
"web": "http://marijnhaverbeke.nl"}],
- "repositories": [{"type": "git",
- "url": "http://marijnhaverbeke.nl/git/codemirror"},
- {"type": "git",
- "url": "https://github.com/marijnh/CodeMirror.git"}]
+ "repository": {"type": "git",
+ "url": "https://github.com/marijnh/CodeMirror.git"}
}
diff --git a/gulliver/js/codemirror/test/comment_test.js b/gulliver/js/codemirror/test/comment_test.js
new file mode 100644
index 000000000..d8ff2c866
--- /dev/null
+++ b/gulliver/js/codemirror/test/comment_test.js
@@ -0,0 +1,63 @@
+namespace = "comment_";
+
+(function() {
+ function test(name, mode, run, before, after) {
+ return testCM(name, function(cm) {
+ run(cm);
+ eq(cm.getValue(), after);
+ }, {value: before, mode: mode});
+ }
+
+ var simpleProg = "function foo() {\n return bar;\n}";
+
+ test("block", "javascript", function(cm) {
+ cm.blockComment(Pos(0, 3), Pos(3, 0), {blockCommentLead: " *"});
+ }, simpleProg + "\n", "/* function foo() {\n * return bar;\n * }\n */");
+
+ test("blockToggle", "javascript", function(cm) {
+ cm.blockComment(Pos(0, 3), Pos(2, 0), {blockCommentLead: " *"});
+ cm.uncomment(Pos(0, 3), Pos(2, 0), {blockCommentLead: " *"});
+ }, simpleProg, simpleProg);
+
+ test("line", "javascript", function(cm) {
+ cm.lineComment(Pos(1, 1), Pos(1, 1));
+ }, simpleProg, "function foo() {\n// return bar;\n}");
+
+ test("lineToggle", "javascript", function(cm) {
+ cm.lineComment(Pos(0, 0), Pos(2, 1));
+ cm.uncomment(Pos(0, 0), Pos(2, 1));
+ }, simpleProg, simpleProg);
+
+ test("fallbackToBlock", "css", function(cm) {
+ cm.lineComment(Pos(0, 0), Pos(2, 1));
+ }, "html {\n border: none;\n}", "/* html {\n border: none;\n} */");
+
+ test("fallbackToLine", "ruby", function(cm) {
+ cm.blockComment(Pos(0, 0), Pos(1));
+ }, "def blah()\n return hah\n", "# def blah()\n# return hah\n");
+
+ test("commentRange", "javascript", function(cm) {
+ cm.blockComment(Pos(1, 2), Pos(1, 13), {fullLines: false});
+ }, simpleProg, "function foo() {\n /*return bar;*/\n}");
+
+ test("indented", "javascript", function(cm) {
+ cm.lineComment(Pos(1, 0), Pos(2), {indent: true});
+ }, simpleProg, "function foo() {\n // return bar;\n // }");
+
+ test("singleEmptyLine", "javascript", function(cm) {
+ cm.setCursor(1);
+ cm.execCommand("toggleComment");
+ }, "a;\n\nb;", "a;\n// \nb;");
+
+ test("dontMessWithStrings", "javascript", function(cm) {
+ cm.execCommand("toggleComment");
+ }, "console.log(\"/*string*/\");", "// console.log(\"/*string*/\");");
+
+ test("dontMessWithStrings2", "javascript", function(cm) {
+ cm.execCommand("toggleComment");
+ }, "console.log(\"// string\");", "// console.log(\"// string\");");
+
+ test("dontMessWithStrings3", "javascript", function(cm) {
+ cm.execCommand("toggleComment");
+ }, "// console.log(\"// string\");", "console.log(\"// string\");");
+})();
diff --git a/gulliver/js/codemirror/test/doc_test.js b/gulliver/js/codemirror/test/doc_test.js
index 3e04e155b..f0f40e76e 100644
--- a/gulliver/js/codemirror/test/doc_test.js
+++ b/gulliver/js/codemirror/test/doc_test.js
@@ -57,7 +57,7 @@
run.apply(null, editors);
successful = true;
} finally {
- if ((debug && !successful) || verbose) {
+ if (!successful || verbose) {
place.style.visibility = "visible";
} else {
for (var i = 0; i < editors.length; ++i)
diff --git a/gulliver/js/codemirror/test/driver.js b/gulliver/js/codemirror/test/driver.js
index aba427702..13952dcc6 100644
--- a/gulliver/js/codemirror/test/driver.js
+++ b/gulliver/js/codemirror/test/driver.js
@@ -1,4 +1,4 @@
-var tests = [], debug = null, debugUsed = new Array(), allNames = [];
+var tests = [], filters = [], allNames = [];
function Failure(why) {this.message = why;}
Failure.prototype.toString = function() { return this.message; };
@@ -23,15 +23,16 @@ function test(name, run, expectedFail) {
tests.push({name: name, func: run, expectedFail: expectedFail});
return name;
}
+var namespace = "";
function testCM(name, run, opts, expectedFail) {
- return test("core_" + name, function() {
- var place = document.getElementById("testground"), cm = CodeMirror(place, opts);
+ return test(namespace + name, function() {
+ var place = document.getElementById("testground"), cm = window.cm = CodeMirror(place, opts);
var successful = false;
try {
run(cm);
successful = true;
} finally {
- if ((debug && !successful) || verbose) {
+ if (!successful || verbose) {
place.style.visibility = "visible";
} else {
place.removeChild(cm.getWrapperElement());
@@ -41,39 +42,23 @@ function testCM(name, run, opts, expectedFail) {
}
function runTests(callback) {
- if (debug) {
- if (indexOf(debug, "verbose") === 0) {
- verbose = true;
- debug.splice(0, 1);
- }
- if (debug.length < 1) {
- debug = null;
- }
- }
var totalTime = 0;
function step(i) {
if (i === tests.length){
running = false;
return callback("done");
- }
+ }
var test = tests[i], expFail = test.expectedFail, startTime = +new Date;
- if (debug !== null) {
- var debugIndex = indexOf(debug, test.name);
- if (debugIndex !== -1) {
- // Remove from array for reporting incorrect tests later
- debug.splice(debugIndex, 1);
- } else {
- var wildcardName = test.name.split("_")[0] + "_*";
- debugIndex = indexOf(debug, wildcardName);
- if (debugIndex !== -1) {
- // Remove from array for reporting incorrect tests later
- debug.splice(debugIndex, 1);
- debugUsed.push(wildcardName);
- } else {
- debugIndex = indexOf(debugUsed, wildcardName);
- if (debugIndex == -1) return step(i + 1);
+ if (filters.length) {
+ for (var j = 0; j < filters.length; j++) {
+ if (test.name.match(filters[j])) {
+ break;
}
}
+ if (j == filters.length) {
+ callback("skipped", test.name, message);
+ return step(i + 1);
+ }
}
var threw = false;
try {
@@ -83,7 +68,7 @@ function runTests(callback) {
if (expFail) callback("expected", test.name);
else if (e instanceof Failure) callback("fail", test.name, e.message);
else {
- var pos = /\bat .*?([^\/:]+):(\d+):/.exec(e.stack);
+ var pos = /(?:\bat |@).*?([^\/:]+):(\d+)/.exec(e.stack);
callback("error", test.name, e.toString() + (pos ? " (" + pos[1] + ":" + pos[2] + ")" : ""));
}
}
@@ -126,13 +111,21 @@ function is(a, msg) {
}
function countTests() {
- if (!debug) return tests.length;
+ if (!filters.length) return tests.length;
var sum = 0;
for (var i = 0; i < tests.length; ++i) {
var name = tests[i].name;
- if (indexOf(debug, name) != -1 ||
- indexOf(debug, name.split("_")[0] + "_*") != -1)
- ++sum;
+ for (var j = 0; j < filters.length; j++) {
+ if (name.match(filters[j])) {
+ ++sum;
+ break;
+ }
+ }
}
return sum;
}
+
+function parseTestFilter(s) {
+ if (/_\*$/.test(s)) return new RegExp("^" + s.slice(0, s.length - 2), "i");
+ else return new RegExp(s, "i");
+}
diff --git a/gulliver/js/codemirror/test/emacs_test.js b/gulliver/js/codemirror/test/emacs_test.js
new file mode 100644
index 000000000..f21605bb3
--- /dev/null
+++ b/gulliver/js/codemirror/test/emacs_test.js
@@ -0,0 +1,138 @@
+(function() {
+ "use strict";
+
+ var Pos = CodeMirror.Pos;
+ namespace = "emacs_";
+
+ var eventCache = {};
+ function fakeEvent(keyName) {
+ var event = eventCache[key];
+ if (event) return event;
+
+ var ctrl, shift, alt;
+ var key = keyName.replace(/\w+-/g, function(type) {
+ if (type == "Ctrl-") ctrl = true;
+ else if (type == "Alt-") alt = true;
+ else if (type == "Shift-") shift = true;
+ return "";
+ });
+ var code;
+ for (var c in CodeMirror.keyNames)
+ if (CodeMirror.keyNames[c] == key) { code = c; break; }
+ if (c == null) throw new Error("Unknown key: " + key);
+
+ return eventCache[keyName] = {
+ type: "keydown", keyCode: code, ctrlKey: ctrl, shiftKey: shift, altKey: alt,
+ preventDefault: function(){}, stopPropagation: function(){}
+ };
+ }
+
+ function sim(name, start /*, actions... */) {
+ var keys = Array.prototype.slice.call(arguments, 2);
+ testCM(name, function(cm) {
+ for (var i = 0; i < keys.length; ++i) {
+ var cur = keys[i];
+ if (cur instanceof Pos) cm.setCursor(cur);
+ else if (cur.call) cur(cm);
+ else cm.triggerOnKeyDown(fakeEvent(cur));
+ }
+ }, {keyMap: "emacs", value: start, mode: "javascript"});
+ }
+
+ function at(line, ch) { return function(cm) { eqPos(cm.getCursor(), Pos(line, ch)); }; }
+ function txt(str) { return function(cm) { eq(cm.getValue(), str); }; }
+
+ sim("motionHSimple", "abc", "Ctrl-F", "Ctrl-F", "Ctrl-B", at(0, 1));
+ sim("motionHMulti", "abcde",
+ "Ctrl-4", "Ctrl-F", at(0, 4), "Ctrl--", "Ctrl-2", "Ctrl-F", at(0, 2),
+ "Ctrl-5", "Ctrl-B", at(0, 0));
+
+ sim("motionHWord", "abc. def ghi",
+ "Alt-F", at(0, 3), "Alt-F", at(0, 8),
+ "Ctrl-B", "Alt-B", at(0, 5), "Alt-B", at(0, 0));
+ sim("motionHWordMulti", "abc. def ghi ",
+ "Ctrl-3", "Alt-F", at(0, 12), "Ctrl-2", "Alt-B", at(0, 5),
+ "Ctrl--", "Alt-B", at(0, 8));
+
+ sim("motionVSimple", "a\nb\nc\n", "Ctrl-N", "Ctrl-N", "Ctrl-P", at(1, 0));
+ sim("motionVMulti", "a\nb\nc\nd\ne\n",
+ "Ctrl-2", "Ctrl-N", at(2, 0), "Ctrl-F", "Ctrl--", "Ctrl-N", at(1, 1),
+ "Ctrl--", "Ctrl-3", "Ctrl-P", at(4, 1));
+
+ sim("killYank", "abc\ndef\nghi",
+ "Ctrl-F", "Ctrl-Space", "Ctrl-N", "Ctrl-N", "Ctrl-W", "Ctrl-E", "Ctrl-Y",
+ txt("ahibc\ndef\ng"));
+ sim("killRing", "abcdef",
+ "Ctrl-Space", "Ctrl-F", "Ctrl-W", "Ctrl-Space", "Ctrl-F", "Ctrl-W",
+ "Ctrl-Y", "Alt-Y",
+ txt("acdef"));
+ sim("copyYank", "abcd",
+ "Ctrl-Space", "Ctrl-E", "Alt-W", "Ctrl-Y",
+ txt("abcdabcd"));
+
+ sim("killLineSimple", "foo\nbar", "Ctrl-F", "Ctrl-K", txt("f\nbar"));
+ sim("killLineEmptyLine", "foo\n \nbar", "Ctrl-N", "Ctrl-K", txt("foo\nbar"));
+ sim("killLineMulti", "foo\nbar\nbaz",
+ "Ctrl-F", "Ctrl-F", "Ctrl-K", "Ctrl-K", "Ctrl-K", "Ctrl-A", "Ctrl-Y",
+ txt("o\nbarfo\nbaz"));
+
+ sim("moveByParagraph", "abc\ndef\n\n\nhij\nklm\n\n",
+ "Ctrl-F", "Ctrl-Down", at(2, 0), "Ctrl-Down", at(6, 0),
+ "Ctrl-N", "Ctrl-Up", at(3, 0), "Ctrl-Up", at(0, 0),
+ Pos(1, 2), "Ctrl-Down", at(2, 0), Pos(4, 2), "Ctrl-Up", at(3, 0));
+ sim("moveByParagraphMulti", "abc\n\ndef\n\nhij\n\nklm",
+ "Ctrl-U", "2", "Ctrl-Down", at(3, 0),
+ "Shift-Alt-.", "Ctrl-3", "Ctrl-Up", at(1, 0));
+
+ sim("moveBySentence", "sentence one! sentence\ntwo\n\nparagraph two",
+ "Alt-E", at(0, 13), "Alt-E", at(1, 3), "Ctrl-F", "Alt-A", at(0, 13));
+
+ sim("moveByExpr", "function foo(a, b) {}",
+ "Ctrl-Alt-F", at(0, 8), "Ctrl-Alt-F", at(0, 12), "Ctrl-Alt-F", at(0, 18),
+ "Ctrl-Alt-B", at(0, 12), "Ctrl-Alt-B", at(0, 9));
+ sim("moveByExprMulti", "foo bar baz bug",
+ "Ctrl-2", "Ctrl-Alt-F", at(0, 7),
+ "Ctrl--", "Ctrl-Alt-F", at(0, 4),
+ "Ctrl--", "Ctrl-2", "Ctrl-Alt-B", at(0, 11));
+ sim("delExpr", "var x = [\n a,\n b\n c\n];",
+ Pos(0, 8), "Ctrl-Alt-K", txt("var x = ;"), "Ctrl-/",
+ Pos(4, 1), "Ctrl-Alt-Backspace", txt("var x = ;"));
+ sim("delExprMulti", "foo bar baz",
+ "Ctrl-2", "Ctrl-Alt-K", txt(" baz"),
+ "Ctrl-/", "Ctrl-E", "Ctrl-2", "Ctrl-Alt-Backspace", txt("foo "));
+
+ sim("justOneSpace", "hi bye ",
+ Pos(0, 4), "Alt-Space", txt("hi bye "),
+ Pos(0, 4), "Alt-Space", txt("hi b ye "),
+ "Ctrl-A", "Alt-Space", "Ctrl-E", "Alt-Space", txt(" hi b ye "));
+
+ sim("openLine", "foo bar", "Alt-F", "Ctrl-O", txt("foo\n bar"))
+
+ sim("transposeChar", "abcd\n\ne",
+ "Ctrl-F", "Ctrl-T", "Ctrl-T", txt("bcad\n\ne"), at(0, 3),
+ "Ctrl-F", "Ctrl-T", "Ctrl-T", "Ctrl-T", txt("bcda\n\ne"), at(0, 4),
+ "Ctrl-F", "Ctrl-T", txt("bcd\na\ne"), at(1, 1));
+
+ sim("manipWordCase", "foo BAR bAZ",
+ "Alt-C", "Alt-L", "Alt-U", txt("Foo bar BAZ"),
+ "Ctrl-A", "Alt-U", "Alt-L", "Alt-C", txt("FOO bar Baz"));
+ sim("manipWordCaseMulti", "foo Bar bAz",
+ "Ctrl-2", "Alt-U", txt("FOO BAR bAz"),
+ "Ctrl-A", "Ctrl-3", "Alt-C", txt("Foo Bar Baz"));
+
+ sim("upExpr", "foo {\n bar[];\n baz(blah);\n}",
+ Pos(2, 7), "Ctrl-Alt-U", at(2, 5), "Ctrl-Alt-U", at(0, 4));
+ sim("transposeExpr", "do foo[bar] dah",
+ Pos(0, 6), "Ctrl-Alt-T", txt("do [bar]foo dah"));
+
+ sim("clearMark", "abcde", Pos(0, 2), "Ctrl-Space", "Ctrl-F", "Ctrl-F",
+ "Ctrl-G", "Ctrl-W", txt("abcde"));
+
+ testCM("save", function(cm) {
+ var saved = false;
+ CodeMirror.commands.save = function(cm) { saved = cm.getValue(); };
+ cm.triggerOnKeyDown(fakeEvent("Ctrl-X"));
+ cm.triggerOnKeyDown(fakeEvent("Ctrl-S"));
+ is(saved, "hi");
+ }, {value: "hi", keyMap: "emacs"});
+})();
diff --git a/gulliver/js/codemirror/test/index.html b/gulliver/js/codemirror/test/index.html
index 0a0da5bd8..8177038e3 100644
--- a/gulliver/js/codemirror/test/index.html
+++ b/gulliver/js/codemirror/test/index.html
@@ -1,44 +1,62 @@
-
-
-
- CodeMirror: Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
- CodeMirror: Test Suite
+CodeMirror: Test Suite
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test Suite
A limited set of programmatic sanity tests for CodeMirror.
@@ -53,10 +71,19 @@
+
+
+
+
+
+
+
+
+
@@ -65,7 +92,9 @@
+
+
-
-
+
+
diff --git a/gulliver/js/codemirror/test/lint/lint.js b/gulliver/js/codemirror/test/lint/lint.js
index b1b9381dd..fda737c08 100644
--- a/gulliver/js/codemirror/test/lint/lint.js
+++ b/gulliver/js/codemirror/test/lint/lint.js
@@ -8,10 +8,22 @@
- missing semicolons and trailing commas
- variables or properties that are reserved words
- assigning to a variable you didn't declare
+ - access to non-whitelisted globals
+ (use a '// declare global: foo, bar' comment to declare extra
+ globals in a file)
[1]: https://github.com/marijnh/acorn/
*/
+var topAllowedGlobals = Object.create(null);
+("Error RegExp Number String Array Function Object Math Date undefined " +
+ "parseInt parseFloat Infinity NaN isNaN " +
+ "window document navigator prompt alert confirm console " +
+ "FileReader Worker postMessage importScripts " +
+ "setInterval clearInterval setTimeout clearTimeout " +
+ "CodeMirror test")
+ .split(" ").forEach(function(n) { topAllowedGlobals[n] = true; });
+
var fs = require("fs"), acorn = require("./acorn.js"), walk = require("./walk.js");
var scopePasser = walk.make({
@@ -19,11 +31,17 @@ var scopePasser = walk.make({
});
function checkFile(fileName) {
- var file = fs.readFileSync(fileName, "utf8");
- var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF]/);
- if (badChar)
- fail("Undesirable character " + badChar[0].charCodeAt(0) + " at position " + badChar.index,
- {source: fileName});
+ var file = fs.readFileSync(fileName, "utf8"), notAllowed;
+ if (notAllowed = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF\t]|[ \t]\n/)) {
+ var msg;
+ if (notAllowed[0] == "\t") msg = "Found tab character";
+ else if (notAllowed[0].indexOf("\n") > -1) msg = "Trailing whitespace";
+ else msg = "Undesirable character " + notAllowed[0].charCodeAt(0);
+ var info = acorn.getLineInfo(file, notAllowed.index);
+ fail(msg + " at line " + info.line + ", column " + info.column, {source: fileName});
+ }
+
+ var globalsSeen = Object.create(null);
try {
var parsed = acorn.parse(file, {
@@ -66,18 +84,31 @@ function checkFile(fileName) {
UpdateExpression: function(node, scope) {checkLHS(node.argument, scope);},
AssignmentExpression: function(node, scope) {checkLHS(node.left, scope);},
Identifier: function(node, scope) {
+ if (node.name == "arguments") return;
// Mark used identifiers
for (var cur = scope; cur; cur = cur.prev)
if (node.name in cur.vars) {
cur.vars[node.name].used = true;
return;
}
+ globalsSeen[node.name] = node.loc;
},
FunctionExpression: function(node) {
if (node.id) fail("Named function expression", node.loc);
}
}, scopePasser);
+ if (!globalsSeen.exports) {
+ var allowedGlobals = Object.create(topAllowedGlobals), m;
+ if (m = file.match(/\/\/ declare global:\s+(.*)/))
+ m[1].split(/,\s*/g).forEach(function(n) { allowedGlobals[n] = true; });
+ for (var glob in globalsSeen)
+ if (!(glob in allowedGlobals))
+ fail("Access to global variable " + glob + ". Add a '// declare global: " + glob +
+ "' comment or add this variable in test/lint/lint.js.", globalsSeen[glob]);
+ }
+
+
for (var i = 0; i < scopes.length; ++i) {
var scope = scopes[i];
for (var name in scope.vars) {
@@ -91,7 +122,7 @@ function checkFile(fileName) {
var failed = false;
function fail(msg, pos) {
if (pos.start) msg += " (" + pos.start.line + ":" + pos.start.column + ")";
- console.log(pos.source.match(/[^\/]+$/)[0] + ": " + msg);
+ console.log(pos.source + ": " + msg);
failed = true;
}
@@ -99,7 +130,7 @@ function checkDir(dir) {
fs.readdirSync(dir).forEach(function(file) {
var fname = dir + "/" + file;
if (/\.js$/.test(file)) checkFile(fname);
- else if (fs.lstatSync(fname).isDirectory()) checkDir(fname);
+ else if (file != "dep" && fs.lstatSync(fname).isDirectory()) checkDir(fname);
});
}
diff --git a/gulliver/js/codemirror/test/lint/parse-js.js b/gulliver/js/codemirror/test/lint/parse-js.js
deleted file mode 100644
index c165a273f..000000000
--- a/gulliver/js/codemirror/test/lint/parse-js.js
+++ /dev/null
@@ -1,1372 +0,0 @@
-/***********************************************************************
-
- A JavaScript tokenizer / parser / beautifier / compressor.
-
- This version is suitable for Node.js. With minimal changes (the
- exports stuff) it should work on any JS platform.
-
- This file contains the tokenizer/parser. It is a port to JavaScript
- of parse-js [1], a JavaScript parser library written in Common Lisp
- by Marijn Haverbeke. Thank you Marijn!
-
- [1] http://marijn.haverbeke.nl/parse-js/
-
- Exported functions:
-
- - tokenizer(code) -- returns a function. Call the returned
- function to fetch the next token.
-
- - parse(code) -- returns an AST of the given JavaScript code.
-
- -------------------------------- (C) ---------------------------------
-
- Author: Mihai Bazon
-
- http://mihai.bazon.net/blog
-
- Distributed under the BSD license:
-
- Copyright 2010 (c) Mihai Bazon
- Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the following
- disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials
- provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- ***********************************************************************/
-
-/* -----[ Tokenizer (constants) ]----- */
-
-var KEYWORDS = array_to_hash([
- "break",
- "case",
- "catch",
- "const",
- "continue",
- "debugger",
- "default",
- "delete",
- "do",
- "else",
- "finally",
- "for",
- "function",
- "if",
- "in",
- "instanceof",
- "new",
- "return",
- "switch",
- "throw",
- "try",
- "typeof",
- "var",
- "void",
- "while",
- "with"
-]);
-
-var RESERVED_WORDS = array_to_hash([
- "abstract",
- "boolean",
- "byte",
- "char",
- "class",
- "double",
- "enum",
- "export",
- "extends",
- "final",
- "float",
- "goto",
- "implements",
- "import",
- "int",
- "interface",
- "long",
- "native",
- "package",
- "private",
- "protected",
- "public",
- "short",
- "static",
- "super",
- "synchronized",
- "throws",
- "transient",
- "volatile"
-]);
-
-var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
- "return",
- "new",
- "delete",
- "throw",
- "else",
- "case"
-]);
-
-var KEYWORDS_ATOM = array_to_hash([
- "false",
- "null",
- "true",
- "undefined"
-]);
-
-var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
-
-var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
-var RE_OCT_NUMBER = /^0[0-7]+$/;
-var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
-
-var OPERATORS = array_to_hash([
- "in",
- "instanceof",
- "typeof",
- "new",
- "void",
- "delete",
- "++",
- "--",
- "+",
- "-",
- "!",
- "~",
- "&",
- "|",
- "^",
- "*",
- "/",
- "%",
- ">>",
- "<<",
- ">>>",
- "<",
- ">",
- "<=",
- ">=",
- "==",
- "===",
- "!=",
- "!==",
- "?",
- "=",
- "+=",
- "-=",
- "/=",
- "*=",
- "%=",
- ">>=",
- "<<=",
- ">>>=",
- "|=",
- "^=",
- "&=",
- "&&",
- "||"
-]);
-
-var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
-
-var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:"));
-
-var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
-
-var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
-
-/* -----[ Tokenizer ]----- */
-
-var UNICODE = { // Unicode 6.1
- letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
- combining_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u08E4-\\u08FE\\u0900-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C01-\\u0C03\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C82\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0D02\\u0D03\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D82\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF2-\\u1CF4\\u1DC0-\\u1DE6\\u1DFC-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA674-\\uA67D\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA880\\uA881\\uA8B4-\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
- connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"),
- digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]")
-};
-
-function is_letter(ch) {
- return UNICODE.letter.test(ch);
-};
-
-function is_digit(ch) {
- ch = ch.charCodeAt(0);
- return ch >= 48 && ch <= 57;
-};
-
-function is_unicode_digit(ch) {
- return UNICODE.digit.test(ch);
-}
-
-function is_alphanumeric_char(ch) {
- return is_digit(ch) || is_letter(ch);
-};
-
-function is_unicode_combining_mark(ch) {
- return UNICODE.combining_mark.test(ch);
-};
-
-function is_unicode_connector_punctuation(ch) {
- return UNICODE.connector_punctuation.test(ch);
-};
-
-function is_identifier_start(ch) {
- return ch == "$" || ch == "_" || is_letter(ch);
-};
-
-function is_identifier_char(ch) {
- return is_identifier_start(ch)
- || is_unicode_combining_mark(ch)
- || is_unicode_digit(ch)
- || is_unicode_connector_punctuation(ch)
- || ch == "\u200c" // zero-width non-joiner
- || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c)
- ;
-};
-
-function parse_js_number(num) {
- if (RE_HEX_NUMBER.test(num)) {
- return parseInt(num.substr(2), 16);
- } else if (RE_OCT_NUMBER.test(num)) {
- return parseInt(num.substr(1), 8);
- } else if (RE_DEC_NUMBER.test(num)) {
- return parseFloat(num);
- }
-};
-
-function JS_Parse_Error(message, line, col, pos) {
- this.message = message;
- this.line = line + 1;
- this.col = col + 1;
- this.pos = pos + 1;
- this.stack = new Error().stack;
-};
-
-JS_Parse_Error.prototype.toString = function() {
- return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
-};
-
-function js_error(message, line, col, pos) {
- throw new JS_Parse_Error(message, line, col, pos);
-};
-
-function is_token(token, type, val) {
- return token.type == type && (val == null || token.value == val);
-};
-
-var EX_EOF = {};
-
-function tokenizer($TEXT) {
-
- var S = {
- text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
- pos : 0,
- tokpos : 0,
- line : 0,
- tokline : 0,
- col : 0,
- tokcol : 0,
- newline_before : false,
- regex_allowed : false,
- comments_before : []
- };
-
- function peek() { return S.text.charAt(S.pos); };
-
- function next(signal_eof, in_string) {
- var ch = S.text.charAt(S.pos++);
- if (signal_eof && !ch)
- throw EX_EOF;
- if (ch == "\n") {
- S.newline_before = S.newline_before || !in_string;
- ++S.line;
- S.col = 0;
- } else {
- ++S.col;
- }
- return ch;
- };
-
- function eof() {
- return !S.peek();
- };
-
- function find(what, signal_eof) {
- var pos = S.text.indexOf(what, S.pos);
- if (signal_eof && pos == -1) throw EX_EOF;
- return pos;
- };
-
- function start_token() {
- S.tokline = S.line;
- S.tokcol = S.col;
- S.tokpos = S.pos;
- };
-
- function token(type, value, is_comment) {
- S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
- (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
- (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
- var ret = {
- type : type,
- value : value,
- line : S.tokline,
- col : S.tokcol,
- pos : S.tokpos,
- endpos : S.pos,
- nlb : S.newline_before
- };
- if (!is_comment) {
- ret.comments_before = S.comments_before;
- S.comments_before = [];
- // make note of any newlines in the comments that came before
- for (var i = 0, len = ret.comments_before.length; i < len; i++) {
- ret.nlb = ret.nlb || ret.comments_before[i].nlb;
- }
- }
- S.newline_before = false;
- return ret;
- };
-
- function skip_whitespace() {
- while (HOP(WHITESPACE_CHARS, peek()))
- next();
- };
-
- function read_while(pred) {
- var ret = "", ch = peek(), i = 0;
- while (ch && pred(ch, i++)) {
- ret += next();
- ch = peek();
- }
- return ret;
- };
-
- function parse_error(err) {
- js_error(err, S.tokline, S.tokcol, S.tokpos);
- };
-
- function read_num(prefix) {
- var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
- var num = read_while(function(ch, i){
- if (ch == "x" || ch == "X") {
- if (has_x) return false;
- return has_x = true;
- }
- if (!has_x && (ch == "E" || ch == "e")) {
- if (has_e) return false;
- return has_e = after_e = true;
- }
- if (ch == "-") {
- if (after_e || (i == 0 && !prefix)) return true;
- return false;
- }
- if (ch == "+") return after_e;
- after_e = false;
- if (ch == ".") {
- if (!has_dot && !has_x && !has_e)
- return has_dot = true;
- return false;
- }
- return is_alphanumeric_char(ch);
- });
- if (prefix)
- num = prefix + num;
- var valid = parse_js_number(num);
- if (!isNaN(valid)) {
- return token("num", valid);
- } else {
- parse_error("Invalid syntax: " + num);
- }
- };
-
- function read_escaped_char(in_string) {
- var ch = next(true, in_string);
- switch (ch) {
- case "n" : return "\n";
- case "r" : return "\r";
- case "t" : return "\t";
- case "b" : return "\b";
- case "v" : return "\u000b";
- case "f" : return "\f";
- case "0" : return "\0";
- case "x" : return String.fromCharCode(hex_bytes(2));
- case "u" : return String.fromCharCode(hex_bytes(4));
- case "\n": return "";
- default : return ch;
- }
- };
-
- function hex_bytes(n) {
- var num = 0;
- for (; n > 0; --n) {
- var digit = parseInt(next(true), 16);
- if (isNaN(digit))
- parse_error("Invalid hex-character pattern in string");
- num = (num << 4) | digit;
- }
- return num;
- };
-
- function read_string() {
- return with_eof_error("Unterminated string constant", function(){
- var quote = next(), ret = "";
- for (;;) {
- var ch = next(true);
- if (ch == "\\") {
- // read OctalEscapeSequence (XXX: deprecated if "strict mode")
- // https://github.com/mishoo/UglifyJS/issues/178
- var octal_len = 0, first = null;
- ch = read_while(function(ch){
- if (ch >= "0" && ch <= "7") {
- if (!first) {
- first = ch;
- return ++octal_len;
- }
- else if (first <= "3" && octal_len <= 2) return ++octal_len;
- else if (first >= "4" && octal_len <= 1) return ++octal_len;
- }
- return false;
- });
- if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
- else ch = read_escaped_char(true);
- }
- else if (ch == quote) break;
- ret += ch;
- }
- return token("string", ret);
- });
- };
-
- function read_line_comment() {
- next();
- var i = find("\n"), ret;
- if (i == -1) {
- ret = S.text.substr(S.pos);
- S.pos = S.text.length;
- } else {
- ret = S.text.substring(S.pos, i);
- S.pos = i;
- }
- return token("comment1", ret, true);
- };
-
- function read_multiline_comment() {
- next();
- return with_eof_error("Unterminated multiline comment", function(){
- var i = find("*/", true),
- text = S.text.substring(S.pos, i);
- S.pos = i + 2;
- S.line += text.split("\n").length - 1;
- S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
-
- // https://github.com/mishoo/UglifyJS/issues/#issue/100
- if (/^@cc_on/i.test(text)) {
- warn("WARNING: at line " + S.line);
- warn("*** Found \"conditional comment\": " + text);
- warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer.");
- }
-
- return token("comment2", text, true);
- });
- };
-
- function read_name() {
- var backslash = false, name = "", ch, escaped = false, hex;
- while ((ch = peek()) != null) {
- if (!backslash) {
- if (ch == "\\") escaped = backslash = true, next();
- else if (is_identifier_char(ch)) name += next();
- else break;
- }
- else {
- if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
- ch = read_escaped_char();
- if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
- name += ch;
- backslash = false;
- }
- }
- if (HOP(KEYWORDS, name) && escaped) {
- hex = name.charCodeAt(0).toString(16).toUpperCase();
- name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
- }
- return name;
- };
-
- function read_regexp(regexp) {
- return with_eof_error("Unterminated regular expression", function(){
- var prev_backslash = false, ch, in_class = false;
- while ((ch = next(true))) if (prev_backslash) {
- regexp += "\\" + ch;
- prev_backslash = false;
- } else if (ch == "[") {
- in_class = true;
- regexp += ch;
- } else if (ch == "]" && in_class) {
- in_class = false;
- regexp += ch;
- } else if (ch == "/" && !in_class) {
- break;
- } else if (ch == "\\") {
- prev_backslash = true;
- } else {
- regexp += ch;
- }
- var mods = read_name();
- return token("regexp", [ regexp, mods ]);
- });
- };
-
- function read_operator(prefix) {
- function grow(op) {
- if (!peek()) return op;
- var bigger = op + peek();
- if (HOP(OPERATORS, bigger)) {
- next();
- return grow(bigger);
- } else {
- return op;
- }
- };
- return token("operator", grow(prefix || next()));
- };
-
- function handle_slash() {
- next();
- var regex_allowed = S.regex_allowed;
- switch (peek()) {
- case "/":
- S.comments_before.push(read_line_comment());
- S.regex_allowed = regex_allowed;
- return next_token();
- case "*":
- S.comments_before.push(read_multiline_comment());
- S.regex_allowed = regex_allowed;
- return next_token();
- }
- return S.regex_allowed ? read_regexp("") : read_operator("/");
- };
-
- function handle_dot() {
- next();
- return is_digit(peek())
- ? read_num(".")
- : token("punc", ".");
- };
-
- function read_word() {
- var word = read_name();
- return !HOP(KEYWORDS, word)
- ? token("name", word)
- : HOP(OPERATORS, word)
- ? token("operator", word)
- : HOP(KEYWORDS_ATOM, word)
- ? token("atom", word)
- : token("keyword", word);
- };
-
- function with_eof_error(eof_error, cont) {
- try {
- return cont();
- } catch(ex) {
- if (ex === EX_EOF) parse_error(eof_error);
- else throw ex;
- }
- };
-
- function next_token(force_regexp) {
- if (force_regexp != null)
- return read_regexp(force_regexp);
- skip_whitespace();
- start_token();
- var ch = peek();
- if (!ch) return token("eof");
- if (is_digit(ch)) return read_num();
- if (ch == '"' || ch == "'") return read_string();
- if (HOP(PUNC_CHARS, ch)) return token("punc", next());
- if (ch == ".") return handle_dot();
- if (ch == "/") return handle_slash();
- if (HOP(OPERATOR_CHARS, ch)) return read_operator();
- if (ch == "\\" || is_identifier_start(ch)) return read_word();
- parse_error("Unexpected character '" + ch + "'");
- };
-
- next_token.context = function(nc) {
- if (nc) S = nc;
- return S;
- };
-
- return next_token;
-
-};
-
-/* -----[ Parser (constants) ]----- */
-
-var UNARY_PREFIX = array_to_hash([
- "typeof",
- "void",
- "delete",
- "--",
- "++",
- "!",
- "~",
- "-",
- "+"
-]);
-
-var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
-
-var ASSIGNMENT = (function(a, ret, i){
- while (i < a.length) {
- ret[a[i]] = a[i].substr(0, a[i].length - 1);
- i++;
- }
- return ret;
-})(
- ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
- { "=": true },
- 0
-);
-
-var PRECEDENCE = (function(a, ret){
- for (var i = 0, n = 1; i < a.length; ++i, ++n) {
- var b = a[i];
- for (var j = 0; j < b.length; ++j) {
- ret[b[j]] = n;
- }
- }
- return ret;
-})(
- [
- ["||"],
- ["&&"],
- ["|"],
- ["^"],
- ["&"],
- ["==", "===", "!=", "!=="],
- ["<", ">", "<=", ">=", "in", "instanceof"],
- [">>", "<<", ">>>"],
- ["+", "-"],
- ["*", "/", "%"]
- ],
- {}
-);
-
-var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
-
-var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
-
-/* -----[ Parser ]----- */
-
-function NodeWithToken(str, start, end) {
- this.name = str;
- this.start = start;
- this.end = end;
-};
-
-NodeWithToken.prototype.toString = function() { return this.name; };
-
-function parse($TEXT, exigent_mode, embed_tokens) {
-
- var S = {
- input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
- token : null,
- prev : null,
- peeked : null,
- in_function : 0,
- in_directives : true,
- in_loop : 0,
- labels : []
- };
-
- S.token = next();
-
- function is(type, value) {
- return is_token(S.token, type, value);
- };
-
- function peek() { return S.peeked || (S.peeked = S.input()); };
-
- function next() {
- S.prev = S.token;
- if (S.peeked) {
- S.token = S.peeked;
- S.peeked = null;
- } else {
- S.token = S.input();
- }
- S.in_directives = S.in_directives && (
- S.token.type == "string" || is("punc", ";")
- );
- return S.token;
- };
-
- function prev() {
- return S.prev;
- };
-
- function croak(msg, line, col, pos) {
- var ctx = S.input.context();
- js_error(msg,
- line != null ? line : ctx.tokline,
- col != null ? col : ctx.tokcol,
- pos != null ? pos : ctx.tokpos);
- };
-
- function token_error(token, msg) {
- croak(msg, token.line, token.col);
- };
-
- function unexpected(token) {
- if (token == null)
- token = S.token;
- token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
- };
-
- function expect_token(type, val) {
- if (is(type, val)) {
- return next();
- }
- token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
- };
-
- function expect(punc) { return expect_token("punc", punc); };
-
- function can_insert_semicolon() {
- return !exigent_mode && (
- S.token.nlb || is("eof") || is("punc", "}")
- );
- };
-
- function semicolon() {
- if (is("punc", ";")) next();
- else if (!can_insert_semicolon()) unexpected();
- };
-
- function as() {
- return slice(arguments);
- };
-
- function parenthesised() {
- expect("(");
- var ex = expression();
- expect(")");
- return ex;
- };
-
- function add_tokens(str, start, end) {
- return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
- };
-
- function maybe_embed_tokens(parser) {
- if (embed_tokens) return function() {
- var start = S.token;
- var ast = parser.apply(this, arguments);
- ast[0] = add_tokens(ast[0], start, prev());
- return ast;
- };
- else return parser;
- };
-
- var statement = maybe_embed_tokens(function() {
- if (is("operator", "/") || is("operator", "/=")) {
- S.peeked = null;
- S.token = S.input(S.token.value.substr(1)); // force regexp
- }
- switch (S.token.type) {
- case "string":
- var dir = S.in_directives, stat = simple_statement();
- if (dir && stat[1][0] == "string" && !is("punc", ","))
- return as("directive", stat[1][1]);
- return stat;
- case "num":
- case "regexp":
- case "operator":
- case "atom":
- return simple_statement();
-
- case "name":
- return is_token(peek(), "punc", ":")
- ? labeled_statement(prog1(S.token.value, next, next))
- : simple_statement();
-
- case "punc":
- switch (S.token.value) {
- case "{":
- return as("block", block_());
- case "[":
- case "(":
- return simple_statement();
- case ";":
- next();
- return as("block");
- default:
- unexpected();
- }
-
- case "keyword":
- switch (prog1(S.token.value, next)) {
- case "break":
- return break_cont("break");
-
- case "continue":
- return break_cont("continue");
-
- case "debugger":
- semicolon();
- return as("debugger");
-
- case "do":
- return (function(body){
- expect_token("keyword", "while");
- return as("do", prog1(parenthesised, semicolon), body);
- })(in_loop(statement));
-
- case "for":
- return for_();
-
- case "function":
- return function_(true);
-
- case "if":
- return if_();
-
- case "return":
- if (S.in_function == 0)
- croak("'return' outside of function");
- return as("return",
- is("punc", ";")
- ? (next(), null)
- : can_insert_semicolon()
- ? null
- : prog1(expression, semicolon));
-
- case "switch":
- return as("switch", parenthesised(), switch_block_());
-
- case "throw":
- if (S.token.nlb)
- croak("Illegal newline after 'throw'");
- return as("throw", prog1(expression, semicolon));
-
- case "try":
- return try_();
-
- case "var":
- return prog1(var_, semicolon);
-
- case "const":
- return prog1(const_, semicolon);
-
- case "while":
- return as("while", parenthesised(), in_loop(statement));
-
- case "with":
- return as("with", parenthesised(), statement());
-
- default:
- unexpected();
- }
- }
- });
-
- function labeled_statement(label) {
- S.labels.push(label);
- var start = S.token, stat = statement();
- if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
- unexpected(start);
- S.labels.pop();
- return as("label", label, stat);
- };
-
- function simple_statement() {
- return as("stat", prog1(expression, semicolon));
- };
-
- function break_cont(type) {
- var name;
- if (!can_insert_semicolon()) {
- name = is("name") ? S.token.value : null;
- }
- if (name != null) {
- next();
- if (!member(name, S.labels))
- croak("Label " + name + " without matching loop or statement");
- }
- else if (S.in_loop == 0)
- croak(type + " not inside a loop or switch");
- semicolon();
- return as(type, name);
- };
-
- function for_() {
- expect("(");
- var init = null;
- if (!is("punc", ";")) {
- init = is("keyword", "var")
- ? (next(), var_(true))
- : expression(true, true);
- if (is("operator", "in")) {
- if (init[0] == "var" && init[1].length > 1)
- croak("Only one variable declaration allowed in for..in loop");
- return for_in(init);
- }
- }
- return regular_for(init);
- };
-
- function regular_for(init) {
- expect(";");
- var test = is("punc", ";") ? null : expression();
- expect(";");
- var step = is("punc", ")") ? null : expression();
- expect(")");
- return as("for", init, test, step, in_loop(statement));
- };
-
- function for_in(init) {
- var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
- next();
- var obj = expression();
- expect(")");
- return as("for-in", init, lhs, obj, in_loop(statement));
- };
-
- var function_ = function(in_statement) {
- var name = is("name") ? prog1(S.token.value, next) : null;
- if (in_statement && !name)
- unexpected();
- expect("(");
- return as(in_statement ? "defun" : "function",
- name,
- // arguments
- (function(first, a){
- while (!is("punc", ")")) {
- if (first) first = false; else expect(",");
- if (!is("name")) unexpected();
- a.push(S.token.value);
- next();
- }
- next();
- return a;
- })(true, []),
- // body
- (function(){
- ++S.in_function;
- var loop = S.in_loop;
- S.in_directives = true;
- S.in_loop = 0;
- var a = block_();
- --S.in_function;
- S.in_loop = loop;
- return a;
- })());
- };
-
- function if_() {
- var cond = parenthesised(), body = statement(), belse;
- if (is("keyword", "else")) {
- next();
- belse = statement();
- }
- return as("if", cond, body, belse);
- };
-
- function block_() {
- expect("{");
- var a = [];
- while (!is("punc", "}")) {
- if (is("eof")) unexpected();
- a.push(statement());
- }
- next();
- return a;
- };
-
- var switch_block_ = curry(in_loop, function(){
- expect("{");
- var a = [], cur = null;
- while (!is("punc", "}")) {
- if (is("eof")) unexpected();
- if (is("keyword", "case")) {
- next();
- cur = [];
- a.push([ expression(), cur ]);
- expect(":");
- }
- else if (is("keyword", "default")) {
- next();
- expect(":");
- cur = [];
- a.push([ null, cur ]);
- }
- else {
- if (!cur) unexpected();
- cur.push(statement());
- }
- }
- next();
- return a;
- });
-
- function try_() {
- var body = block_(), bcatch, bfinally;
- if (is("keyword", "catch")) {
- next();
- expect("(");
- if (!is("name"))
- croak("Name expected");
- var name = S.token.value;
- next();
- expect(")");
- bcatch = [ name, block_() ];
- }
- if (is("keyword", "finally")) {
- next();
- bfinally = block_();
- }
- if (!bcatch && !bfinally)
- croak("Missing catch/finally blocks");
- return as("try", body, bcatch, bfinally);
- };
-
- function vardefs(no_in) {
- var a = [];
- for (;;) {
- if (!is("name"))
- unexpected();
- var name = S.token.value;
- next();
- if (is("operator", "=")) {
- next();
- a.push([ name, expression(false, no_in) ]);
- } else {
- a.push([ name ]);
- }
- if (!is("punc", ","))
- break;
- next();
- }
- return a;
- };
-
- function var_(no_in) {
- return as("var", vardefs(no_in));
- };
-
- function const_() {
- return as("const", vardefs());
- };
-
- function new_() {
- var newexp = expr_atom(false), args;
- if (is("punc", "(")) {
- next();
- args = expr_list(")");
- } else {
- args = [];
- }
- return subscripts(as("new", newexp, args), true);
- };
-
- var expr_atom = maybe_embed_tokens(function(allow_calls) {
- if (is("operator", "new")) {
- next();
- return new_();
- }
- if (is("punc")) {
- switch (S.token.value) {
- case "(":
- next();
- return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
- case "[":
- next();
- return subscripts(array_(), allow_calls);
- case "{":
- next();
- return subscripts(object_(), allow_calls);
- }
- unexpected();
- }
- if (is("keyword", "function")) {
- next();
- return subscripts(function_(false), allow_calls);
- }
- if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
- var atom = S.token.type == "regexp"
- ? as("regexp", S.token.value[0], S.token.value[1])
- : as(S.token.type, S.token.value);
- return subscripts(prog1(atom, next), allow_calls);
- }
- unexpected();
- });
-
- function expr_list(closing, allow_trailing_comma, allow_empty) {
- var first = true, a = [];
- while (!is("punc", closing)) {
- if (first) first = false; else expect(",");
- if (allow_trailing_comma && is("punc", closing)) break;
- if (is("punc", ",") && allow_empty) {
- a.push([ "atom", "undefined" ]);
- } else {
- a.push(expression(false));
- }
- }
- next();
- return a;
- };
-
- function array_() {
- return as("array", expr_list("]", !exigent_mode, true));
- };
-
- function object_() {
- var first = true, a = [];
- while (!is("punc", "}")) {
- if (first) first = false; else expect(",");
- if (!exigent_mode && is("punc", "}"))
- // allow trailing comma
- break;
- var type = S.token.type;
- var name = as_property_name();
- if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
- a.push([ as_name(), function_(false), name ]);
- } else {
- expect(":");
- a.push([ name, expression(false) ]);
- }
- // FIXME [!!] Line not in original parse-js,
- // added to be able to warn about unquoted
- // keyword properties
- a[a.length - 1].type = type;
- }
- next();
- return as("object", a);
- };
-
- function as_property_name() {
- switch (S.token.type) {
- case "num":
- case "string":
- return prog1(S.token.value, next);
- }
- return as_name();
- };
-
- function as_name() {
- switch (S.token.type) {
- case "name":
- case "operator":
- case "keyword":
- case "atom":
- return prog1(S.token.value, next);
- default:
- unexpected();
- }
- };
-
- function subscripts(expr, allow_calls) {
- if (is("punc", ".")) {
- next();
- return subscripts(as("dot", expr, as_name()), allow_calls);
- }
- if (is("punc", "[")) {
- next();
- return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
- }
- if (allow_calls && is("punc", "(")) {
- next();
- return subscripts(as("call", expr, expr_list(")")), true);
- }
- return expr;
- };
-
- function maybe_unary(allow_calls) {
- if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
- return make_unary("unary-prefix",
- prog1(S.token.value, next),
- maybe_unary(allow_calls));
- }
- var val = expr_atom(allow_calls);
- while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) {
- val = make_unary("unary-postfix", S.token.value, val);
- next();
- }
- return val;
- };
-
- function make_unary(tag, op, expr) {
- if ((op == "++" || op == "--") && !is_assignable(expr))
- croak("Invalid use of " + op + " operator");
- return as(tag, op, expr);
- };
-
- function expr_op(left, min_prec, no_in) {
- var op = is("operator") ? S.token.value : null;
- if (op && op == "in" && no_in) op = null;
- var prec = op != null ? PRECEDENCE[op] : null;
- if (prec != null && prec > min_prec) {
- next();
- var right = expr_op(maybe_unary(true), prec, no_in);
- return expr_op(as("binary", op, left, right), min_prec, no_in);
- }
- return left;
- };
-
- function expr_ops(no_in) {
- return expr_op(maybe_unary(true), 0, no_in);
- };
-
- function maybe_conditional(no_in) {
- var expr = expr_ops(no_in);
- if (is("operator", "?")) {
- next();
- var yes = expression(false);
- expect(":");
- return as("conditional", expr, yes, expression(false, no_in));
- }
- return expr;
- };
-
- function is_assignable(expr) {
- if (!exigent_mode) return true;
- switch (expr[0]+"") {
- case "dot":
- case "sub":
- case "new":
- case "call":
- return true;
- case "name":
- return expr[1] != "this";
- }
- };
-
- function maybe_assign(no_in) {
- var left = maybe_conditional(no_in), val = S.token.value;
- if (is("operator") && HOP(ASSIGNMENT, val)) {
- if (is_assignable(left)) {
- next();
- return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
- }
- croak("Invalid assignment");
- }
- return left;
- };
-
- var expression = maybe_embed_tokens(function(commas, no_in) {
- if (arguments.length == 0)
- commas = true;
- var expr = maybe_assign(no_in);
- if (commas && is("punc", ",")) {
- next();
- return as("seq", expr, expression(true, no_in));
- }
- return expr;
- });
-
- function in_loop(cont) {
- try {
- ++S.in_loop;
- return cont();
- } finally {
- --S.in_loop;
- }
- };
-
- return as("toplevel", (function(a){
- while (!is("eof"))
- a.push(statement());
- return a;
- })([]));
-
-};
-
-/* -----[ Utilities ]----- */
-
-function curry(f) {
- var args = slice(arguments, 1);
- return function() { return f.apply(this, args.concat(slice(arguments))); };
-};
-
-function prog1(ret) {
- if (ret instanceof Function)
- ret = ret();
- for (var i = 1, n = arguments.length; --n > 0; ++i)
- arguments[i]();
- return ret;
-};
-
-function array_to_hash(a) {
- var ret = {};
- for (var i = 0; i < a.length; ++i)
- ret[a[i]] = true;
- return ret;
-};
-
-function slice(a, start) {
- return Array.prototype.slice.call(a, start || 0);
-};
-
-function characters(str) {
- return str.split("");
-};
-
-function member(name, array) {
- for (var i = array.length; --i >= 0;)
- if (array[i] == name)
- return true;
- return false;
-};
-
-function HOP(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
-};
-
-var warn = function() {};
-
-/* -----[ Exports ]----- */
-
-exports.tokenizer = tokenizer;
-exports.parse = parse;
-exports.slice = slice;
-exports.curry = curry;
-exports.member = member;
-exports.array_to_hash = array_to_hash;
-exports.PRECEDENCE = PRECEDENCE;
-exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
-exports.RESERVED_WORDS = RESERVED_WORDS;
-exports.KEYWORDS = KEYWORDS;
-exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
-exports.OPERATORS = OPERATORS;
-exports.is_alphanumeric_char = is_alphanumeric_char;
-exports.is_identifier_start = is_identifier_start;
-exports.is_identifier_char = is_identifier_char;
-exports.set_logger = function(logger) {
- warn = logger;
-};
-
-// Local variables:
-// js-indent-level: 8
-// End:
diff --git a/gulliver/js/codemirror/test/mode_test.js b/gulliver/js/codemirror/test/mode_test.js
index 79a775249..46174e1f7 100644
--- a/gulliver/js/codemirror/test/mode_test.js
+++ b/gulliver/js/codemirror/test/mode_test.js
@@ -66,6 +66,10 @@
});
};
+ function esc(str) {
+ return str.replace('&', '&').replace('<', '<');
+ }
+
function compare(text, expected, mode) {
var expectedOutput = [];
@@ -77,43 +81,26 @@
var observedOutput = highlight(text, mode);
- var pass, passStyle = "";
- pass = highlightOutputsEqual(expectedOutput, observedOutput);
- passStyle = pass ? 'mt-pass' : 'mt-fail';
-
- var s = '';
- if (pass) {
- s += '';
- s += '
' + text + ' ';
- s += '
';
- s += prettyPrintOutputTable(observedOutput);
- s += '
';
- s += '
';
- return s;
- } else {
- s += '';
- s += '
' + text + ' ';
+ var s = "";
+ var diff = highlightOutputsDifferent(expectedOutput, observedOutput);
+ if (diff != null) {
+ s += '
';
+ s += '
' + esc(text) + ' ';
s += '
';
s += 'expected:';
- s += prettyPrintOutputTable(expectedOutput);
+ s += prettyPrintOutputTable(expectedOutput, diff);
s += 'observed:';
- s += prettyPrintOutputTable(observedOutput);
+ s += prettyPrintOutputTable(observedOutput, diff);
s += '
';
s += '
';
- throw s;
}
+ if (observedOutput.indentFailures) {
+ for (var i = 0; i < observedOutput.indentFailures.length; i++)
+ s += "
" + esc(observedOutput.indentFailures[i]) + "
";
+ }
+ if (s) throw new Failure(s);
}
- /**
- * Emulation of CodeMirror's internal highlight routine for testing. Multi-line
- * input is supported.
- *
- * @param string to highlight
- *
- * @param mode the mode that will do the actual highlighting
- *
- * @return array of [style, token] pairs
- */
function highlight(string, mode) {
var state = mode.startState()
@@ -121,18 +108,24 @@
var st = [], pos = 0;
for (var i = 0; i < lines.length; ++i) {
var line = lines[i], newLine = true;
+ if (mode.indent) {
+ var ws = line.match(/^\s*/)[0];
+ var indent = mode.indent(state, line.slice(ws.length));
+ if (indent != CodeMirror.Pass && indent != ws.length)
+ (st.indentFailures || (st.indentFailures = [])).push(
+ "Indentation of line " + (i + 1) + " is " + indent + " (expected " + ws.length + ")");
+ }
var stream = new CodeMirror.StringStream(line);
if (line == "" && mode.blankLine) mode.blankLine(state);
/* Start copied code from CodeMirror.highlight */
while (!stream.eol()) {
- var style = mode.token(stream, state), substr = stream.current();
- if (style && style.indexOf(" ") > -1) style = style.split(' ').sort().join(' ');
-
+ var compare = mode.token(stream, state), substr = stream.current();
+ if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');
stream.start = stream.pos;
- if (pos && st[pos-2] == style && !newLine) {
+ if (pos && st[pos-2] == compare && !newLine) {
st[pos-1] += substr;
} else if (substr) {
- st[pos++] = style; st[pos++] = substr;
+ st[pos++] = compare; st[pos++] = substr;
}
// Give up when line is ridiculously long
if (stream.pos > 5000) {
@@ -146,45 +139,28 @@
return st;
}
- /**
- * Compare two arrays of output from highlight.
- *
- * @param o1 array of [style, token] pairs
- *
- * @param o2 array of [style, token] pairs
- *
- * @return boolean; true iff outputs equal
- */
- function highlightOutputsEqual(o1, o2) {
- if (o1.length != o2.length) return false;
- for (var i = 0; i < o1.length; ++i)
- if (o1[i] != o2[i]) return false;
- return true;
+ function highlightOutputsDifferent(o1, o2) {
+ var minLen = Math.min(o1.length, o2.length);
+ for (var i = 0; i < minLen; ++i)
+ if (o1[i] != o2[i]) return i >> 1;
+ if (o1.length > minLen || o2.length > minLen) return minLen;
}
- /**
- * Print tokens and corresponding styles in a table. Spaces in the token are
- * replaced with 'interpunct' dots (·).
- *
- * @param output array of [style, token] pairs
- *
- * @return html string
- */
- function prettyPrintOutputTable(output) {
+ function prettyPrintOutputTable(output, diffAt) {
var s = '
';
s += '';
for (var i = 0; i < output.length; i += 2) {
var style = output[i], val = output[i+1];
s +=
- '' +
- '' +
- val.replace(/ /g,'\xb7') +
+ ' ' +
+ '' +
+ esc(val.replace(/ /g,'\xb7')) +
' ' +
' ';
}
s += ' ';
for (var i = 0; i < output.length; i += 2) {
- s += '' + output[i] + ' ';
+ s += '' + (output[i] || null) + ' ';
}
s += '
';
return s;
diff --git a/gulliver/js/codemirror/test/run.js b/gulliver/js/codemirror/test/run.js
index 5588d6f38..140539c17 100755
--- a/gulliver/js/codemirror/test/run.js
+++ b/gulliver/js/codemirror/test/run.js
@@ -5,29 +5,34 @@ var lint = require("./lint/lint");
lint.checkDir("mode");
lint.checkDir("lib");
lint.checkDir("addon");
+lint.checkDir("keymap");
var ok = lint.success();
-var files = new (require('node-static').Server)('.');
+var files = new (require('node-static').Server)();
var server = require('http').createServer(function (req, res) {
req.addListener('end', function () {
- files.serve(req, res);
- });
+ files.serve(req, res, function (err/*, result */) {
+ if (err) {
+ console.error(err);
+ process.exit(1);
+ }
+ });
+ }).resume();
}).addListener('error', function (err) {
throw err;
}).listen(3000, function () {
- var child_process = require('child_process');
- child_process.exec("which phantomjs", function (err) {
- if (err) {
- console.error("PhantomJS is not installed. Download from http://phantomjs.org");
- process.exit(1);
- }
- var cmd = 'phantomjs test/phantom_driver.js';
- child_process.exec(cmd, function (err, stdout) {
- server.close();
- console.log(stdout);
- process.exit(err || !ok ? 1 : 0);
- });
+ var childProcess = require('child_process');
+ var phantomjs = require("phantomjs");
+ var childArgs = [
+ require("path").join(__dirname, 'phantom_driver.js')
+ ];
+ childProcess.execFile(phantomjs.path, childArgs, function (err, stdout, stderr) {
+ server.close();
+ console.log(stdout);
+ if (err) console.error(err);
+ if (stderr) console.error(stderr);
+ process.exit(err || stderr || !ok ? 1 : 0);
});
});
diff --git a/gulliver/js/codemirror/test/search_test.js b/gulliver/js/codemirror/test/search_test.js
new file mode 100644
index 000000000..04a1e685a
--- /dev/null
+++ b/gulliver/js/codemirror/test/search_test.js
@@ -0,0 +1,62 @@
+(function() {
+ "use strict";
+
+ function test(name) {
+ var text = Array.prototype.slice.call(arguments, 1, arguments.length - 1).join("\n");
+ var body = arguments[arguments.length - 1];
+ return window.test("search_" + name, function() {
+ body(new CodeMirror.Doc(text));
+ });
+ }
+
+ function run(doc, query, insensitive) {
+ var cursor = doc.getSearchCursor(query, null, insensitive);
+ for (var i = 3; i < arguments.length; i += 4) {
+ var found = cursor.findNext();
+ is(found, "not enough results (forward)");
+ eqPos(Pos(arguments[i], arguments[i + 1]), cursor.from(), "from, forward, " + (i - 3) / 4);
+ eqPos(Pos(arguments[i + 2], arguments[i + 3]), cursor.to(), "to, forward, " + (i - 3) / 4);
+ }
+ is(!cursor.findNext(), "too many matches (forward)");
+ for (var i = arguments.length - 4; i >= 3; i -= 4) {
+ var found = cursor.findPrevious();
+ is(found, "not enough results (backwards)");
+ eqPos(Pos(arguments[i], arguments[i + 1]), cursor.from(), "from, backwards, " + (i - 3) / 4);
+ eqPos(Pos(arguments[i + 2], arguments[i + 3]), cursor.to(), "to, backwards, " + (i - 3) / 4);
+ }
+ is(!cursor.findPrevious(), "too many matches (backwards)");
+ }
+
+ test("simple", "abcdefg", "abcdefg", function(doc) {
+ run(doc, "cde", false, 0, 2, 0, 5, 1, 2, 1, 5);
+ });
+
+ test("multiline", "hallo", "goodbye", function(doc) {
+ run(doc, "llo\ngoo", false, 0, 2, 1, 3);
+ run(doc, "blah\nhall", false);
+ run(doc, "bye\neye", false);
+ });
+
+ test("regexp", "abcde", "abcde", function(doc) {
+ run(doc, /bcd/, false, 0, 1, 0, 4, 1, 1, 1, 4);
+ run(doc, /BCD/, false);
+ run(doc, /BCD/i, false, 0, 1, 0, 4, 1, 1, 1, 4);
+ });
+
+ test("insensitive", "hallo", "HALLO", "oink", "hAllO", function(doc) {
+ run(doc, "All", false, 3, 1, 3, 4);
+ run(doc, "All", true, 0, 1, 0, 4, 1, 1, 1, 4, 3, 1, 3, 4);
+ });
+
+ test("multilineInsensitive", "zie ginds komT", "De Stoomboot", "uit Spanje weer aan", function(doc) {
+ run(doc, "komt\nde stoomboot\nuit", false);
+ run(doc, "komt\nde stoomboot\nuit", true, 0, 10, 2, 3);
+ run(doc, "kOMt\ndE stOOmboot\nuiT", true, 0, 10, 2, 3);
+ });
+
+ test("expandingCaseFold", "
İİ İİ ", "
uu uu ", function(doc) {
+ if (phantom) return; // A Phantom bug makes this hang
+ run(doc, "", true, 0, 8, 0, 12, 1, 8, 1, 12);
+ run(doc, "İİ", true, 0, 3, 0, 5, 0, 6, 0, 8);
+ });
+})();
diff --git a/gulliver/js/codemirror/test/test.js b/gulliver/js/codemirror/test/test.js
index 96f37353a..3ad8d3549 100644
--- a/gulliver/js/codemirror/test/test.js
+++ b/gulliver/js/codemirror/test/test.js
@@ -1,5 +1,7 @@
var Pos = CodeMirror.Pos;
+CodeMirror.defaults.rtlMoveVisually = true;
+
function forEach(arr, f) {
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
}
@@ -32,6 +34,8 @@ var opera_version = opera && navigator.userAgent.match(/Version\/(\d+\.\d+)/);
if (opera_version) opera_version = Number(opera_version);
var opera_lt10 = opera && (!opera_version || opera_version < 10);
+namespace = "core_";
+
test("core_fromTextArea", function() {
var te = document.getElementById("code");
te.value = "CONTENT";
@@ -153,6 +157,16 @@ testCM("indent", function(cm) {
eq(cm.getLine(1), "\t\t blah();");
}, {value: "if (x) {\nblah();\n}", indentUnit: 3, indentWithTabs: true, tabSize: 8});
+testCM("indentByNumber", function(cm) {
+ cm.indentLine(0, 2);
+ eq(cm.getLine(0), " foo");
+ cm.indentLine(0, -200);
+ eq(cm.getLine(0), "foo");
+ cm.setSelection(Pos(0, 0), Pos(1, 2));
+ cm.indentSelection(3);
+ eq(cm.getValue(), " foo\n bar\nbaz");
+}, {value: "foo\nbar\nbaz"});
+
test("core_defaults", function() {
var defsCopy = {}, defs = CodeMirror.defaults;
for (var opt in defs) defsCopy[opt] = defs[opt];
@@ -209,15 +223,18 @@ testCM("coords", function(cm) {
testCM("coordsChar", function(cm) {
addDoc(cm, 35, 70);
- for (var ch = 0; ch <= 35; ch += 5) {
- for (var line = 0; line < 70; line += 5) {
- cm.setCursor(line, ch);
- var coords = cm.charCoords(Pos(line, ch));
- var pos = cm.coordsChar({left: coords.left, top: coords.top + 5});
- eqPos(pos, Pos(line, ch));
+ for (var i = 0; i < 2; ++i) {
+ var sys = i ? "local" : "page";
+ for (var ch = 0; ch <= 35; ch += 5) {
+ for (var line = 0; line < 70; line += 5) {
+ cm.setCursor(line, ch);
+ var coords = cm.charCoords(Pos(line, ch), sys);
+ var pos = cm.coordsChar({left: coords.left + 1, top: coords.top + 1}, sys);
+ eqPos(pos, Pos(line, ch));
+ }
}
}
-});
+}, {lineNumbers: true});
testCM("posFromIndex", function(cm) {
cm.setValue(
@@ -419,6 +436,36 @@ testCM("markTextStayGone", function(cm) {
eq(m1.find(), null);
}, {value: "hello"});
+testCM("markTextAllowEmpty", function(cm) {
+ var m1 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false});
+ is(m1.find());
+ cm.replaceRange("x", Pos(0, 0));
+ is(m1.find());
+ cm.replaceRange("y", Pos(0, 2));
+ is(m1.find());
+ cm.replaceRange("z", Pos(0, 3), Pos(0, 4));
+ is(!m1.find());
+ var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {clearWhenEmpty: false,
+ inclusiveLeft: true,
+ inclusiveRight: true});
+ cm.replaceRange("q", Pos(0, 1), Pos(0, 2));
+ is(m2.find());
+ cm.replaceRange("", Pos(0, 0), Pos(0, 3));
+ is(!m2.find());
+ var m3 = cm.markText(Pos(0, 1), Pos(0, 1), {clearWhenEmpty: false});
+ cm.replaceRange("a", Pos(0, 3));
+ is(m3.find());
+ cm.replaceRange("b", Pos(0, 1));
+ is(!m3.find());
+}, {value: "abcde"});
+
+testCM("markTextStacked", function(cm) {
+ var m1 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false});
+ var m2 = cm.markText(Pos(0, 0), Pos(0, 0), {clearWhenEmpty: false});
+ cm.replaceRange("B", Pos(0, 1));
+ is(m1.find() && m2.find());
+}, {value: "A"});
+
testCM("undoPreservesNewMarks", function(cm) {
cm.markText(Pos(0, 3), Pos(0, 4));
cm.markText(Pos(1, 1), Pos(1, 3));
@@ -445,6 +492,13 @@ testCM("markClearBetween", function(cm) {
eq(cm.findMarksAt(Pos(1, 1)).length, 0);
});
+testCM("deleteSpanCollapsedInclusiveLeft", function(cm) {
+ var from = Pos(1, 0), to = Pos(1, 1);
+ var m = cm.markText(from, to, {collapsed: true, inclusiveLeft: true});
+ // Delete collapsed span.
+ cm.replaceRange("", from, to);
+}, {value: "abc\nX\ndef"});
+
testCM("bookmark", function(cm) {
function p(v) { return v && Pos(v[0], v[1]); }
forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]},
@@ -477,6 +531,42 @@ testCM("bookmarkInsertLeft", function(cm) {
eqPos(bl.find(), Pos(0, 1));
}, {value: "abcdef"});
+testCM("bookmarkCursor", function(cm) {
+ var pos01 = cm.cursorCoords(Pos(0, 1)), pos11 = cm.cursorCoords(Pos(1, 1)),
+ pos20 = cm.cursorCoords(Pos(2, 0)), pos30 = cm.cursorCoords(Pos(3, 0)),
+ pos41 = cm.cursorCoords(Pos(4, 1));
+ cm.setBookmark(Pos(0, 1), {widget: document.createTextNode("←"), insertLeft: true});
+ cm.setBookmark(Pos(2, 0), {widget: document.createTextNode("←"), insertLeft: true});
+ cm.setBookmark(Pos(1, 1), {widget: document.createTextNode("→")});
+ cm.setBookmark(Pos(3, 0), {widget: document.createTextNode("→")});
+ var new01 = cm.cursorCoords(Pos(0, 1)), new11 = cm.cursorCoords(Pos(1, 1)),
+ new20 = cm.cursorCoords(Pos(2, 0)), new30 = cm.cursorCoords(Pos(3, 0));
+ is(new01.left == pos01.left && new01.top == pos01.top, "at left, middle of line");
+ is(new11.left > pos11.left && new11.top == pos11.top, "at right, middle of line");
+ is(new20.left == pos20.left && new20.top == pos20.top, "at left, empty line");
+ is(new30.left > pos30.left && new30.top == pos30.top, "at right, empty line");
+ cm.setBookmark(Pos(4, 0), {widget: document.createTextNode("→")});
+ is(cm.cursorCoords(Pos(4, 1)).left > pos41.left, "single-char bug");
+}, {value: "foo\nbar\n\n\nx\ny"});
+
+testCM("multiBookmarkCursor", function(cm) {
+ if (phantom) return;
+ var ms = [], m;
+ function add(insertLeft) {
+ for (var i = 0; i < 3; ++i) {
+ var node = document.createElement("span");
+ node.innerHTML = "X";
+ ms.push(cm.setBookmark(Pos(0, 1), {widget: node, insertLeft: insertLeft}));
+ }
+ }
+ var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left;
+ add(true);
+ is(Math.abs(base1 - cm.cursorCoords(Pos(0, 1)).left) < .1);
+ while (m = ms.pop()) m.clear();
+ add(false);
+ is(Math.abs(base4 - cm.cursorCoords(Pos(0, 1)).left) < .1);
+}, {value: "abcdefg"});
+
testCM("getAllMarks", function(cm) {
addDoc(cm, 10, 10);
var m1 = cm.setBookmark(Pos(0, 2));
@@ -511,6 +601,25 @@ testCM("scrollSnap", function(cm) {
is(info.left == 0 && info.top + 2 > info.height - cm.getScrollerElement().clientHeight, "scrolled clean to bottom");
});
+testCM("scrollIntoView", function(cm) {
+ if (phantom) return;
+ var outer = cm.getWrapperElement().getBoundingClientRect();
+ function test(line, ch) {
+ var pos = Pos(line, ch);
+ cm.scrollIntoView(pos);
+ var box = cm.charCoords(pos, "window");
+ is(box.left >= outer.left && box.right <= outer.right &&
+ box.top >= outer.top && box.bottom <= outer.bottom);
+ }
+ addDoc(cm, 200, 200);
+ test(199, 199);
+ test(0, 0);
+ test(100, 100);
+ test(199, 0);
+ test(0, 199);
+ test(100, 100);
+});
+
testCM("selectionPos", function(cm) {
if (phantom) return;
cm.setSize(100, 100);
@@ -633,8 +742,8 @@ testCM("collapsedRangeCoordsChar", function(cm) {
var m1 = cm.markText(Pos(0, 0), Pos(2, 0), opts);
eqPos(cm.coordsChar(pos_1_3), Pos(3, 3));
m1.clear();
- var m1 = cm.markText(Pos(0, 0), Pos(1, 1), opts);
- var m2 = cm.markText(Pos(1, 1), Pos(2, 0), opts);
+ var m1 = cm.markText(Pos(0, 0), Pos(1, 1), {collapsed: true, inclusiveLeft: true});
+ var m2 = cm.markText(Pos(1, 1), Pos(2, 0), {collapsed: true, inclusiveRight: true});
eqPos(cm.coordsChar(pos_1_3), Pos(3, 3));
m1.clear(); m2.clear();
var m1 = cm.markText(Pos(0, 0), Pos(1, 6), opts);
@@ -682,6 +791,7 @@ testCM("everythingFolded", function(cm) {
});
testCM("structuredFold", function(cm) {
+ if (phantom) return;
addDoc(cm, 4, 8);
var range = cm.markText(Pos(1, 2), Pos(6, 2), {
replacedWith: document.createTextNode("Q")
@@ -695,7 +805,7 @@ testCM("structuredFold", function(cm) {
eq(cm.getValue(), "xxxx\nxxxx\nxxxx");
addDoc(cm, 4, 8);
range = cm.markText(Pos(1, 2), Pos(6, 2), {
- replacedWith: document.createTextNode("x"),
+ replacedWith: document.createTextNode("M"),
clearOnEnter: true
});
var cleared = 0;
@@ -716,6 +826,12 @@ testCM("structuredFold", function(cm) {
cm.setCursor(1, 2);
CodeMirror.commands.goCharRight(cm);
eqPos(cm.getCursor(), Pos(1, 3));
+ range = cm.markText(Pos(2, 0), Pos(4, 4), {
+ replacedWith: document.createTextNode("M")
+ });
+ cm.setCursor(1, 0);
+ CodeMirror.commands.goLineDown(cm);
+ eqPos(cm.getCursor(), Pos(2, 0));
}, null);
testCM("nestedFold", function(cm) {
@@ -755,6 +871,65 @@ testCM("badNestedFold", function(cm) {
is(/overlap/i.test(caught.message), "wrong error");
});
+testCM("nestedFoldOnSide", function(cm) {
+ var m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true, inclusiveRight: true});
+ var m2 = cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true});
+ cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true}).clear();
+ try { cm.markText(Pos(0, 1), Pos(0, 2), {collapsed: true, inclusiveLeft: true}); }
+ catch(e) { var caught = e; }
+ is(caught && /overlap/i.test(caught.message));
+ var m3 = cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true});
+ var m4 = cm.markText(Pos(2, 0), Pos(2, 1), {collapse: true, inclusiveRight: true});
+ m1.clear(); m4.clear();
+ m1 = cm.markText(Pos(0, 1), Pos(2, 1), {collapsed: true});
+ cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true}).clear();
+ try { cm.markText(Pos(2, 0), Pos(2, 1), {collapsed: true, inclusiveRight: true}); }
+ catch(e) { var caught = e; }
+ is(caught && /overlap/i.test(caught.message));
+}, {value: "ab\ncd\ef"});
+
+testCM("wrappingInlineWidget", function(cm) {
+ cm.setSize("11em");
+ var w = document.createElement("span");
+ w.style.color = "red";
+ w.innerHTML = "one two three four";
+ cm.markText(Pos(0, 6), Pos(0, 9), {replacedWith: w});
+ var cur0 = cm.cursorCoords(Pos(0, 0)), cur1 = cm.cursorCoords(Pos(0, 10));
+ is(cur0.top < cur1.top);
+ is(cur0.bottom < cur1.bottom);
+ var curL = cm.cursorCoords(Pos(0, 6)), curR = cm.cursorCoords(Pos(0, 9));
+ eq(curL.top, cur0.top);
+ eq(curL.bottom, cur0.bottom);
+ eq(curR.top, cur1.top);
+ eq(curR.bottom, cur1.bottom);
+ cm.replaceRange("", Pos(0, 9), Pos(0));
+ curR = cm.cursorCoords(Pos(0, 9));
+ eq(curR.top, cur1.top);
+ eq(curR.bottom, cur1.bottom);
+}, {value: "1 2 3 xxx 4", lineWrapping: true});
+
+testCM("changedInlineWidget", function(cm) {
+ cm.setSize("10em");
+ var w = document.createElement("span");
+ w.innerHTML = "x";
+ var m = cm.markText(Pos(0, 4), Pos(0, 5), {replacedWith: w});
+ w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed";
+ m.changed();
+ var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0];
+ is(hScroll.scrollWidth > hScroll.clientWidth);
+}, {value: "hello there"});
+
+testCM("changedBookmark", function(cm) {
+ cm.setSize("10em");
+ var w = document.createElement("span");
+ w.innerHTML = "x";
+ var m = cm.setBookmark(Pos(0, 4), {widget: w});
+ w.innerHTML = "and now the widget is really really long all of a sudden and a scrollbar is needed";
+ m.changed();
+ var hScroll = byClassName(cm.getWrapperElement(), "CodeMirror-hscrollbar")[0];
+ is(hScroll.scrollWidth > hScroll.clientWidth);
+}, {value: "abcdefg"});
+
testCM("inlineWidget", function(cm) {
var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")});
cm.setCursor(0, 2);
@@ -845,6 +1020,24 @@ testCM("moveVstuck", function(cm) {
eqPos(cm.getCursor(), Pos(0, 26));
}, {lineWrapping: true}, ie_lt8 || opera_lt10);
+testCM("collapseOnMove", function(cm) {
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
+ cm.execCommand("goLineUp");
+ is(!cm.somethingSelected());
+ eqPos(cm.getCursor(), Pos(0, 1));
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
+ cm.execCommand("goPageDown");
+ is(!cm.somethingSelected());
+ eqPos(cm.getCursor(), Pos(2, 4));
+ cm.execCommand("goLineUp");
+ cm.execCommand("goLineUp");
+ eqPos(cm.getCursor(), Pos(0, 4));
+ cm.setSelection(Pos(0, 1), Pos(2, 4));
+ cm.execCommand("goCharLeft");
+ is(!cm.somethingSelected());
+ eqPos(cm.getCursor(), Pos(0, 1));
+}, {value: "aaaaa\nb\nccccc"});
+
testCM("clickTab", function(cm) {
var p0 = cm.charCoords(Pos(0, 0));
eqPos(cm.coordsChar({left: p0.left + 5, top: p0.top + 5}), Pos(0, 0));
@@ -858,7 +1051,7 @@ testCM("verticalScroll", function(cm) {
cm.setLine(0, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah");
is(sc.scrollWidth > baseWidth, "scrollbar present");
cm.setLine(0, "foo");
- eq(sc.scrollWidth, baseWidth, "scrollbar gone");
+ if (!phantom) eq(sc.scrollWidth, baseWidth, "scrollbar gone");
cm.setLine(0, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah");
cm.setLine(1, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh");
is(sc.scrollWidth > baseWidth, "present again");
@@ -1013,7 +1206,8 @@ testCM("verticalMovementCommandsWrapping", function(cm) {
testCM("rtlMovement", function(cm) {
forEach(["خحج", "خحabcخحج", "abخحخحجcd", "abخde", "abخح2342خ1حج", "خ1ح2خح3حxج",
- "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!", "foobarر"], function(line) {
+ "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!", "foobarر", "خ ة ق",
+ "
"], function(line) {
var inv = line.charAt(0) == "خ";
cm.setValue(line + "\n"); cm.execCommand(inv ? "goLineEnd" : "goLineStart");
var cursor = byClassName(cm.getWrapperElement(), "CodeMirror-cursor")[0];
@@ -1032,7 +1226,7 @@ testCM("rtlMovement", function(cm) {
prevX = cursor.offsetLeft;
}
});
-}, {rtlMoveVisually: true});
+});
// Verify that updating a line clears its bidi ordering
testCM("bidiUpdate", function(cm) {
@@ -1213,6 +1407,7 @@ testCM("atomicMarker", function(cm) {
eqPos(cm.getCursor(), Pos(8, 3));
m.clear();
m = atom(1, 1, 3, 8);
+ cm.setCursor(Pos(0, 0));
cm.setCursor(Pos(2, 0));
eqPos(cm.getCursor(), Pos(3, 8));
cm.execCommand("goCharLeft");
@@ -1284,6 +1479,21 @@ testCM("dirtyBit", function(cm) {
eq(cm.isClean(), true);
});
+testCM("changeGeneration", function(cm) {
+ cm.replaceSelection("x", null, "+insert");
+ var softGen = cm.changeGeneration();
+ cm.replaceSelection("x", null, "+insert");
+ cm.undo();
+ eq(cm.getValue(), "");
+ is(!cm.isClean(softGen));
+ cm.replaceSelection("x", null, "+insert");
+ var hardGen = cm.changeGeneration(true);
+ cm.replaceSelection("x", null, "+insert");
+ cm.undo();
+ eq(cm.getValue(), "x");
+ is(cm.isClean(hardGen));
+});
+
testCM("addKeyMap", function(cm) {
function sendKey(code) {
cm.triggerOnKeyDown({type: "keydown", keyCode: code,
@@ -1355,6 +1565,19 @@ testCM("beforeChange", function(cm) {
eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey");
}, {value: "abcdefghijk"});
+testCM("beforeChangeUndo", function(cm) {
+ cm.setLine(0, "hi");
+ cm.setLine(0, "bye");
+ eq(cm.historySize().undo, 2);
+ cm.on("beforeChange", function(cm, change) {
+ is(!change.update);
+ change.cancel();
+ });
+ cm.undo();
+ eq(cm.historySize().undo, 0);
+ eq(cm.getValue(), "bye\ntwo");
+}, {value: "one\ntwo"});
+
testCM("beforeSelectionChange", function(cm) {
function notAtEnd(cm, pos) {
var len = cm.getLine(pos.line).length;
@@ -1398,3 +1621,41 @@ testCM("change_removedText", function(cm) {
eq(removedText[0].join("\n"), "abc\nd");
eq(removedText[1].join("\n"), "");
});
+
+testCM("lineStyleFromMode", function(cm) {
+ CodeMirror.defineMode("test_mode", function() {
+ return {token: function(stream) {
+ if (stream.match(/^\[[^\]]*\]/)) return "line-brackets";
+ if (stream.match(/^\([^\]]*\)/)) return "line-background-parens";
+ stream.match(/^\s+|^\S+/);
+ }};
+ });
+ cm.setOption("mode", "test_mode");
+ var bracketElts = byClassName(cm.getWrapperElement(), "brackets");
+ eq(bracketElts.length, 1);
+ eq(bracketElts[0].nodeName, "PRE");
+ is(!/brackets.*brackets/.test(bracketElts[0].className));
+ var parenElts = byClassName(cm.getWrapperElement(), "parens");
+ eq(parenElts.length, 1);
+ eq(parenElts[0].nodeName, "DIV");
+ is(!/parens.*parens/.test(parenElts[0].className));
+}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: nothing"});
+
+CodeMirror.registerHelper("xxx", "a", "A");
+CodeMirror.registerHelper("xxx", "b", "B");
+CodeMirror.defineMode("yyy", function() {
+ return {
+ token: function(stream) { stream.skipToEnd(); },
+ xxx: ["a", "b", "q"]
+ };
+});
+CodeMirror.registerGlobalHelper("xxx", "c", function(m) { return m.enableC; }, "C");
+
+testCM("helpers", function(cm) {
+ cm.setOption("mode", "yyy");
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "A/B");
+ cm.setOption("mode", {name: "yyy", modeProps: {xxx: "b", enableC: true}});
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "B/C");
+ cm.setOption("mode", "javascript");
+ eq(cm.getHelpers(Pos(0, 0), "xxx").join("/"), "");
+});
diff --git a/gulliver/js/codemirror/test/vim_test.js b/gulliver/js/codemirror/test/vim_test.js
index f91be02f9..7184cb25a 100644
--- a/gulliver/js/codemirror/test/vim_test.js
+++ b/gulliver/js/codemirror/test/vim_test.js
@@ -10,7 +10,9 @@ var code = '' +
' n = read(0, buf, sizeof buf);\n' +
' bufp = buf;\n' +
' }\n' +
+'\n' +
' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' +
+' \n' +
'}\n';
var lines = (function() {
@@ -32,6 +34,7 @@ var wordLine = lines[0];
var bigWordLine = lines[1];
var charLine = lines[2];
var bracesLine = lines[3];
+var seekBraceLine = lines[4];
var word1 = {
start: { line: wordLine.line, ch: 1 },
@@ -80,15 +83,29 @@ var curlys1 = {
start: { line: bracesLine.line, ch: 9 },
end: { line: bracesLine.line, ch: 11 }
};
+var seekOutside = {
+ start: { line: seekBraceLine.line, ch: 1 },
+ end: { line: seekBraceLine.line, ch: 16 }
+};
+var seekInside = {
+ start: { line: seekBraceLine.line, ch: 14 },
+ end: { line: seekBraceLine.line, ch: 11 }
+};
function copyCursor(cur) {
return { ch: cur.ch, line: cur.line };
}
+function forEach(arr, func) {
+ for (var i = 0; i < arr.length; i++) {
+ func(arr[i]);
+ }
+}
+
function testVim(name, run, opts, expectedFail) {
var vimOpts = {
lineNumbers: true,
- keyMap: 'vim',
+ vimMode: true,
showCursorWhenSelecting: true,
value: code
};
@@ -100,8 +117,7 @@ function testVim(name, run, opts, expectedFail) {
return test('vim_' + name, function() {
var place = document.getElementById("testground");
var cm = CodeMirror(place, vimOpts);
- CodeMirror.Vim.maybeInitState(cm);
- var vim = cm.vimState;
+ var vim = CodeMirror.Vim.maybeInitVimState_(cm);
function doKeysFn(cm) {
return function(args) {
@@ -113,6 +129,31 @@ function testVim(name, run, opts, expectedFail) {
}
}
}
+ function doInsertModeKeysFn(cm) {
+ return function(args) {
+ if (args instanceof Array) { arguments = args; }
+ function executeHandler(handler) {
+ if (typeof handler == 'string') {
+ CodeMirror.commands[handler](cm);
+ } else {
+ handler(cm);
+ }
+ return true;
+ }
+ for (var i = 0; i < arguments.length; i++) {
+ var key = arguments[i];
+ // Find key in keymap and handle.
+ var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler);
+ // Record for insert mode.
+ if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') {
+ var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
+ if (lastChange) {
+ lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
+ }
+ }
+ }
+ }
+ }
function doExFn(cm) {
return function(command) {
cm.openDialog = helpers.fakeOpenDialog(command);
@@ -137,6 +178,10 @@ function testVim(name, run, opts, expectedFail) {
}
var helpers = {
doKeys: doKeysFn(cm),
+ // Warning: Only emulates keymap events, not character insertions. Use
+ // replaceRange to simulate character insertions.
+ // Keys are in CodeMirror format, NOT vim format.
+ doInsertModeKeys: doInsertModeKeysFn(cm),
doEx: doExFn(cm),
assertCursorAt: assertCursorAtFn(cm),
fakeOpenDialog: fakeOpenDialog,
@@ -144,13 +189,13 @@ function testVim(name, run, opts, expectedFail) {
return CodeMirror.Vim.getRegisterController();
}
}
- CodeMirror.Vim.clearVimGlobalState_();
+ CodeMirror.Vim.resetVimGlobalState_();
var successful = false;
try {
run(cm, vim, helpers);
successful = true;
} finally {
- if ((debug && !successful) || verbose) {
+ if (!successful || verbose) {
place.style.visibility = "visible";
} else {
place.removeChild(cm.getWrapperElement());
@@ -158,7 +203,70 @@ function testVim(name, run, opts, expectedFail) {
}
}, expectedFail);
};
-
+testVim('qq@q', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('q', 'q', 'l', 'l', 'q');
+ helpers.assertCursorAt(0,2);
+ helpers.doKeys('@', 'q');
+ helpers.assertCursorAt(0,4);
+}, { value: ' '});
+testVim('@@', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('q', 'q', 'l', 'l', 'q');
+ helpers.assertCursorAt(0,2);
+ helpers.doKeys('@', 'q');
+ helpers.assertCursorAt(0,4);
+ helpers.doKeys('@', '@');
+ helpers.assertCursorAt(0,6);
+}, { value: ' '});
+var jumplistScene = ''+
+ 'word\n'+
+ '(word)\n'+
+ '{word\n'+
+ 'word.\n'+
+ '\n'+
+ 'word search\n'+
+ '}word\n'+
+ 'word\n'+
+ 'word\n';
+function testJumplist(name, keys, endPos, startPos, dialog) {
+ endPos = makeCursor(endPos[0], endPos[1]);
+ startPos = makeCursor(startPos[0], startPos[1]);
+ testVim(name, function(cm, vim, helpers) {
+ CodeMirror.Vim.resetVimGlobalState_();
+ if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
+ cm.setCursor(startPos);
+ helpers.doKeys.apply(null, keys);
+ helpers.assertCursorAt(endPos);
+ }, {value: jumplistScene});
+};
+testJumplist('jumplist_H', ['H', '
'], [5,2], [5,2]);
+testJumplist('jumplist_M', ['M', ''], [2,2], [2,2]);
+testJumplist('jumplist_L', ['L', ''], [2,2], [2,2]);
+testJumplist('jumplist_[[', ['[', '[', ''], [5,2], [5,2]);
+testJumplist('jumplist_]]', [']', ']', ''], [2,2], [2,2]);
+testJumplist('jumplist_G', ['G', ''], [5,2], [5,2]);
+testJumplist('jumplist_gg', ['g', 'g', ''], [5,2], [5,2]);
+testJumplist('jumplist_%', ['%', ''], [1,5], [1,5]);
+testJumplist('jumplist_{', ['{', ''], [1,5], [1,5]);
+testJumplist('jumplist_}', ['}', ''], [1,5], [1,5]);
+testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', ''], [1,5], [1,5]);
+testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', ''], [1,5], [1,5]);
+testJumplist('jumplist_*_cachedCursor', ['*', ''], [1,3], [1,3]);
+testJumplist('jumplist_#_cachedCursor', ['#', ''], [1,3], [1,3]);
+testJumplist('jumplist_n', ['#', 'n', ''], [1,1], [2,3]);
+testJumplist('jumplist_N', ['#', 'N', ''], [1,1], [2,3]);
+testJumplist('jumplist_repeat_', ['*', '*', '*', '3', ''], [2,3], [2,3]);
+testJumplist('jumplist_repeat_', ['*', '*', '*', '3', '', '2', ''], [5,0], [2,3]);
+testJumplist('jumplist_repeated_motion', ['3', '*', ''], [2,3], [2,3]);
+testJumplist('jumplist_/', ['/', ''], [2,3], [2,3], 'dialog');
+testJumplist('jumplist_?', ['?', ''], [2,3], [2,3], 'dialog');
+testJumplist('jumplist_skip_delted_mark',
+ ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''],
+ [0,2], [0,2]);
+testJumplist('jumplist_skip_delted_mark',
+ ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''],
+ [1,0], [0,2]);
/**
* @param name Name of the test
* @param keys An array of keys or a string with a single key to simulate.
@@ -193,27 +301,35 @@ testMotion('l', 'l', makeCursor(0, 1));
testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end);
testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end);
+testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument);
testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end);
testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4));
+testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4));
testMotion('w', 'w', word1.start);
+testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2));
+testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51));
testMotion('w_repeat', ['2', 'w'], word2.start);
testMotion('w_wrap', ['w'], word3.start, word2.start);
testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument);
+testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0));
testMotion('W', 'W', bigWord1.start);
testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start);
testMotion('e', 'e', word1.end);
testMotion('e_repeat', ['2', 'e'], word2.end);
testMotion('e_wrap', 'e', word3.end, word2.end);
testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument);
+testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0));
testMotion('b', 'b', word3.start, word3.end);
testMotion('b_repeat', ['2', 'b'], word2.start, word3.end);
testMotion('b_wrap', 'b', word2.start, word3.start);
testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0));
+testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument);
testMotion('ge', ['g', 'e'], word2.end, word3.end);
testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start);
testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start);
testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0),
makeCursor(0, 0));
+testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument);
testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart),
makeCursor(3, 1));
testMotion('gg_repeat', ['3', 'g', 'g'],
@@ -246,11 +362,34 @@ testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]
testMotion('%_parens', ['%'], parens1.end, parens1.start);
testMotion('%_squares', ['%'], squares1.end, squares1.start);
testMotion('%_braces', ['%'], curlys1.end, curlys1.start);
+testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start);
+testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start);
+testVim('%_seek_skip', function(cm, vim, helpers) {
+ cm.setCursor(0,0);
+ helpers.doKeys(['%']);
+ helpers.assertCursorAt(0,9);
+}, {value:'01234"("()'});
+testVim('%_skip_string', function(cm, vim, helpers) {
+ cm.setCursor(0,0);
+ helpers.doKeys(['%']);
+ helpers.assertCursorAt(0,4);
+ cm.setCursor(0,2);
+ helpers.doKeys(['%']);
+ helpers.assertCursorAt(0,0);
+}, {value:'(")")'});
+(')')
+testVim('%_skip_comment', function(cm, vim, helpers) {
+ cm.setCursor(0,0);
+ helpers.doKeys(['%']);
+ helpers.assertCursorAt(0,6);
+ cm.setCursor(0,3);
+ helpers.doKeys(['%']);
+ helpers.assertCursorAt(0,0);
+}, {value:'(/*)*/)'});
// Make sure that moving down after going to the end of a line always leaves you
// at the end of a line, but preserves the offset in other cases
testVim('Changing lines after Eol operation', function(cm, vim, helpers) {
- var startPos = { line: 0, ch: 0 };
- cm.setCursor(startPos);
+ cm.setCursor(0,0);
helpers.doKeys(['$']);
helpers.doKeys(['j']);
// After moving to Eol and then down, we should be at Eol of line 2
@@ -304,6 +443,34 @@ testVim('j_k_and_gj_gk', function(cm,vim,helpers){
helpers.doKeys('k');
helpers.assertCursorAt(0, 176);
},{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'});
+testVim('gj_gk', function(cm, vim, helpers) {
+ if (phantom) return;
+ cm.setSize(120);
+ // Test top of document edge case.
+ cm.setCursor(0, 4);
+ helpers.doKeys('g', 'j');
+ helpers.doKeys('10', 'g', 'k');
+ helpers.assertCursorAt(0, 4);
+
+ // Test moving down preserves column position.
+ helpers.doKeys('g', 'j');
+ var pos1 = cm.getCursor();
+ var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4};
+ helpers.doKeys('g', 'j');
+ helpers.assertCursorAt(expectedPos2);
+
+ // Move to the last character
+ cm.setCursor(0, 0);
+ // Move left to reset HSPos
+ helpers.doKeys('h');
+ // Test bottom of document edge case.
+ helpers.doKeys('100', 'g', 'j');
+ var endingPos = cm.getCursor();
+ is(endingPos != 0, 'gj should not be on wrapped line 0');
+ var topLeftCharCoords = cm.charCoords(makeCursor(0, 0));
+ var endingCharCoords = cm.charCoords(endingPos);
+ is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0');
+},{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' });
testVim('}', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('}');
@@ -339,14 +506,13 @@ testVim('dl', function(cm, vim, helpers) {
eqPos(curStart, cm.getCursor());
}, { value: ' word1 ' });
testVim('dl_eol', function(cm, vim, helpers) {
- var curStart = makeCursor(0, 6);
- cm.setCursor(curStart);
+ cm.setCursor(0, 6);
helpers.doKeys('d', 'l');
eq(' word1', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq(' ', register.text);
is(!register.linewise);
- helpers.assertCursorAt(0, 6);
+ helpers.assertCursorAt(0, 5);
}, { value: ' word1 ' });
testVim('dl_repeat', function(cm, vim, helpers) {
var curStart = makeCursor(0, 0);
@@ -431,39 +597,151 @@ testVim('dw_word', function(cm, vim, helpers) {
testVim('dw_only_word', function(cm, vim, helpers) {
// Test that if there is only 1 word left, dw deletes till the end of the
// line.
- var curStart = makeCursor(0, 1);
- cm.setCursor(curStart);
+ cm.setCursor(0, 1);
helpers.doKeys('d', 'w');
eq(' ', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('word1 ', register.text);
is(!register.linewise);
- eqPos(curStart, cm.getCursor());
+ helpers.assertCursorAt(0, 0);
}, { value: ' word1 ' });
testVim('dw_eol', function(cm, vim, helpers) {
// Assert that dw does not delete the newline if last word to delete is at end
// of line.
- var curStart = makeCursor(0, 1);
- cm.setCursor(curStart);
+ cm.setCursor(0, 1);
helpers.doKeys('d', 'w');
eq(' \nword2', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('word1', register.text);
is(!register.linewise);
- eqPos(curStart, cm.getCursor());
+ helpers.assertCursorAt(0, 0);
}, { value: ' word1\nword2' });
+testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
+ // Assert that dw does not delete the newline if last word to delete is at end
+ // of line and it is followed by multiple newlines.
+ cm.setCursor(0, 1);
+ helpers.doKeys('d', 'w');
+ eq(' \n\nword2', cm.getValue());
+ var register = helpers.getRegisterController().getRegister();
+ eq('word1', register.text);
+ is(!register.linewise);
+ helpers.assertCursorAt(0, 0);
+}, { value: ' word1\n\nword2' });
+testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq(' \nword', cm.getValue());
+}, { value: '\n \nword' });
+testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq('word', cm.getValue());
+}, { value: '\nword' });
+testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq('\n', cm.getValue());
+}, { value: '\n\n' });
+testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq('\n \n', cm.getValue());
+}, { value: ' \n \n' });
+testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq('\n\n', cm.getValue());
+}, { value: ' \n\n' });
+testVim('dw_word_whitespace_word', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'w');
+ eq('\n \nword2', cm.getValue());
+}, { value: 'word1\n \nword2'})
+testVim('dw_end_of_document', function(cm, vim, helpers) {
+ cm.setCursor(1, 2);
+ helpers.doKeys('d', 'w');
+ eq('\nab', cm.getValue());
+}, { value: '\nabc' });
testVim('dw_repeat', function(cm, vim, helpers) {
// Assert that dw does delete newline if it should go to the next line, and
// that repeat works properly.
- var curStart = makeCursor(0, 1);
- cm.setCursor(curStart);
+ cm.setCursor(0, 1);
helpers.doKeys('d', '2', 'w');
eq(' ', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('word1\nword2', register.text);
is(!register.linewise);
- eqPos(curStart, cm.getCursor());
+ helpers.assertCursorAt(0, 0);
}, { value: ' word1\nword2' });
+testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'e');
+ eq('\n\n', cm.getValue());
+}, { value: 'word\n\n' });
+testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(0, 3);
+ helpers.doKeys('d', 'e');
+ eq('wor', cm.getValue());
+}, { value: 'word\n\n\n' });
+testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'e');
+ eq('', cm.getValue());
+}, { value: ' \n\n\n' });
+testVim('de_end_of_document', function(cm, vim, helpers) {
+ cm.setCursor(1, 2);
+ helpers.doKeys('d', 'e');
+ eq('\nab', cm.getValue());
+}, { value: '\nabc' });
+testVim('db_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(2, 0);
+ helpers.doKeys('d', 'b');
+ eq('\n\n', cm.getValue());
+}, { value: '\n\n\n' });
+testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(2, 0);
+ helpers.doKeys('d', 'b');
+ eq('\nword', cm.getValue());
+}, { value: '\n\nword' });
+testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(2, 3);
+ helpers.doKeys('d', 'b');
+ eq('\n\nd', cm.getValue());
+}, { value: '\n\nword' });
+testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(2, 0);
+ helpers.doKeys('d', 'b');
+ eq('', cm.getValue());
+}, { value: '\n \n' });
+testVim('db_start_of_document', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'b');
+ eq('abc\n', cm.getValue());
+}, { value: 'abc\n' });
+testVim('dge_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(1, 0);
+ helpers.doKeys('d', 'g', 'e');
+ // Note: In real VIM the result should be '', but it's not quite consistent,
+ // since 2 newlines are deleted. But in the similar case of word\n\n, only
+ // 1 newline is deleted. We'll diverge from VIM's behavior since it's much
+ // easier this way.
+ eq('\n', cm.getValue());
+}, { value: '\n\n' });
+testVim('dge_word_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(1, 0);
+ helpers.doKeys('d', 'g', 'e');
+ eq('wor\n', cm.getValue());
+}, { value: 'word\n\n'});
+testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) {
+ cm.setCursor(2, 0);
+ helpers.doKeys('d', 'g', 'e');
+ eq('', cm.getValue());
+}, { value: '\n \n' });
+testVim('dge_start_of_document', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', 'g', 'e');
+ eq('bc\n', cm.getValue());
+}, { value: 'abc\n' });
testVim('d_inclusive', function(cm, vim, helpers) {
// Assert that when inclusive is set, the character the cursor is on gets
// deleted too.
@@ -534,6 +812,13 @@ testVim('dd_multiply_repeat', function(cm, vim, helpers) {
is(register.linewise);
helpers.assertCursorAt(0, lines[6].textStart);
});
+testVim('dd_lastline', function(cm, vim, helpers) {
+ cm.setCursor(cm.lineCount(), 0);
+ var expectedLineCount = cm.lineCount() - 1;
+ helpers.doKeys('d', 'd');
+ eq(expectedLineCount, cm.lineCount());
+ helpers.assertCursorAt(cm.lineCount() - 1, 0);
+});
// Yank commands should behave the exact same as d commands, expect that nothing
// gets deleted.
testVim('yw_repeat', function(cm, vim, helpers) {
@@ -564,6 +849,12 @@ testVim('yy_multiply_repeat', function(cm, vim, helpers) {
// Change commands behave like d commands except that it also enters insert
// mode. In addition, when the change is linewise, an additional newline is
// inserted so that insert mode starts on that line.
+testVim('cw', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', '2', 'w');
+ eq(' word3', cm.getValue());
+ helpers.assertCursorAt(0, 0);
+}, { value: 'word1 word2 word3'});
testVim('cw_repeat', function(cm, vim, helpers) {
// Assert that cw does delete newline if it should go to the next line, and
// that repeat works properly.
@@ -587,9 +878,14 @@ testVim('cc_multiply_repeat', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister();
eq(expectedBuffer, register.text);
is(register.linewise);
- helpers.assertCursorAt(0, lines[0].textStart);
eq('vim-insert', cm.getOption('keyMap'));
});
+testVim('cc_append', function(cm, vim, helpers) {
+ var expectedLineCount = cm.lineCount();
+ cm.setCursor(cm.lastLine(), 0);
+ helpers.doKeys('c', 'c');
+ eq(expectedLineCount, cm.lineCount());
+});
// Swapcase commands edit in place and do not modify registers.
testVim('g~w_repeat', function(cm, vim, helpers) {
// Assert that dw does delete newline if it should go to the next line, and
@@ -660,16 +956,57 @@ testVim('<<', function(cm, vim, helpers) {
helpers.assertCursorAt(0, 1);
}, { value: ' word1\n word2\nword3 ', indentUnit: 2 });
+// Edit tests
+function testEdit(name, before, pos, edit, after) {
+ return testVim(name, function(cm, vim, helpers) {
+ cm.setCursor(0, before.search(pos));
+ helpers.doKeys.apply(this, edit.split(''));
+ eq(after, cm.getValue());
+ }, {value: before});
+}
+
+// These Delete tests effectively cover word-wise Change, Visual & Yank.
+// Tabs are used as differentiated whitespace to catch edge cases.
+// Normal word:
+testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz');
+testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz');
+testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz');
+testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz');
+testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz');
+testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz');
+testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz');
+testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz');
+testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz');
+testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz');
+testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t');
+testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo');
+testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.');
+testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.');
+// Big word:
+testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz');
+testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz');
+testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz');
+testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz');
+testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz');
+testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz');
+testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz');
+testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz');
+testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz');
+testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz');
+testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t');
+testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo');
+testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t');
+testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
+
// Operator-motion tests
testVim('D', function(cm, vim, helpers) {
- var curStart = makeCursor(0, 3);
- cm.setCursor(curStart);
+ cm.setCursor(0, 3);
helpers.doKeys('D');
eq(' wo\nword2\n word3', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('rd1', register.text);
is(!register.linewise);
- helpers.assertCursorAt(0, 3);
+ helpers.assertCursorAt(0, 2);
}, { value: ' word1\nword2\n word3' });
testVim('C', function(cm, vim, helpers) {
var curStart = makeCursor(0, 3);
@@ -679,7 +1016,7 @@ testVim('C', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister();
eq('rd1', register.text);
is(!register.linewise);
- helpers.assertCursorAt(0, 3);
+ eqPos(curStart, cm.getCursor());
eq('vim-insert', cm.getOption('keyMap'));
}, { value: ' word1\nword2\n word3' });
testVim('Y', function(cm, vim, helpers) {
@@ -692,8 +1029,42 @@ testVim('Y', function(cm, vim, helpers) {
is(!register.linewise);
helpers.assertCursorAt(0, 3);
}, { value: ' word1\nword2\n word3' });
+testVim('~', function(cm, vim, helpers) {
+ helpers.doKeys('3', '~');
+ eq('ABCdefg', cm.getValue());
+ helpers.assertCursorAt(0, 3);
+}, { value: 'abcdefg' });
// Action tests
+testVim('ctrl-a', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('');
+ eq('-9', cm.getValue());
+ helpers.assertCursorAt(0, 1);
+ helpers.doKeys('2','');
+ eq('-7', cm.getValue());
+}, {value: '-10'});
+testVim('ctrl-x', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('');
+ eq('-1', cm.getValue());
+ helpers.assertCursorAt(0, 1);
+ helpers.doKeys('2','');
+ eq('-3', cm.getValue());
+}, {value: '0'});
+testVim('/ search forward', function(cm, vim, helpers) {
+ forEach(['', ''], function(key) {
+ cm.setCursor(0, 0);
+ helpers.doKeys(key);
+ helpers.assertCursorAt(0, 5);
+ helpers.doKeys('l');
+ helpers.doKeys(key);
+ helpers.assertCursorAt(0, 10);
+ cm.setCursor(0, 11);
+ helpers.doKeys(key);
+ helpers.assertCursorAt(0, 11);
+ });
+}, {value: '__jmp1 jmp2 jmp'});
testVim('a', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('a');
@@ -712,8 +1083,22 @@ testVim('i', function(cm, vim, helpers) {
helpers.assertCursorAt(0, 1);
eq('vim-insert', cm.getOption('keyMap'));
});
+testVim('i_repeat', function(cm, vim, helpers) {
+ helpers.doKeys('3', 'i');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ eq('testtesttest', cm.getValue());
+ helpers.assertCursorAt(0, 11);
+}, { value: '' });
+testVim('i_repeat_delete', function(cm, vim, helpers) {
+ cm.setCursor(0, 4);
+ helpers.doKeys('2', 'i');
+ cm.replaceRange('z', cm.getCursor());
+ helpers.doInsertModeKeys('Backspace', 'Backspace', 'Esc');
+ eq('abe', cm.getValue());
+ helpers.assertCursorAt(0, 1);
+}, { value: 'abcde' });
testVim('A', function(cm, vim, helpers) {
- cm.setCursor(0, 0);
helpers.doKeys('A');
helpers.assertCursorAt(0, lines[0].length);
eq('vim-insert', cm.getOption('keyMap'));
@@ -724,6 +1109,14 @@ testVim('I', function(cm, vim, helpers) {
helpers.assertCursorAt(0, lines[0].textStart);
eq('vim-insert', cm.getOption('keyMap'));
});
+testVim('I_repeat', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('3', 'I');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ eq('testtesttestblah', cm.getValue());
+ helpers.assertCursorAt(0, 11);
+}, { value: 'blah' });
testVim('o', function(cm, vim, helpers) {
cm.setCursor(0, 4);
helpers.doKeys('o');
@@ -731,6 +1124,14 @@ testVim('o', function(cm, vim, helpers) {
helpers.assertCursorAt(1, 0);
eq('vim-insert', cm.getOption('keyMap'));
}, { value: 'word1\nword2' });
+testVim('o_repeat', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('3', 'o');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ eq('\ntest\ntest\ntest', cm.getValue());
+ helpers.assertCursorAt(3, 3);
+}, { value: '' });
testVim('O', function(cm, vim, helpers) {
cm.setCursor(0, 4);
helpers.doKeys('O');
@@ -780,6 +1181,13 @@ testVim('p_line', function(cm, vim, helpers) {
eq('___\n a\nd\n a\nd', cm.getValue());
helpers.assertCursorAt(1, 2);
}, { value: '___' });
+testVim('p_lastline', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.getRegisterController().pushText('"', 'yank', ' a\nd', true);
+ helpers.doKeys('2', 'p');
+ eq('___\n a\nd\n a\nd', cm.getValue());
+ helpers.assertCursorAt(1, 2);
+}, { value: '___' });
testVim('P', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
@@ -800,9 +1208,16 @@ testVim('r', function(cm, vim, helpers) {
eq('wuuuet\nanother', cm.getValue(),'3r failed');
helpers.assertCursorAt(0, 3);
cm.setCursor(0, 4);
- helpers.doKeys('v', 'j', 'h', 'r', 'Space');
+ helpers.doKeys('v', 'j', 'h', 'r', '');
eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed');
}, { value: 'wordet\nanother' });
+testVim('R', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('R');
+ helpers.assertCursorAt(0, 1);
+ eq('vim-replace', cm.getOption('keyMap'));
+ is(cm.state.overwrite, 'Setting overwrite state failed');
+});
testVim('mark', function(cm, vim, helpers) {
cm.setCursor(2, 2);
helpers.doKeys('m', 't');
@@ -1073,6 +1488,38 @@ testVim('visual_join', function(cm, vim, helpers) {
helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
eq(' 1 2 3\n 4\n 5', cm.getValue());
}, { value: ' 1\n 2\n 3\n 4\n 5' });
+testVim('visual_blank', function(cm, vim, helpers) {
+ helpers.doKeys('v', 'k');
+ eq(vim.visualMode, true);
+}, { value: '\n' });
+testVim('s_normal', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('s');
+ helpers.doInsertModeKeys('Esc');
+ helpers.assertCursorAt(0, 0);
+ eq('ac', cm.getValue());
+}, { value: 'abc'});
+testVim('s_visual', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('v', 's');
+ helpers.doInsertModeKeys('Esc');
+ helpers.assertCursorAt(0, 0);
+ eq('ac', cm.getValue());
+}, { value: 'abc'});
+testVim('S_normal', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('j', 'S');
+ helpers.doInsertModeKeys('Esc');
+ helpers.assertCursorAt(1, 0);
+ eq('aa\n\ncc', cm.getValue());
+}, { value: 'aa\nbb\ncc'});
+testVim('S_visual', function(cm, vim, helpers) {
+ cm.setCursor(0, 1);
+ helpers.doKeys('v', 'j', 'S');
+ helpers.doInsertModeKeys('Esc');
+ helpers.assertCursorAt(0, 0);
+ eq('\ncc', cm.getValue());
+}, { value: 'aa\nbb\ncc'});
testVim('/ and n/N', function(cm, vim, helpers) {
cm.openDialog = helpers.fakeOpenDialog('match');
helpers.doKeys('/');
@@ -1091,6 +1538,76 @@ testVim('/_case', function(cm, vim, helpers) {
helpers.doKeys('/');
helpers.assertCursorAt(1, 6);
}, { value: 'match nope match \n nope Match' });
+testVim('/_nongreedy', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('aa');
+ helpers.doKeys('/');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa \n a aa'});
+testVim('?_nongreedy', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('aa');
+ helpers.doKeys('?');
+ helpers.assertCursorAt(1, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa \n a aa'});
+testVim('/_greedy', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('a+');
+ helpers.doKeys('/');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 1);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa \n a aa'});
+testVim('?_greedy', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('a+');
+ helpers.doKeys('?');
+ helpers.assertCursorAt(1, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 1);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa \n a aa'});
+testVim('/_greedy_0_or_more', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('a*');
+ helpers.doKeys('/');
+ helpers.assertCursorAt(0, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 5);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 0);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 1);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa\n aa'});
+testVim('?_greedy_0_or_more', function(cm, vim, helpers) {
+ cm.openDialog = helpers.fakeOpenDialog('a*');
+ helpers.doKeys('?');
+ helpers.assertCursorAt(1, 1);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(1, 0);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 5);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 4);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 3);
+ helpers.doKeys('n');
+ helpers.assertCursorAt(0, 0);
+}, { value: 'aaa aa\n aa'});
testVim('? and n/N', function(cm, vim, helpers) {
cm.openDialog = helpers.fakeOpenDialog('match');
helpers.doKeys('?');
@@ -1156,6 +1673,479 @@ testVim('._repeat', function(cm, vim, helpers) {
helpers.doKeys('3', '.');
eq('6', cm.getValue());
}, { value: '1 2 3 4 5 6'});
+testVim('._insert', function(cm, vim, helpers) {
+ helpers.doKeys('i');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ helpers.doKeys('.');
+ eq('testestt', cm.getValue());
+ helpers.assertCursorAt(0, 6);
+}, { value: ''});
+testVim('._insert_repeat', function(cm, vim, helpers) {
+ helpers.doKeys('i');
+ cm.replaceRange('test', cm.getCursor());
+ cm.setCursor(0, 4);
+ helpers.doInsertModeKeys('Esc');
+ helpers.doKeys('2', '.');
+ eq('testesttestt', cm.getValue());
+ helpers.assertCursorAt(0, 10);
+}, { value: ''});
+testVim('._repeat_insert', function(cm, vim, helpers) {
+ helpers.doKeys('3', 'i');
+ cm.replaceRange('te', cm.getCursor());
+ cm.setCursor(0, 2);
+ helpers.doInsertModeKeys('Esc');
+ helpers.doKeys('.');
+ eq('tetettetetee', cm.getValue());
+ helpers.assertCursorAt(0, 10);
+}, { value: ''});
+testVim('._insert_o', function(cm, vim, helpers) {
+ helpers.doKeys('o');
+ cm.replaceRange('z', cm.getCursor());
+ cm.setCursor(1, 1);
+ helpers.doInsertModeKeys('Esc');
+ helpers.doKeys('.');
+ eq('\nz\nz', cm.getValue());
+ helpers.assertCursorAt(2, 0);
+}, { value: ''});
+testVim('._insert_o_repeat', function(cm, vim, helpers) {
+ helpers.doKeys('o');
+ cm.replaceRange('z', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ cm.setCursor(1, 0);
+ helpers.doKeys('2', '.');
+ eq('\nz\nz\nz', cm.getValue());
+ helpers.assertCursorAt(3, 0);
+}, { value: ''});
+testVim('._insert_o_indent', function(cm, vim, helpers) {
+ helpers.doKeys('o');
+ cm.replaceRange('z', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ cm.setCursor(1, 2);
+ helpers.doKeys('.');
+ eq('{\n z\n z', cm.getValue());
+ helpers.assertCursorAt(2, 2);
+}, { value: '{'});
+testVim('._insert_cw', function(cm, vim, helpers) {
+ helpers.doKeys('c', 'w');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ cm.setCursor(0, 3);
+ helpers.doKeys('2', 'l');
+ helpers.doKeys('.');
+ eq('test test word3', cm.getValue());
+ helpers.assertCursorAt(0, 8);
+}, { value: 'word1 word2 word3' });
+testVim('._insert_cw_repeat', function(cm, vim, helpers) {
+ // For some reason, repeat cw in desktop VIM will does not repeat insert mode
+ // changes. Will conform to that behavior.
+ helpers.doKeys('c', 'w');
+ cm.replaceRange('test', cm.getCursor());
+ helpers.doInsertModeKeys('Esc');
+ cm.setCursor(0, 4);
+ helpers.doKeys('l');
+ helpers.doKeys('2', '.');
+ eq('test test', cm.getValue());
+ helpers.assertCursorAt(0, 8);
+}, { value: 'word1 word2 word3' });
+testVim('._delete', function(cm, vim, helpers) {
+ cm.setCursor(0, 5);
+ helpers.doKeys('i');
+ helpers.doInsertModeKeys('Backspace', 'Esc');
+ helpers.doKeys('.');
+ eq('zace', cm.getValue());
+ helpers.assertCursorAt(0, 1);
+}, { value: 'zabcde'});
+testVim('._delete_repeat', function(cm, vim, helpers) {
+ cm.setCursor(0, 6);
+ helpers.doKeys('i');
+ helpers.doInsertModeKeys('Backspace', 'Esc');
+ helpers.doKeys('2', '.');
+ eq('zzce', cm.getValue());
+ helpers.assertCursorAt(0, 1);
+}, { value: 'zzabcde'});
+testVim('f;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('f', 'x');
+ helpers.doKeys(';');
+ helpers.doKeys('2', ';');
+ eq(9, cm.getCursor().ch);
+}, { value: '01x3xx678x'});
+testVim('F;', function(cm, vim, helpers) {
+ cm.setCursor(0, 8);
+ helpers.doKeys('F', 'x');
+ helpers.doKeys(';');
+ helpers.doKeys('2', ';');
+ eq(2, cm.getCursor().ch);
+}, { value: '01x3xx6x8x'});
+testVim('t;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('t', 'x');
+ helpers.doKeys(';');
+ helpers.doKeys('2', ';');
+ eq(8, cm.getCursor().ch);
+}, { value: '01x3xx678x'});
+testVim('T;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('T', 'x');
+ helpers.doKeys(';');
+ helpers.doKeys('2', ';');
+ eq(2, cm.getCursor().ch);
+}, { value: '0xx3xx678x'});
+testVim('f,', function(cm, vim, helpers) {
+ cm.setCursor(0, 6);
+ helpers.doKeys('f', 'x');
+ helpers.doKeys(',');
+ helpers.doKeys('2', ',');
+ eq(2, cm.getCursor().ch);
+}, { value: '01x3xx678x'});
+testVim('F,', function(cm, vim, helpers) {
+ cm.setCursor(0, 3);
+ helpers.doKeys('F', 'x');
+ helpers.doKeys(',');
+ helpers.doKeys('2', ',');
+ eq(9, cm.getCursor().ch);
+}, { value: '01x3xx678x'});
+testVim('t,', function(cm, vim, helpers) {
+ cm.setCursor(0, 6);
+ helpers.doKeys('t', 'x');
+ helpers.doKeys(',');
+ helpers.doKeys('2', ',');
+ eq(3, cm.getCursor().ch);
+}, { value: '01x3xx678x'});
+testVim('T,', function(cm, vim, helpers) {
+ cm.setCursor(0, 4);
+ helpers.doKeys('T', 'x');
+ helpers.doKeys(',');
+ helpers.doKeys('2', ',');
+ eq(8, cm.getCursor().ch);
+}, { value: '01x3xx67xx'});
+testVim('fd,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('f', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', ';');
+ eq('56789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('d', ',');
+ eq('01239', cm.getValue());
+}, { value: '0123456789'});
+testVim('Fd,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('F', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('d', ';');
+ eq('01239', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', ',');
+ eq('56789', cm.getValue());
+}, { value: '0123456789'});
+testVim('td,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('t', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', ';');
+ eq('456789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('d', ',');
+ eq('012349', cm.getValue());
+}, { value: '0123456789'});
+testVim('Td,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('T', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('d', ';');
+ eq('012349', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('d', ',');
+ eq('456789', cm.getValue());
+}, { value: '0123456789'});
+testVim('fc,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('f', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', ';', 'Esc');
+ eq('56789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('c', ',');
+ eq('01239', cm.getValue());
+}, { value: '0123456789'});
+testVim('Fc,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('F', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('c', ';', 'Esc');
+ eq('01239', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', ',');
+ eq('56789', cm.getValue());
+}, { value: '0123456789'});
+testVim('tc,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('t', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', ';', 'Esc');
+ eq('456789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('c', ',');
+ eq('012349', cm.getValue());
+}, { value: '0123456789'});
+testVim('Tc,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('T', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('c', ';', 'Esc');
+ eq('012349', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', ',');
+ eq('456789', cm.getValue());
+}, { value: '0123456789'});
+testVim('fy,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('f', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('y', ';', 'P');
+ eq('012340123456789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('y', ',', 'P');
+ eq('012345678456789', cm.getValue());
+}, { value: '0123456789'});
+testVim('Fy,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('F', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('y', ';', 'p');
+ eq('012345678945678', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('y', ',', 'P');
+ eq('012340123456789', cm.getValue());
+}, { value: '0123456789'});
+testVim('ty,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('t', '4');
+ cm.setCursor(0, 0);
+ helpers.doKeys('y', ';', 'P');
+ eq('01230123456789', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 9);
+ helpers.doKeys('y', ',', 'p');
+ eq('01234567895678', cm.getValue());
+}, { value: '0123456789'});
+testVim('Ty,;', function(cm, vim, helpers) {
+ cm.setCursor(0, 9);
+ helpers.doKeys('T', '4');
+ cm.setCursor(0, 9);
+ helpers.doKeys('y', ';', 'p');
+ eq('01234567895678', cm.getValue());
+ helpers.doKeys('u');
+ cm.setCursor(0, 0);
+ helpers.doKeys('y', ',', 'P');
+ eq('01230123456789', cm.getValue());
+}, { value: '0123456789'});
+testVim('HML', function(cm, vim, helpers) {
+ var lines = 35;
+ var textHeight = cm.defaultTextHeight();
+ cm.setSize(600, lines*textHeight);
+ cm.setCursor(120, 0);
+ helpers.doKeys('H');
+ helpers.assertCursorAt(86, 2);
+ helpers.doKeys('L');
+ helpers.assertCursorAt(120, 4);
+ helpers.doKeys('M');
+ helpers.assertCursorAt(103,4);
+}, { value: (function(){
+ var lines = new Array(100);
+ var upper = ' xx\n';
+ var lower = ' xx\n';
+ upper = lines.join(upper);
+ lower = lines.join(lower);
+ return upper + lower;
+})()});
+
+var zVals = ['zb','zz','zt','z-','z.','z'].map(function(e, idx){
+ var lineNum = 250;
+ var lines = 35;
+ testVim(e, function(cm, vim, helpers) {
+ var k1 = e[0];
+ var k2 = e.substring(1);
+ var textHeight = cm.defaultTextHeight();
+ cm.setSize(600, lines*textHeight);
+ cm.setCursor(lineNum, 0);
+ helpers.doKeys(k1, k2);
+ zVals[idx] = cm.getScrollInfo().top;
+ }, { value: (function(){
+ return new Array(500).join('\n');
+ })()});
+});
+testVim('zb', function(cm, vim, helpers){
+ eq(zVals[2], zVals[5]);
+});
+
+var scrollMotionSandbox =
+ '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
+ '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
+ '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
+ '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n';
+testVim('scrollMotion', function(cm, vim, helpers){
+ var prevCursor, prevScrollInfo;
+ cm.setCursor(0, 0);
+ // ctrl-y at the top of the file should have no effect.
+ helpers.doKeys('');
+ eq(0, cm.getCursor().line);
+ prevScrollInfo = cm.getScrollInfo();
+ helpers.doKeys('');
+ eq(1, cm.getCursor().line);
+ eq(true, prevScrollInfo.top < cm.getScrollInfo().top);
+ // Jump to the end of the sandbox.
+ cm.setCursor(1000, 0);
+ prevCursor = cm.getCursor();
+ // ctrl-e at the bottom of the file should have no effect.
+ helpers.doKeys('');
+ eq(prevCursor.line, cm.getCursor().line);
+ prevScrollInfo = cm.getScrollInfo();
+ helpers.doKeys('');
+ eq(prevCursor.line - 1, cm.getCursor().line);
+ eq(true, prevScrollInfo.top > cm.getScrollInfo().top);
+}, { value: scrollMotionSandbox});
+
+var squareBracketMotionSandbox = ''+
+ '({\n'+//0
+ ' ({\n'+//11
+ ' /*comment {\n'+//2
+ ' */(\n'+//3
+ '#else \n'+//4
+ ' /* )\n'+//5
+ '#if }\n'+//6
+ ' )}*/\n'+//7
+ ')}\n'+//8
+ '{}\n'+//9
+ '#else {{\n'+//10
+ '{}\n'+//11
+ '}\n'+//12
+ '{\n'+//13
+ '#endif\n'+//14
+ '}\n'+//15
+ '}\n'+//16
+ '#else';//17
+testVim('[[, ]]', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys(']', ']');
+ helpers.assertCursorAt(9,0);
+ helpers.doKeys('2', ']', ']');
+ helpers.assertCursorAt(13,0);
+ helpers.doKeys(']', ']');
+ helpers.assertCursorAt(17,0);
+ helpers.doKeys('[', '[');
+ helpers.assertCursorAt(13,0);
+ helpers.doKeys('2', '[', '[');
+ helpers.assertCursorAt(9,0);
+ helpers.doKeys('[', '[');
+ helpers.assertCursorAt(0,0);
+}, { value: squareBracketMotionSandbox});
+testVim('[], ][', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys(']', '[');
+ helpers.assertCursorAt(12,0);
+ helpers.doKeys('2', ']', '[');
+ helpers.assertCursorAt(16,0);
+ helpers.doKeys(']', '[');
+ helpers.assertCursorAt(17,0);
+ helpers.doKeys('[', ']');
+ helpers.assertCursorAt(16,0);
+ helpers.doKeys('2', '[', ']');
+ helpers.assertCursorAt(12,0);
+ helpers.doKeys('[', ']');
+ helpers.assertCursorAt(0,0);
+}, { value: squareBracketMotionSandbox});
+testVim('[{, ]}', function(cm, vim, helpers) {
+ cm.setCursor(4, 10);
+ helpers.doKeys('[', '{');
+ helpers.assertCursorAt(2,12);
+ helpers.doKeys('2', '[', '{');
+ helpers.assertCursorAt(0,1);
+ cm.setCursor(4, 10);
+ helpers.doKeys(']', '}');
+ helpers.assertCursorAt(6,11);
+ helpers.doKeys('2', ']', '}');
+ helpers.assertCursorAt(8,1);
+ cm.setCursor(0,1);
+ helpers.doKeys(']', '}');
+ helpers.assertCursorAt(8,1);
+ helpers.doKeys('[', '{');
+ helpers.assertCursorAt(0,1);
+}, { value: squareBracketMotionSandbox});
+testVim('[(, ])', function(cm, vim, helpers) {
+ cm.setCursor(4, 10);
+ helpers.doKeys('[', '(');
+ helpers.assertCursorAt(3,14);
+ helpers.doKeys('2', '[', '(');
+ helpers.assertCursorAt(0,0);
+ cm.setCursor(4, 10);
+ helpers.doKeys(']', ')');
+ helpers.assertCursorAt(5,11);
+ helpers.doKeys('2', ']', ')');
+ helpers.assertCursorAt(8,0);
+ helpers.doKeys('[', '(');
+ helpers.assertCursorAt(0,0);
+ helpers.doKeys(']', ')');
+ helpers.assertCursorAt(8,0);
+}, { value: squareBracketMotionSandbox});
+testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) {
+ forEach(['*', '/'], function(key){
+ cm.setCursor(7, 0);
+ helpers.doKeys('2', '[', key);
+ helpers.assertCursorAt(2,2);
+ helpers.doKeys('2', ']', key);
+ helpers.assertCursorAt(7,5);
+ });
+}, { value: squareBracketMotionSandbox});
+testVim('[#, ]#', function(cm, vim, helpers) {
+ cm.setCursor(10, 3);
+ helpers.doKeys('2', '[', '#');
+ helpers.assertCursorAt(4,0);
+ helpers.doKeys('5', ']', '#');
+ helpers.assertCursorAt(17,0);
+ cm.setCursor(10, 3);
+ helpers.doKeys(']', '#');
+ helpers.assertCursorAt(14,0);
+}, { value: squareBracketMotionSandbox});
+testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) {
+ cm.setCursor(11, 0);
+ helpers.doKeys('[', 'm');
+ helpers.assertCursorAt(10,7);
+ helpers.doKeys('4', '[', 'm');
+ helpers.assertCursorAt(1,3);
+ helpers.doKeys('5', ']', 'm');
+ helpers.assertCursorAt(11,0);
+ helpers.doKeys('[', 'M');
+ helpers.assertCursorAt(9,1);
+ helpers.doKeys('3', ']', 'M');
+ helpers.assertCursorAt(15,0);
+ helpers.doKeys('5', '[', 'M');
+ helpers.assertCursorAt(7,3);
+}, { value: squareBracketMotionSandbox});
// Ex mode tests
testVim('ex_go_to_line', function(cm, vim, helpers) {
@@ -1182,6 +2172,59 @@ testVim('ex_write', function(cm, vim, helpers) {
}
CodeMirror.commands.save = tmp;
});
+testVim('ex_sort', function(cm, vim, helpers) {
+ helpers.doEx('sort');
+ eq('Z\na\nb\nc\nd', cm.getValue());
+}, { value: 'b\nZ\nd\nc\na'});
+testVim('ex_sort_reverse', function(cm, vim, helpers) {
+ helpers.doEx('sort!');
+ eq('d\nc\nb\na', cm.getValue());
+}, { value: 'b\nd\nc\na'});
+testVim('ex_sort_range', function(cm, vim, helpers) {
+ helpers.doEx('2,3sort');
+ eq('b\nc\nd\na', cm.getValue());
+}, { value: 'b\nd\nc\na'});
+testVim('ex_sort_oneline', function(cm, vim, helpers) {
+ helpers.doEx('2sort');
+ // Expect no change.
+ eq('b\nd\nc\na', cm.getValue());
+}, { value: 'b\nd\nc\na'});
+testVim('ex_sort_ignoreCase', function(cm, vim, helpers) {
+ helpers.doEx('sort i');
+ eq('a\nb\nc\nd\nZ', cm.getValue());
+}, { value: 'b\nZ\nd\nc\na'});
+testVim('ex_sort_unique', function(cm, vim, helpers) {
+ helpers.doEx('sort u');
+ eq('Z\na\nb\nc\nd', cm.getValue());
+}, { value: 'b\nZ\na\na\nd\na\nc\na'});
+testVim('ex_sort_decimal', function(cm, vim, helpers) {
+ helpers.doEx('sort d');
+ eq('d3\n s5\n6\n.9', cm.getValue());
+}, { value: '6\nd3\n s5\n.9'});
+testVim('ex_sort_decimal_negative', function(cm, vim, helpers) {
+ helpers.doEx('sort d');
+ eq('z-9\nd3\n s5\n6\n.9', cm.getValue());
+}, { value: '6\nd3\n s5\n.9\nz-9'});
+testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) {
+ helpers.doEx('sort! d');
+ eq('.9\n6\n s5\nd3', cm.getValue());
+}, { value: '6\nd3\n s5\n.9'});
+testVim('ex_sort_hex', function(cm, vim, helpers) {
+ helpers.doEx('sort x');
+ eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue());
+}, { value: '6\nd3\n s5\n&0xB\n.9'});
+testVim('ex_sort_octal', function(cm, vim, helpers) {
+ helpers.doEx('sort o');
+ eq('.8\n.9\nd3\n s5\n6', cm.getValue());
+}, { value: '6\nd3\n s5\n.9\n.8'});
+testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) {
+ helpers.doEx('sort d');
+ eq('y\nz\nc1\nb2\na3', cm.getValue());
+}, { value: 'a3\nz\nc1\ny\nb2'});
+testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) {
+ helpers.doEx('sort! d');
+ eq('a3\nb2\nc1\nz\ny', cm.getValue());
+}, { value: 'a3\nz\nc1\ny\nb2'});
testVim('ex_substitute_same_line', function(cm, vim, helpers) {
cm.setCursor(1, 0);
helpers.doEx('s/one/two');
@@ -1227,6 +2270,78 @@ testVim('ex_substitute_count_with_range', function(cm, vim, helpers) {
helpers.doEx('1,3s/\\d/0/ 3');
eq('1\n2\n0\n0', cm.getValue());
}, { value: '1\n2\n3\n4' });
+function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) {
+ testVim(name, function(cm, vim, helpers) {
+ var savedOpenDialog = cm.openDialog;
+ var savedKeyName = CodeMirror.keyName;
+ var onKeyDown;
+ var recordedCallback;
+ var closed = true; // Start out closed, set false on second openDialog.
+ function close() {
+ closed = true;
+ }
+ // First openDialog should save callback.
+ cm.openDialog = function(template, callback, options) {
+ recordedCallback = callback;
+ }
+ // Do first openDialog.
+ helpers.doKeys(':');
+ // Second openDialog should save keyDown handler.
+ cm.openDialog = function(template, callback, options) {
+ onKeyDown = options.onKeyDown;
+ closed = false;
+ };
+ // Return the command to Vim and trigger second openDialog.
+ recordedCallback(command);
+ // The event should really use keyCode, but here just mock it out and use
+ // key and replace keyName to just return key.
+ CodeMirror.keyName = function (e) { return e.key; }
+ keys = keys.toUpperCase();
+ for (var i = 0; i < keys.length; i++) {
+ is(!closed);
+ onKeyDown({ key: keys.charAt(i) }, '', close);
+ }
+ try {
+ eq(expectedValue, cm.getValue());
+ helpers.assertCursorAt(finalPos);
+ is(closed);
+ } catch(e) {
+ throw e
+ } finally {
+ // Restore overriden functions.
+ CodeMirror.keyName = savedKeyName;
+ cm.openDialog = savedOpenDialog;
+ }
+ }, { value: initialValue });
+};
+testSubstituteConfirm('ex_substitute_confirm_emptydoc',
+ '%s/x/b/c', '', '', '', makeCursor(0, 0));
+testSubstituteConfirm('ex_substitute_confirm_nomatch',
+ '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
+testSubstituteConfirm('ex_substitute_confirm_accept',
+ '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
+testSubstituteConfirm('ex_substitute_confirm_random_keys',
+ '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
+testSubstituteConfirm('ex_substitute_confirm_some',
+ '%s/a/b/c', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1));
+testSubstituteConfirm('ex_substitute_confirm_all',
+ '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1));
+testSubstituteConfirm('ex_substitute_confirm_accept_then_all',
+ '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1));
+testSubstituteConfirm('ex_substitute_confirm_quit',
+ '%s/a/b/c', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3));
+testSubstituteConfirm('ex_substitute_confirm_last',
+ '%s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
+testSubstituteConfirm('ex_substitute_confirm_oneline',
+ '1s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
+testSubstituteConfirm('ex_substitute_confirm_range_accept',
+ '1,2s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0));
+testSubstituteConfirm('ex_substitute_confirm_range_some',
+ '1,3s/a/b/c', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0));
+testSubstituteConfirm('ex_substitute_confirm_range_all',
+ '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0));
+testSubstituteConfirm('ex_substitute_confirm_range_last',
+ '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0));
//:noh should clear highlighting of search-results but allow to resume search through n
testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) {
cm.openDialog = helpers.fakeOpenDialog('match');
@@ -1286,6 +2401,26 @@ testVim('ex_map_key2ex', function(cm, vim, helpers) {
eq(written, true);
eq(actualCm, cm);
});
+testVim('ex_map_key2key_visual_api', function(cm, vim, helpers) {
+ CodeMirror.Vim.map('b', ':w', 'visual');
+ var tmp = CodeMirror.commands.save;
+ var written = false;
+ var actualCm;
+ CodeMirror.commands.save = function(cm) {
+ written = true;
+ actualCm = cm;
+ };
+ // Mapping should not work in normal mode.
+ helpers.doKeys('b');
+ eq(written, false);
+ // Mapping should work in visual mode.
+ helpers.doKeys('v', 'b');
+ eq(written, true);
+ eq(actualCm, cm);
+
+ CodeMirror.commands.save = tmp;
+});
+
// Testing registration of functions as ex-commands and mapping to -keys
testVim('ex_api_test', function(cm, vim, helpers) {
var res=false;
@@ -1297,7 +2432,7 @@ testVim('ex_api_test', function(cm, vim, helpers) {
helpers.doEx(':ext to');
eq(val,'to','Defining ex-command failed');
CodeMirror.Vim.map('',':ext');
- helpers.doKeys('Ctrl-Enter','Space');
+ helpers.doKeys('','');
is(res,'Mapping to key failed');
});
// For now, this test needs to be last because it messes up : for future tests.
diff --git a/gulliver/js/codemirror/theme/3024-day.css b/gulliver/js/codemirror/theme/3024-day.css
new file mode 100644
index 000000000..cbb9a4fa4
--- /dev/null
+++ b/gulliver/js/codemirror/theme/3024-day.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: 3024 day
+ Author: Jan T. Sott (http://github.com/idleberg)
+
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;}
+.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;}
+.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;}
+.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;}
+.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;}
+
+.cm-s-3024-day span.cm-comment {color: #cdab53;}
+.cm-s-3024-day span.cm-atom {color: #a16a94;}
+.cm-s-3024-day span.cm-number {color: #a16a94;}
+
+.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;}
+.cm-s-3024-day span.cm-keyword {color: #db2d20;}
+.cm-s-3024-day span.cm-string {color: #fded02;}
+
+.cm-s-3024-day span.cm-variable {color: #01a252;}
+.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;}
+.cm-s-3024-day span.cm-def {color: #e8bbd0;}
+.cm-s-3024-day span.cm-bracket {color: #3a3432;}
+.cm-s-3024-day span.cm-tag {color: #db2d20;}
+.cm-s-3024-day span.cm-link {color: #a16a94;}
+.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;}
+
+.cm-s-3024-day .CodeMirror-activeline-background {background: #e8f2ff !important;}
+.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/3024-night.css b/gulliver/js/codemirror/theme/3024-night.css
new file mode 100644
index 000000000..2c62e221b
--- /dev/null
+++ b/gulliver/js/codemirror/theme/3024-night.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: 3024 night
+ Author: Jan T. Sott (http://github.com/idleberg)
+
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;}
+.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;}
+.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;}
+.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;}
+.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;}
+
+.cm-s-3024-night span.cm-comment {color: #cdab53;}
+.cm-s-3024-night span.cm-atom {color: #a16a94;}
+.cm-s-3024-night span.cm-number {color: #a16a94;}
+
+.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;}
+.cm-s-3024-night span.cm-keyword {color: #db2d20;}
+.cm-s-3024-night span.cm-string {color: #fded02;}
+
+.cm-s-3024-night span.cm-variable {color: #01a252;}
+.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;}
+.cm-s-3024-night span.cm-def {color: #e8bbd0;}
+.cm-s-3024-night span.cm-bracket {color: #d6d5d4;}
+.cm-s-3024-night span.cm-tag {color: #db2d20;}
+.cm-s-3024-night span.cm-link {color: #a16a94;}
+.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;}
+
+.cm-s-3024-night .CodeMirror-activeline-background {background: #2F2F2F !important;}
+.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/ambiance.css b/gulliver/js/codemirror/theme/ambiance.css
index 0185426f0..3a54b2a02 100644
--- a/gulliver/js/codemirror/theme/ambiance.css
+++ b/gulliver/js/codemirror/theme/ambiance.css
@@ -15,7 +15,6 @@
.cm-s-ambiance .cm-string { color: #8f9d6a; }
.cm-s-ambiance .cm-string-2 { color: #9d937c; }
.cm-s-ambiance .cm-meta { color: #D2A8A1; }
-.cm-s-ambiance .cm-error { color: #AF2018; }
.cm-s-ambiance .cm-qualifier { color: yellow; }
.cm-s-ambiance .cm-builtin { color: #9999cc; }
.cm-s-ambiance .cm-bracket { color: #24C2C7; }
@@ -26,6 +25,7 @@
.cm-s-ambiance .cm-hr { color: pink; }
.cm-s-ambiance .cm-link { color: #F4C20B; }
.cm-s-ambiance .cm-special { color: #FF9D00; }
+.cm-s-ambiance .cm-error { color: #AF2018; }
.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; }
.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; }
@@ -33,7 +33,7 @@
.cm-s-ambiance .CodeMirror-selected {
background: rgba(255, 255, 255, 0.15);
}
-.cm-s-ambiance .CodeMirror-focused .CodeMirror-selected {
+.cm-s-ambiance.CodeMirror-focused .CodeMirror-selected {
background: rgba(255, 255, 255, 0.10);
}
@@ -65,7 +65,7 @@
border-left: 1px solid #7991E8;
}
-.cm-s-ambiance .activeline {
+.cm-s-ambiance .CodeMirror-activeline-background {
background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031);
}
diff --git a/gulliver/js/codemirror/theme/base16-dark.css b/gulliver/js/codemirror/theme/base16-dark.css
new file mode 100644
index 000000000..3b7b21c7a
--- /dev/null
+++ b/gulliver/js/codemirror/theme/base16-dark.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: Base16 Default Dark
+ Author: Chris Kempson (http://chriskempson.com)
+
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;}
+.cm-s-base16-dark div.CodeMirror-selected {background: #202020 !important;}
+.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;}
+.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;}
+.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;}
+
+.cm-s-base16-dark span.cm-comment {color: #8f5536;}
+.cm-s-base16-dark span.cm-atom {color: #aa759f;}
+.cm-s-base16-dark span.cm-number {color: #aa759f;}
+
+.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;}
+.cm-s-base16-dark span.cm-keyword {color: #ac4142;}
+.cm-s-base16-dark span.cm-string {color: #f4bf75;}
+
+.cm-s-base16-dark span.cm-variable {color: #90a959;}
+.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;}
+.cm-s-base16-dark span.cm-def {color: #d28445;}
+.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;}
+.cm-s-base16-dark span.cm-tag {color: #ac4142;}
+.cm-s-base16-dark span.cm-link {color: #aa759f;}
+.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;}
+
+.cm-s-base16-dark .CodeMirror-activeline-background {background: #2F2F2F !important;}
+.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/base16-light.css b/gulliver/js/codemirror/theme/base16-light.css
new file mode 100644
index 000000000..5aa4b5389
--- /dev/null
+++ b/gulliver/js/codemirror/theme/base16-light.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: Base16 Default Light
+ Author: Chris Kempson (http://chriskempson.com)
+
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools)
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;}
+.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;}
+.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;}
+.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;}
+.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;}
+
+.cm-s-base16-light span.cm-comment {color: #8f5536;}
+.cm-s-base16-light span.cm-atom {color: #aa759f;}
+.cm-s-base16-light span.cm-number {color: #aa759f;}
+
+.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;}
+.cm-s-base16-light span.cm-keyword {color: #ac4142;}
+.cm-s-base16-light span.cm-string {color: #f4bf75;}
+
+.cm-s-base16-light span.cm-variable {color: #90a959;}
+.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;}
+.cm-s-base16-light span.cm-def {color: #d28445;}
+.cm-s-base16-light span.cm-bracket {color: #202020;}
+.cm-s-base16-light span.cm-tag {color: #ac4142;}
+.cm-s-base16-light span.cm-link {color: #aa759f;}
+.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;}
+
+.cm-s-base16-light .CodeMirror-activeline-background {background: #DDDCDC !important;}
+.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/blackboard.css b/gulliver/js/codemirror/theme/blackboard.css
index f2bde690c..8b7608472 100644
--- a/gulliver/js/codemirror/theme/blackboard.css
+++ b/gulliver/js/codemirror/theme/blackboard.css
@@ -16,10 +16,13 @@
.cm-s-blackboard .cm-string { color: #61CE3C; }
.cm-s-blackboard .cm-string-2 { color: #61CE3C; }
.cm-s-blackboard .cm-meta { color: #D8FA3C; }
-.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
.cm-s-blackboard .cm-builtin { color: #8DA6CE; }
.cm-s-blackboard .cm-tag { color: #8DA6CE; }
.cm-s-blackboard .cm-attribute { color: #8DA6CE; }
.cm-s-blackboard .cm-header { color: #FF6400; }
.cm-s-blackboard .cm-hr { color: #AEAEAE; }
.cm-s-blackboard .cm-link { color: #8DA6CE; }
+.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
+
+.cm-s-blackboard .CodeMirror-activeline-background {background: #3C3636 !important;}
+.cm-s-blackboard .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
\ No newline at end of file
diff --git a/gulliver/js/codemirror/theme/cobalt.css b/gulliver/js/codemirror/theme/cobalt.css
index 6095799f3..b4a917736 100644
--- a/gulliver/js/codemirror/theme/cobalt.css
+++ b/gulliver/js/codemirror/theme/cobalt.css
@@ -12,7 +12,10 @@
.cm-s-cobalt span.cm-meta { color: #ff9d00; }
.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { color: white; }
-.cm-s-cobalt span.cm-error { color: #9d1e15; }
.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
.cm-s-cobalt span.cm-link { color: #845dc4; }
+.cm-s-cobalt span.cm-error { color: #9d1e15; }
+
+.cm-s-cobalt .CodeMirror-activeline-background {background: #002D57 !important;}
+.cm-s-cobalt .CodeMirror-matchingbracket {outline:1px solid grey;color:white !important}
diff --git a/gulliver/js/codemirror/theme/eclipse.css b/gulliver/js/codemirror/theme/eclipse.css
index 4807e4515..317218e3d 100644
--- a/gulliver/js/codemirror/theme/eclipse.css
+++ b/gulliver/js/codemirror/theme/eclipse.css
@@ -11,15 +11,13 @@
.cm-s-eclipse span.cm-comment {color: #3F7F5F;}
.cm-s-eclipse span.cm-string {color: #2A00FF;}
.cm-s-eclipse span.cm-string-2 {color: #f50;}
-.cm-s-eclipse span.cm-error {color: #f00;}
.cm-s-eclipse span.cm-qualifier {color: #555;}
.cm-s-eclipse span.cm-builtin {color: #30a;}
.cm-s-eclipse span.cm-bracket {color: #cc7;}
.cm-s-eclipse span.cm-tag {color: #170;}
.cm-s-eclipse span.cm-attribute {color: #00c;}
.cm-s-eclipse span.cm-link {color: #219;}
+.cm-s-eclipse span.cm-error {color: #f00;}
-.cm-s-eclipse .CodeMirror-matchingbracket {
- outline:1px solid grey;
- color:black !important;;
-}
+.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}
+.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
diff --git a/gulliver/js/codemirror/theme/elegant.css b/gulliver/js/codemirror/theme/elegant.css
index d0ce0cb56..dd7df7b73 100644
--- a/gulliver/js/codemirror/theme/elegant.css
+++ b/gulliver/js/codemirror/theme/elegant.css
@@ -6,5 +6,8 @@
.cm-s-elegant span.cm-qualifier {color: #555;}
.cm-s-elegant span.cm-keyword {color: #730;}
.cm-s-elegant span.cm-builtin {color: #30a;}
-.cm-s-elegant span.cm-error {background-color: #fdd;}
.cm-s-elegant span.cm-link {color: #762;}
+.cm-s-elegant span.cm-error {background-color: #fdd;}
+
+.cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;}
+.cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
diff --git a/gulliver/js/codemirror/theme/erlang-dark.css b/gulliver/js/codemirror/theme/erlang-dark.css
index cf5bf2bd6..db56b1084 100644
--- a/gulliver/js/codemirror/theme/erlang-dark.css
+++ b/gulliver/js/codemirror/theme/erlang-dark.css
@@ -4,18 +4,27 @@
.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }
.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
-.cm-s-erlang-dark span.cm-atom { color: #845dc4; }
+.cm-s-erlang-dark span.cm-atom { color: #f133f1; }
.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; }
.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; }
.cm-s-erlang-dark span.cm-builtin { color: #eaa; }
.cm-s-erlang-dark span.cm-comment { color: #77f; }
.cm-s-erlang-dark span.cm-def { color: #e7a; }
-.cm-s-erlang-dark span.cm-error { color: #9d1e15; }
.cm-s-erlang-dark span.cm-keyword { color: #ffee80; }
.cm-s-erlang-dark span.cm-meta { color: #50fefe; }
.cm-s-erlang-dark span.cm-number { color: #ffd0d0; }
-.cm-s-erlang-dark span.cm-operator { color: #d11; }
+.cm-s-erlang-dark span.cm-operator { color: #d55; }
+.cm-s-erlang-dark span.cm-property { color: #ccc; }
+.cm-s-erlang-dark span.cm-qualifier { color: #ccc; }
+.cm-s-erlang-dark span.cm-quote { color: #ccc; }
+.cm-s-erlang-dark span.cm-special { color: #ffbbbb; }
.cm-s-erlang-dark span.cm-string { color: #3ad900; }
+.cm-s-erlang-dark span.cm-string-2 { color: #ccc; }
.cm-s-erlang-dark span.cm-tag { color: #9effff; }
.cm-s-erlang-dark span.cm-variable { color: #50fe50; }
.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }
+.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; }
+.cm-s-erlang-dark span.cm-error { color: #9d1e15; }
+
+.cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;}
+.cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
diff --git a/gulliver/js/codemirror/theme/lesser-dark.css b/gulliver/js/codemirror/theme/lesser-dark.css
index 67f71ad72..c32559663 100644
--- a/gulliver/js/codemirror/theme/lesser-dark.css
+++ b/gulliver/js/codemirror/theme/lesser-dark.css
@@ -14,7 +14,7 @@ Ported to CodeMirror by Peter Kroon
.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/
-div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
+.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }
.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }
@@ -32,7 +32,6 @@ div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
.cm-s-lesser-dark span.cm-string { color: #BCD279; }
.cm-s-lesser-dark span.cm-string-2 {color: #f50;}
.cm-s-lesser-dark span.cm-meta { color: #738C73; }
-.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
.cm-s-lesser-dark span.cm-qualifier {color: #555;}
.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }
.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }
@@ -42,3 +41,7 @@ div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
.cm-s-lesser-dark span.cm-quote {color: #090;}
.cm-s-lesser-dark span.cm-hr {color: #999;}
.cm-s-lesser-dark span.cm-link {color: #00c;}
+.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
+
+.cm-s-lesser-dark .CodeMirror-activeline-background {background: #3C3A3A !important;}
+.cm-s-lesser-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
diff --git a/gulliver/js/codemirror/theme/mbo.css b/gulliver/js/codemirror/theme/mbo.css
new file mode 100644
index 000000000..bb52e6d17
--- /dev/null
+++ b/gulliver/js/codemirror/theme/mbo.css
@@ -0,0 +1,37 @@
+/* Based on mbonaci's Brackets mbo theme */
+
+.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;}
+.cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;}
+.cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;}
+.cm-s-mbo .CodeMirror-linenumber {color: #dadada;}
+.cm-s-mbo .CodeMirror-cursor {border-left: 1px solid #ffffec !important;}
+
+.cm-s-mbo span.cm-comment {color: #95958a;}
+.cm-s-mbo span.cm-atom {color: #00a8c6;}
+.cm-s-mbo span.cm-number {color: #00a8c6;}
+
+.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;}
+.cm-s-mbo span.cm-keyword {color: #ffb928;}
+.cm-s-mbo span.cm-string {color: #ffcf6c;}
+
+.cm-s-mbo span.cm-variable {color: #ffffec;}
+.cm-s-mbo span.cm-variable-2 {color: #00a8c6;}
+.cm-s-mbo span.cm-def {color: #ffffec;}
+.cm-s-mbo span.cm-bracket {color: #fffffc; font-weight: bold;}
+.cm-s-mbo span.cm-tag {color: #9ddfe9;}
+.cm-s-mbo span.cm-link {color: #f54b07;}
+.cm-s-mbo span.cm-error {background: #636363; color: #ffffec;}
+
+.cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;}
+.cm-s-mbo .CodeMirror-matchingbracket {
+ text-decoration: underline;
+ color: #f5e107 !important;
+ }
+
+.cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;}
+
+.cm-s-mbo span.cm-searching {
+ background-color: none;
+ background: none;
+ box-shadow: 0 0 0 1px #ffffec;
+}
diff --git a/gulliver/js/codemirror/theme/midnight.css b/gulliver/js/codemirror/theme/midnight.css
new file mode 100644
index 000000000..468d87daf
--- /dev/null
+++ b/gulliver/js/codemirror/theme/midnight.css
@@ -0,0 +1,43 @@
+/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */
+
+/**/
+.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }
+.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }
+
+/**/
+.cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;}
+
+.cm-s-midnight.CodeMirror {
+ background: #0F192A;
+ color: #D1EDFF;
+}
+
+.cm-s-midnight.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+
+.cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;}
+.cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;}
+.cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;}
+.cm-s-midnight .CodeMirror-cursor {
+ border-left: 1px solid #F8F8F0 !important;
+}
+
+.cm-s-midnight span.cm-comment {color: #428BDD;}
+.cm-s-midnight span.cm-atom {color: #AE81FF;}
+.cm-s-midnight span.cm-number {color: #D1EDFF;}
+
+.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute {color: #A6E22E;}
+.cm-s-midnight span.cm-keyword {color: #E83737;}
+.cm-s-midnight span.cm-string {color: #1DC116;}
+
+.cm-s-midnight span.cm-variable {color: #FFAA3E;}
+.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;}
+.cm-s-midnight span.cm-def {color: #4DD;}
+.cm-s-midnight span.cm-bracket {color: #D1EDFF;}
+.cm-s-midnight span.cm-tag {color: #449;}
+.cm-s-midnight span.cm-link {color: #AE81FF;}
+.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;}
+
+.cm-s-midnight .CodeMirror-matchingbracket {
+ text-decoration: underline;
+ color: white !important;
+}
diff --git a/gulliver/js/codemirror/theme/monokai.css b/gulliver/js/codemirror/theme/monokai.css
index a0b3c7c0a..7ac601a13 100644
--- a/gulliver/js/codemirror/theme/monokai.css
+++ b/gulliver/js/codemirror/theme/monokai.css
@@ -17,11 +17,12 @@
.cm-s-monokai span.cm-variable {color: #a6e22e;}
.cm-s-monokai span.cm-variable-2 {color: #9effff;}
.cm-s-monokai span.cm-def {color: #fd971f;}
-.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
.cm-s-monokai span.cm-bracket {color: #f8f8f2;}
.cm-s-monokai span.cm-tag {color: #f92672;}
.cm-s-monokai span.cm-link {color: #ae81ff;}
+.cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;}
+.cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;}
.cm-s-monokai .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
diff --git a/gulliver/js/codemirror/theme/neat.css b/gulliver/js/codemirror/theme/neat.css
index 8a307f802..115083b81 100644
--- a/gulliver/js/codemirror/theme/neat.css
+++ b/gulliver/js/codemirror/theme/neat.css
@@ -7,3 +7,6 @@
.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
.cm-s-neat span.cm-meta {color: #555;}
.cm-s-neat span.cm-link { color: #3a3; }
+
+.cm-s-neat .CodeMirror-activeline-background {background: #e8f2ff !important;}
+.cm-s-neat .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}
diff --git a/gulliver/js/codemirror/theme/night.css b/gulliver/js/codemirror/theme/night.css
index 8804a399a..016e55ee7 100644
--- a/gulliver/js/codemirror/theme/night.css
+++ b/gulliver/js/codemirror/theme/night.css
@@ -14,8 +14,11 @@
.cm-s-night span.cm-meta { color: #7678e2; }
.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
-.cm-s-night span.cm-error { color: #9d1e15; }
.cm-s-night span.cm-bracket { color: #8da6ce; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
.cm-s-night span.cm-link { color: #845dc4; }
+.cm-s-night span.cm-error { color: #9d1e15; }
+
+.cm-s-night .CodeMirror-activeline-background {background: #1C005A !important;}
+.cm-s-night .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
diff --git a/gulliver/js/codemirror/theme/paraiso-dark.css b/gulliver/js/codemirror/theme/paraiso-dark.css
new file mode 100644
index 000000000..ddefc55d2
--- /dev/null
+++ b/gulliver/js/codemirror/theme/paraiso-dark.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: Paraíso (Dark)
+ Author: Jan T. Sott
+
+ Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+
+*/
+
+.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;}
+.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;}
+.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;}
+.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;}
+.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;}
+
+.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;}
+.cm-s-paraiso-dark span.cm-atom {color: #815ba4;}
+.cm-s-paraiso-dark span.cm-number {color: #815ba4;}
+
+.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;}
+.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;}
+.cm-s-paraiso-dark span.cm-string {color: #fec418;}
+
+.cm-s-paraiso-dark span.cm-variable {color: #48b685;}
+.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;}
+.cm-s-paraiso-dark span.cm-def {color: #f99b15;}
+.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;}
+.cm-s-paraiso-dark span.cm-tag {color: #ef6155;}
+.cm-s-paraiso-dark span.cm-link {color: #815ba4;}
+.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;}
+
+.cm-s-paraiso-dark .CodeMirror-activeline-background {background: #4D344A !important;}
+.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/paraiso-light.css b/gulliver/js/codemirror/theme/paraiso-light.css
new file mode 100644
index 000000000..8afb14be4
--- /dev/null
+++ b/gulliver/js/codemirror/theme/paraiso-light.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: Paraíso (Light)
+ Author: Jan T. Sott
+
+ Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
+ Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+
+*/
+
+.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;}
+.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;}
+.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;}
+.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;}
+.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;}
+
+.cm-s-paraiso-light span.cm-comment {color: #e96ba8;}
+.cm-s-paraiso-light span.cm-atom {color: #815ba4;}
+.cm-s-paraiso-light span.cm-number {color: #815ba4;}
+
+.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;}
+.cm-s-paraiso-light span.cm-keyword {color: #ef6155;}
+.cm-s-paraiso-light span.cm-string {color: #fec418;}
+
+.cm-s-paraiso-light span.cm-variable {color: #48b685;}
+.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;}
+.cm-s-paraiso-light span.cm-def {color: #f99b15;}
+.cm-s-paraiso-light span.cm-bracket {color: #41323f;}
+.cm-s-paraiso-light span.cm-tag {color: #ef6155;}
+.cm-s-paraiso-light span.cm-link {color: #815ba4;}
+.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;}
+
+.cm-s-paraiso-light .CodeMirror-activeline-background {background: #CFD1C4 !important;}
+.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/pastel-on-dark.css b/gulliver/js/codemirror/theme/pastel-on-dark.css
new file mode 100644
index 000000000..df95699a0
--- /dev/null
+++ b/gulliver/js/codemirror/theme/pastel-on-dark.css
@@ -0,0 +1,49 @@
+/**
+ * Pastel On Dark theme ported from ACE editor
+ * @license MIT
+ * @copyright AtomicPages LLC 2014
+ * @author Dennis Thompson, AtomicPages LLC
+ * @version 1.1
+ * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme
+ */
+
+.cm-s-pastel-on-dark.CodeMirror {
+ background: #2c2827;
+ color: #8F938F;
+ line-height: 1.5;
+ font-family: consolas, Courier, monospace;
+ font-size: 14px;
+}
+.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2) !important; }
+.cm-s-pastel-on-dark .CodeMirror-gutters {
+ background: #34302f;
+ border-right: 0px;
+ padding: 0 3px;
+}
+.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }
+.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
+.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }
+.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }
+.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }
+.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }
+.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-string { color: #66A968; }
+.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
+.cm-s-pastel-on-dark span.cm-variable-3 { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
+.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
+.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }
+.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-error {
+ background: #757aD8;
+ color: #f8f8f0;
+}
+.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031) !important; }
+.cm-s-pastel-on-dark .CodeMirror-matchingbracket {
+ border: 1px solid rgba(255,255,255,0.25);
+ color: #8F938F !important;
+ margin: -1px -1px 0 -1px;
+}
diff --git a/gulliver/js/codemirror/theme/rubyblue.css b/gulliver/js/codemirror/theme/rubyblue.css
index 8817de07b..b556139d7 100644
--- a/gulliver/js/codemirror/theme/rubyblue.css
+++ b/gulliver/js/codemirror/theme/rubyblue.css
@@ -1,4 +1,4 @@
-.cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
+.cm-s-rubyblue { font-family: Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
.cm-s-rubyblue.CodeMirror { background: #112435; color: white; }
.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
@@ -14,8 +14,10 @@
.cm-s-rubyblue span.cm-meta { color: #F0F; }
.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def { color: white; }
-.cm-s-rubyblue span.cm-error { color: #AF2018; }
.cm-s-rubyblue span.cm-bracket { color: #F0F; }
.cm-s-rubyblue span.cm-link { color: #F4C20B; }
.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
+.cm-s-rubyblue span.cm-error { color: #AF2018; }
+
+.cm-s-rubyblue .CodeMirror-activeline-background {background: #173047 !important;}
diff --git a/gulliver/js/codemirror/theme/solarized.css b/gulliver/js/codemirror/theme/solarized.css
index 06a6c7fa1..af30d6213 100644
--- a/gulliver/js/codemirror/theme/solarized.css
+++ b/gulliver/js/codemirror/theme/solarized.css
@@ -67,11 +67,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
.cm-s-solarized .cm-string-2 { color: #b58900; }
.cm-s-solarized .cm-meta { color: #859900; }
-.cm-s-solarized .cm-error,
-.cm-s-solarized .cm-invalidchar {
- color: #586e75;
- border-bottom: 1px dotted #dc322f;
-}
.cm-s-solarized .cm-qualifier { color: #b58900; }
.cm-s-solarized .cm-builtin { color: #d33682; }
.cm-s-solarized .cm-bracket { color: #cb4b16; }
@@ -98,37 +93,20 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
content: "➤"; /*visualize tab character*/
color: #586e75;
}
-
-.cm-s-solarized.cm-s-dark .CodeMirror-focused .CodeMirror-selected {
- background: #386774;
- color: inherit;
-}
-
-.cm-s-solarized.cm-s-dark ::selection {
- background: #386774;
- color: inherit;
+.cm-s-solarized .cm-error,
+.cm-s-solarized .cm-invalidchar {
+ color: #586e75;
+ border-bottom: 1px dotted #dc322f;
}
.cm-s-solarized.cm-s-dark .CodeMirror-selected {
- background: #586e75;
-}
-
-.cm-s-solarized.cm-s-light .CodeMirror-focused .CodeMirror-selected {
- background: #eee8d5;
- color: inherit;
-}
-
-.cm-s-solarized.cm-s-light ::selection {
- background: #eee8d5;
- color: inherit;
+ background: #073642;
}
.cm-s-solarized.cm-s-light .CodeMirror-selected {
- background: #93a1a1;
+ background: #eee8d5;
}
-
-
/* Editor styling */
@@ -186,16 +164,11 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png
Active line. Negative margin compensates left padding of the text in the
view-port
*/
-.cm-s-solarized .activeline {
- margin-left: -20px;
+.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
+ background: rgba(255, 255, 255, 0.10);
}
-
-.cm-s-solarized.cm-s-dark .activeline {
- background: rgba(255, 255, 255, 0.05);
-
-}
-.cm-s-solarized.cm-s-light .activeline {
- background: rgba(0, 0, 0, 0.05);
+.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
+ background: rgba(0, 0, 0, 0.10);
}
/*
diff --git a/gulliver/js/codemirror/theme/the-matrix.css b/gulliver/js/codemirror/theme/the-matrix.css
new file mode 100644
index 000000000..0c3704a62
--- /dev/null
+++ b/gulliver/js/codemirror/theme/the-matrix.css
@@ -0,0 +1,26 @@
+.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
+.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D !important; }
+.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }
+.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }
+.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; }
+
+.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;}
+.cm-s-the-matrix span.cm-atom {color: #3FF;}
+.cm-s-the-matrix span.cm-number {color: #FFB94F;}
+.cm-s-the-matrix span.cm-def {color: #99C;}
+.cm-s-the-matrix span.cm-variable {color: #F6C;}
+.cm-s-the-matrix span.cm-variable-2 {color: #C6F;}
+.cm-s-the-matrix span.cm-variable-3 {color: #96F;}
+.cm-s-the-matrix span.cm-property {color: #62FFA0;}
+.cm-s-the-matrix span.cm-operator {color: #999}
+.cm-s-the-matrix span.cm-comment {color: #CCCCCC;}
+.cm-s-the-matrix span.cm-string {color: #39C;}
+.cm-s-the-matrix span.cm-meta {color: #C9F;}
+.cm-s-the-matrix span.cm-qualifier {color: #FFF700;}
+.cm-s-the-matrix span.cm-builtin {color: #30a;}
+.cm-s-the-matrix span.cm-bracket {color: #cc7;}
+.cm-s-the-matrix span.cm-tag {color: #FFBD40;}
+.cm-s-the-matrix span.cm-attribute {color: #FFF700;}
+.cm-s-the-matrix span.cm-error {color: #FF0000;}
+
+.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;}
diff --git a/gulliver/js/codemirror/theme/tomorrow-night-eighties.css b/gulliver/js/codemirror/theme/tomorrow-night-eighties.css
new file mode 100644
index 000000000..85c2a4a78
--- /dev/null
+++ b/gulliver/js/codemirror/theme/tomorrow-night-eighties.css
@@ -0,0 +1,34 @@
+/*
+
+ Name: Tomorrow Night - Eighties
+ Author: Chris Kempson
+
+ CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+ Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-tomorrow-night-eighties.CodeMirror {background: #000000; color: #CCCCCC;}
+.cm-s-tomorrow-night-eighties div.CodeMirror-selected {background: #2D2D2D !important;}
+.cm-s-tomorrow-night-eighties .CodeMirror-gutters {background: #000000; border-right: 0px;}
+.cm-s-tomorrow-night-eighties .CodeMirror-linenumber {color: #515151;}
+.cm-s-tomorrow-night-eighties .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;}
+
+.cm-s-tomorrow-night-eighties span.cm-comment {color: #d27b53;}
+.cm-s-tomorrow-night-eighties span.cm-atom {color: #a16a94;}
+.cm-s-tomorrow-night-eighties span.cm-number {color: #a16a94;}
+
+.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute {color: #99cc99;}
+.cm-s-tomorrow-night-eighties span.cm-keyword {color: #f2777a;}
+.cm-s-tomorrow-night-eighties span.cm-string {color: #ffcc66;}
+
+.cm-s-tomorrow-night-eighties span.cm-variable {color: #99cc99;}
+.cm-s-tomorrow-night-eighties span.cm-variable-2 {color: #6699cc;}
+.cm-s-tomorrow-night-eighties span.cm-def {color: #f99157;}
+.cm-s-tomorrow-night-eighties span.cm-bracket {color: #CCCCCC;}
+.cm-s-tomorrow-night-eighties span.cm-tag {color: #f2777a;}
+.cm-s-tomorrow-night-eighties span.cm-link {color: #a16a94;}
+.cm-s-tomorrow-night-eighties span.cm-error {background: #f2777a; color: #6A6A6A;}
+
+.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background {background: #343600 !important;}
+.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
diff --git a/gulliver/js/codemirror/theme/twilight.css b/gulliver/js/codemirror/theme/twilight.css
index fd8944ba8..19d6abadd 100644
--- a/gulliver/js/codemirror/theme/twilight.css
+++ b/gulliver/js/codemirror/theme/twilight.css
@@ -16,11 +16,13 @@
.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/
.cm-s-twilight .cm-string-2 { color:#bd6b18 } /*?*/
.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/
-.cm-s-twilight .cm-error { border-bottom: 1px solid red; }
.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/
.cm-s-twilight .cm-tag { color: #997643; } /**/
.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/
.cm-s-twilight .cm-header { color: #FF6400; }
.cm-s-twilight .cm-hr { color: #AEAEAE; }
.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/
+.cm-s-twilight .cm-error { border-bottom: 1px solid red; }
+.cm-s-twilight .CodeMirror-activeline-background {background: #27282E !important;}
+.cm-s-twilight .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
diff --git a/gulliver/js/codemirror/theme/vibrant-ink.css b/gulliver/js/codemirror/theme/vibrant-ink.css
index 22024a489..0206225bf 100644
--- a/gulliver/js/codemirror/theme/vibrant-ink.css
+++ b/gulliver/js/codemirror/theme/vibrant-ink.css
@@ -11,17 +11,20 @@
.cm-s-vibrant-ink .cm-atom { color: #FC0; }
.cm-s-vibrant-ink .cm-number { color: #FFEE98; }
.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
-.cm-s-vibrant-ink span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #FFC66D }
-.cm-s-vibrant-ink span.cm-variable-3, .cm-s-cobalt span.cm-def { color: #FFC66D }
+.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D }
+.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def { color: #FFC66D }
.cm-s-vibrant-ink .cm-operator { color: #888; }
.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
.cm-s-vibrant-ink .cm-string { color: #A5C25C }
.cm-s-vibrant-ink .cm-string-2 { color: red }
.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
-.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
.cm-s-vibrant-ink .cm-header { color: #FF6400; }
.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
.cm-s-vibrant-ink .cm-link { color: blue; }
+.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
+
+.cm-s-vibrant-ink .CodeMirror-activeline-background {background: #27282E !important;}
+.cm-s-vibrant-ink .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
diff --git a/gulliver/js/codemirror/theme/xq-dark.css b/gulliver/js/codemirror/theme/xq-dark.css
index fd9bb12ab..4a0b2138c 100644
--- a/gulliver/js/codemirror/theme/xq-dark.css
+++ b/gulliver/js/codemirror/theme/xq-dark.css
@@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }
-.cm-s-xq-dark span.CodeMirror-selected { background: #a8f !important; }
+.cm-s-xq-dark .CodeMirror-selected { background: #27007A !important; }
.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }
.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
@@ -38,9 +38,12 @@ THE SOFTWARE.
.cm-s-xq-dark span.cm-comment {color: gray;}
.cm-s-xq-dark span.cm-string {color: #9FEE00;}
.cm-s-xq-dark span.cm-meta {color: yellow;}
-.cm-s-xq-dark span.cm-error {color: #f00;}
.cm-s-xq-dark span.cm-qualifier {color: #FFF700;}
.cm-s-xq-dark span.cm-builtin {color: #30a;}
.cm-s-xq-dark span.cm-bracket {color: #cc7;}
.cm-s-xq-dark span.cm-tag {color: #FFBD40;}
.cm-s-xq-dark span.cm-attribute {color: #FFF700;}
+.cm-s-xq-dark span.cm-error {color: #f00;}
+
+.cm-s-xq-dark .CodeMirror-activeline-background {background: #27282E !important;}
+.cm-s-xq-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;}
\ No newline at end of file
diff --git a/gulliver/js/codemirror/theme/xq-light.css b/gulliver/js/codemirror/theme/xq-light.css
index 08784d58c..20b5c7961 100644
--- a/gulliver/js/codemirror/theme/xq-light.css
+++ b/gulliver/js/codemirror/theme/xq-light.css
@@ -32,12 +32,12 @@ THE SOFTWARE.
.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;}
.cm-s-xq-light span.cm-string {color: red;}
.cm-s-xq-light span.cm-meta {color: yellow;}
-.cm-s-xq-light span.cm-error {color: #f00;}
.cm-s-xq-light span.cm-qualifier {color: grey}
.cm-s-xq-light span.cm-builtin {color: #7EA656;}
.cm-s-xq-light span.cm-bracket {color: #cc7;}
.cm-s-xq-light span.cm-tag {color: #3F7F7F;}
.cm-s-xq-light span.cm-attribute {color: #7F007F;}
+.cm-s-xq-light span.cm-error {color: #f00;}
.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;}
-.cm-s-xq-light .CodeMirror-matchingbracket {border:1px solid grey;color:black !important;background:yellow;}
\ No newline at end of file
+.cm-s-xq-light .CodeMirror-matchingbracket {outline:1px solid grey;color:black !important;background:yellow;}
\ No newline at end of file
diff --git a/workflow/engine/templates/designer/index.html b/workflow/engine/templates/designer/index.html
index 8d7ce2c02..35ac9c2fb 100644
--- a/workflow/engine/templates/designer/index.html
+++ b/workflow/engine/templates/designer/index.html
@@ -63,3 +63,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file