Merge pull request #76 from eric-wood/master

Added CodeMirror editor replacement
This commit is contained in:
Jason Barnabe 2012-12-01 14:56:38 -08:00
commit 88c3eeaf20
51 changed files with 8144 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.DS_Store

2
codemirror/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/node_modules
/npm-debug.log

3
codemirror/.travis.yml Normal file
View File

@ -0,0 +1,3 @@
language: node_js
node_js:
- 0.8

23
codemirror/LICENSE Normal file
View File

@ -0,0 +1,23 @@
Copyright (C) 2012 by Marijn Haverbeke <marijnh@gmail.com>
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.
Please note that some subdirectories of the CodeMirror distribution
include their own LICENSE files, and are released under different
licences.

8
codemirror/README.md Normal file
View File

@ -0,0 +1,8 @@
# CodeMirror [![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/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
in, it will color your code, and optionally help with indentation.
The project page is http://codemirror.net
The manual is at http://codemirror.net/doc/manual.html

88
codemirror/bin/compress Executable file
View File

@ -0,0 +1,88 @@
#!/usr/bin/env node
// Compression helper for CodeMirror
//
// Example:
//
// bin/compress codemirror runmode javascript xml
//
// Will take lib/codemirror.js, lib/util/runmode.js,
// mode/javascript/javascript.js, and mode/xml/xml.js, run them though
// the online minifier at http://marijnhaverbeke.nl/uglifyjs, and spit
// out the result.
//
// bin/compress codemirror --local /path/to/bin/UglifyJS
//
// Will use a local minifier instead of the online default one.
//
// Script files are specified without .js ending. Prefixing them with
// their full (local) path is optional. So you may say lib/codemirror
// or mode/xml/xml to be more precise. In fact, even the .js suffix
// may be speficied, if wanted.
"use strict";
var fs = require("fs");
function help(ok) {
console.log("usage: " + process.argv[1] + " [--local /path/to/uglifyjs] files...");
process.exit(ok ? 0 : 1);
}
var local = null, args = 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);
} else if (arg == "--help") {
help(true);
} else if (arg[0] != "-") {
files.push({name: arg, re: new RegExp("(?:\\/|^)" + arg + (/\.js$/.test(arg) ? "$" : "\\.js$"))});
} else help(false);
}
function walk(dir) {
fs.readdirSync(dir).forEach(function(fname) {
if (/^[_\.]/.test(fname)) return;
var file = dir + fname;
if (fs.statSync(file).isDirectory()) return walk(file + "/");
if (files.some(function(spec, i) {
var match = spec.re.test(file);
if (match) files.splice(i, 1);
return match;
})) {
if (local) args.push(file);
else blob += fs.readFileSync(file, "utf8");
}
});
}
walk("lib/");
walk("mode/");
if (files.length) {
console.log("Some speficied files were not found: " +
files.map(function(a){return a.name;}).join(", "));
process.exit(1);
}
if (local) {
require("child_process").spawn(local, args, {stdio: ["ignore", process.stdout, process.stderr]});
} else {
var data = new Buffer("js_code=" + require("querystring").escape(blob), "utf8");
var req = require("http").request({
host: "marijnhaverbeke.nl",
port: 80,
method: "POST",
path: "/uglifyjs",
headers: {"content-type": "application/x-www-form-urlencoded",
"content-length": data.length}
});
req.on("response", function(resp) {
resp.on("data", function (chunk) { process.stdout.write(chunk); });
});
req.end(data);
}

480
codemirror/index.html Normal file
View File

@ -0,0 +1,480 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>CodeMirror</title>
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
<link rel="stylesheet" type="text/css" href="doc/docs.css"/>
<link rel="alternate" href="https://groups.google.com/group/codemirror-announce/feed/atom_v1_0_topics.xml" type="application/atom+xml"/>
</head>
<body>
<h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
<div class="grey">
<img src="doc/baboon.png" class="logo" alt="logo"/>
<pre>
/* In-browser code editing
made bearable */
</pre>
</div>
<div class="clear"><div class="left blk">
<p style="margin-top: 0">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.</p>
<p>A <a href="doc/manual.html">rich programming API</a> and a CSS
theming system are available for customizing CodeMirror to fit your
application, and extending it with new functionality.</p>
<div class="clear"><div class="left1 blk">
<h2 style="margin-top: 0">Supported modes:</h2>
<ul>
<li><a href="mode/clike/index.html">C, C++, C#</a></li>
<li><a href="mode/clojure/index.html">Clojure</a></li>
<li><a href="mode/coffeescript/index.html">CoffeeScript</a></li>
<li><a href="mode/commonlisp/index.html">Common Lisp</a></li>
<li><a href="mode/css/index.html">CSS</a></li>
<li><a href="mode/diff/index.html">diff</a></li>
<li><a href="mode/ecl/index.html">ECL</a></li>
<li><a href="mode/erlang/index.html">Erlang</a></li>
<li><a href="mode/go/index.html">Go</a></li>
<li><a href="mode/groovy/index.html">Groovy</a></li>
<li><a href="mode/haskell/index.html">Haskell</a></li>
<li><a href="mode/haxe/index.html">Haxe</a></li>
<li><a href="mode/htmlembedded/index.html">HTML embedded scripts</a></li>
<li><a href="mode/htmlmixed/index.html">HTML mixed-mode</a></li>
<li><a href="mode/clike/index.html">Java</a></li>
<li><a href="mode/javascript/index.html">JavaScript</a></li>
<li><a href="mode/jinja2/index.html">Jinja2</a></li>
<li><a href="mode/less/index.html">LESS</a></li>
<li><a href="mode/lua/index.html">Lua</a></li>
<li><a href="mode/markdown/index.html">Markdown</a> (<a href="mode/gfm/index.html">GitHub-flavour</a>)</li>
<li><a href="mode/mysql/index.html">MySQL</a></li>
<li><a href="mode/ntriples/index.html">NTriples</a></li>
<li><a href="mode/ocaml/index.html">OCaml</a></li>
<li><a href="mode/pascal/index.html">Pascal</a></li>
<li><a href="mode/perl/index.html">Perl</a></li>
<li><a href="mode/php/index.html">PHP</a></li>
<li><a href="mode/pig/index.html">Pig Latin</a></li>
<li><a href="mode/plsql/index.html">PL/SQL</a></li>
<li><a href="mode/properties/index.html">Properties files</a></li>
<li><a href="mode/python/index.html">Python</a></li>
<li><a href="mode/r/index.html">R</a></li>
<li>RPM <a href="mode/rpm/spec/index.html">spec</a> and <a href="mode/rpm/changes/index.html">changelog</a></li>
<li><a href="mode/rst/index.html">reStructuredText</a></li>
<li><a href="mode/ruby/index.html">Ruby</a></li>
<li><a href="mode/rust/index.html">Rust</a></li>
<li><a href="mode/clike/scala.html">Scala</a></li>
<li><a href="mode/scheme/index.html">Scheme</a></li>
<li><a href="mode/shell/index.html">Shell</a></li>
<li><a href="mode/sieve/index.html">Sieve</a></li>
<li><a href="mode/smalltalk/index.html">Smalltalk</a></li>
<li><a href="mode/smarty/index.html">Smarty</a></li>
<li><a href="mode/sparql/index.html">SPARQL</a></li>
<li><a href="mode/stex/index.html">sTeX, LaTeX</a></li>
<li><a href="mode/tiddlywiki/index.html">Tiddlywiki</a></li>
<li><a href="mode/tiki/index.html">Tiki wiki</a></li>
<li><a href="mode/vb/index.html">VB.NET</a></li>
<li><a href="mode/vbscript/index.html">VBScript</a></li>
<li><a href="mode/velocity/index.html">Velocity</a></li>
<li><a href="mode/verilog/index.html">Verilog</a></li>
<li><a href="mode/xml/index.html">XML/HTML</a></li>
<li><a href="mode/xquery/index.html">XQuery</a></li>
<li><a href="mode/yaml/index.html">YAML</a></li>
<li><a href="mode/z80/index.html">Z80</a></li>
</ul>
</div><div class="left2 blk">
<h2 style="margin-top: 0">Usage demos:</h2>
<ul>
<li><a href="demo/complete.html">Autocompletion</a> (<a href="demo/xmlcomplete.html">XML</a>)</li>
<li><a href="demo/search.html">Search/replace</a></li>
<li><a href="demo/folding.html">Code folding</a></li>
<li><a href="demo/mustache.html">Mode overlays</a></li>
<li><a href="demo/multiplex.html">Mode multiplexer</a></li>
<li><a href="demo/preview.html">HTML editor with preview</a></li>
<li><a href="demo/resize.html">Auto-resizing editor</a></li>
<li><a href="demo/marker.html">Setting breakpoints</a></li>
<li><a href="demo/activeline.html">Highlighting the current line</a></li>
<li><a href="demo/matchhighlighter.html">Highlighting selection matches</a></li>
<li><a href="demo/theme.html">Theming</a></li>
<li><a href="demo/runmode.html">Stand-alone highlighting</a></li>
<li><a href="demo/fullscreen.html">Full-screen editing</a></li>
<li><a href="demo/changemode.html">Mode auto-changing</a></li>
<li><a href="demo/visibletabs.html">Visible tabs</a></li>
<li><a href="demo/formatting.html">Autoformatting of code</a></li>
<li><a href="demo/emacs.html">Emacs keybindings</a></li>
<li><a href="demo/vim.html">Vim keybindings</a></li>
<li><a href="demo/closetag.html">Automatic xml tag closing</a></li>
<li><a href="demo/loadmode.html">Lazy mode loading</a></li>
</ul>
<h2>Real-world uses:</h2>
<ul>
<li><a href="http://jsbin.com">jsbin.com</a> (JS playground)</li>
<li><a href="http://www.chris-granger.com/2012/04/12/light-table---a-new-ide-concept/">Light Table</a> (experimental IDE)</li>
<li><a href="http://brackets.io">Adobe Brackets</a> (code editor)</li>
<li><a href="http://www.mergely.com/">Mergely</a> (interactive diffing)</li>
<li><a href="https://script.google.com/">Google Apps Script</a></li>
<li><a href="https://github.com/github/android">GitHub's Android app</a></li>
<li><a href="http://eloquentjavascript.net/chapter1.html">Eloquent JavaScript</a> (book)</li>
<li><a href="http://media.chikuyonok.ru/codemirror2/">Zen Coding</a> (fast XML editing)</li>
<li><a href="http://paperjs.org/">Paper.js</a> (graphics scripting)</li>
<li><a href="http://tour.golang.org">Go language tour</a></li>
<li><a href="http://codev.it/">Codev</a> (collaborative IDE)</li>
<li><a href="http://enjalot.com/tributary/2636296/sinwaves.js">Tributary</a> (augmented editing)</li>
<li><a href="http://prose.io/">Prose.io</a> (github content editor)</li>
<li><a href="http://www.wescheme.org/">WeScheme</a> (learning tool)</li>
<li><a href="http://webglplayground.net/">WebGL playground</a></li>
<li><a href="http://ql.io/">ql.io</a> (http API query helper)</li>
<li><a href="http://elm-lang.org/Examples.elm">Elm language examples</a></li>
<li><a href="https://thefiletree.com">The File Tree</a> (collab editor)</li>
<li><a href="http://www.jshint.com/">JSHint</a> (JS linter)</li>
<li><a href="http://kl1p.com/cmtest/1">kl1p</a> (paste service)</li>
<li><a href="http://sqlfiddle.com">SQLFiddle</a> (SQL playground)</li>
<li><a href="http://try.haxe.org">Try Haxe</a> (Haxe Playground) </li>
<li><a href="http://cssdeck.com/">CSSDeck</a> (CSS showcase)</li>
<li><a href="http://www.sketchpatch.net/labs/livecodelabIntro.html">sketchPatch Livecodelab</a></li>
<li><a href="https://notex.ch">NoTex</a> (rST authoring)</li>
<li><a href="doc/realworld.html">More...</a></li>
</ul>
</div></div>
<h2 id="code">Getting the code</h2>
<p>All of CodeMirror is released under a <a
href="LICENSE">MIT-style</a> license. To get it, you can download
the <a href="http://codemirror.net/codemirror.zip">latest
release</a> or the current <a
href="http://codemirror.net/codemirror-latest.zip">development
snapshot</a> as zip files. To create a custom minified script file,
you can use the <a href="doc/compress.html">compression API</a>.</p>
<p>We use <a href="http://git-scm.com/">git</a> for version control.
The main repository can be fetched in this way:</p>
<pre class="code">git clone http://marijnhaverbeke.nl/git/codemirror</pre>
<p>CodeMirror can also be found on GitHub at <a
href="http://github.com/marijnh/CodeMirror">marijnh/CodeMirror</a>.
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.</p>
<h2 id="documention">Documentation</h2>
<p>The <a href="doc/manual.html">manual</a> 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.</p>
<p>For those who want to learn more about the code, there is
an <a href="doc/internals.html">overview of the internals</a> available.
The <a href="http://github.com/marijnh/CodeMirror">source code</a>
itself is, for the most part, also well commented.</p>
<h2 id="support">Support and bug reports</h2>
<p>Community discussion, questions, and informal bug reporting is
done on
the <a href="http://groups.google.com/group/codemirror">CodeMirror
Google group</a>. There is a separate
group, <a href="http://groups.google.com/group/codemirror-announce">CodeMirror-announce</a>,
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.</p>
<p>Though bug reports through e-mail are responded to, the preferred
way to report bugs is to use
the <a href="http://github.com/marijnh/CodeMirror/issues">GitHub
issue tracker</a>. Before reporting a
bug, <a href="doc/reporting.html">read these pointers</a>. Also,
the issue tracker is for <em>bugs</em>, not requests for help.</p>
<p>When none of these seem fitting, you can
simply <a href="mailto:marijnh@gmail.com">e-mail the maintainer</a>
directly.</p>
<h2 id="supported">Supported browsers</h2>
<p>The following <em>desktop</em> browsers are able to run CodeMirror:</p>
<ul>
<li>Firefox 2 or higher</li>
<li>Chrome, any version</li>
<li>Safari 3 or higher</li>
<li>Opera 9 or higher (with some key-handling problems on OS X)</li>
<li>Internet Explorer 7 or higher in standards mode<br>
<em>(So not quirks mode. But quasi-standards mode with a
transitional doctype is also flaky. <code>&lt;!doctype
html></code> is recommended.)</em></li>
</ul>
<p>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 <a href="#support">here</a> for information on how to contact
me.</p>
<p>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.</p>
<h2 id="commercial">Commercial support</h2>
<p>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.</p>
<ul>
<li>You'll be funding further work on CodeMirror.</li>
<li>You ensure that you get a quick response when you have a
problem, even when I am otherwise busy.</li>
</ul>
<p>CodeMirror support contracts exist in two
forms—<strong>basic</strong> at €100 per month,
and <strong>premium</strong> at €500 per
month. <a href="mailto:marijnh@gmail.com">Contact me</a> for further
information.</p>
</div>
<div class="right blk">
<a href="http://codemirror.net/codemirror.zip" class="download">Download the latest release</a>
<h2>Support CodeMirror</h2>
<ul>
<li>Donate
(<span onclick="document.getElementById('paypal').submit();"
class="quasilink">Paypal</span>,
<span onclick="document.getElementById('bankinfo').style.display = 'block';"
class="quasilink">bank</span>, or
<a href="https://www.gittip.com/marijnh">Gittip</a>)</li>
<li>Purchase <a href="#commercial">commercial support</a></li>
</ul>
<p id="bankinfo" style="display: none;">
Bank: <i>Rabobank</i><br/>
Country: <i>Netherlands</i><br/>
SWIFT: <i>RABONL2U</i><br/>
Account: <i>147850770</i><br/>
Name: <i>Marijn Haverbeke</i><br/>
IBAN: <i>NL26 RABO 0147 8507 70</i>
</p>
<h2>Reading material</h2>
<ul>
<li><a href="doc/manual.html">User manual</a></li>
<li><a href="http://github.com/marijnh/CodeMirror">Browse the code</a></li>
</ul>
<h2 id=releases>Releases</h2>
<p class="rel">20-11-2012: <a href="http://codemirror.net/codemirror-2.36.zip">Version 2.36</a>:</p>
<ul class="rel-note">
<li>New mode: <a href="mode/z80/index.html">Z80 assembly</a>.</li>
<li>New theme: <a href="demo/theme.html?twilight">Twilight</a>.</li>
<li>Add command-line compression helper.</li>
<li>Make <a href="doc/manual.html#scrollIntoView"><code>scrollIntoView</code></a> public.</li>
<li>Add <a href="doc/manual.html#defaultTextHeight"><code>defaultTextHeight</code></a> method.</li>
<li>Various extensions to the vim keymap.</li>
<li>Make <a href="mode/php/index.html">PHP mode</a> build on <a href="mode/htmlmixed/index.html">mixed HTML mode</a>.</li>
<li>Add <a href="doc/manual.html#util_continuecomment">comment-continuing</a> add-on.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/v2.35...v2.36">list of patches</a>.</li>
</ul>
<p class="rel">20-11-2012: <a href="http://codemirror.net/codemirror-3.0rc1.zip">Version 3.0, release candidate 1</a>:</p>
<p class="rel-note"><strong>New major version</strong>. Only partially
backwards-compatible. See
the <a href="http://codemirror.net/3/doc/upgrade_v3.html">upgrading
guide</a> for more information. Changes since beta 2:</p>
<ul class="rel-note">
<li>New theme: <a href="http://codemirror.net/3/demo/theme.html?solarized%20light">Solarized</a>.</li>
<li>Introduce <a href="http://codemirror.net/3/doc/manual.html#addLineClass"><code>addLineClass</code></a>
and <a href="http://codemirror.net/3/doc/manual.html#removeLineClass"><code>removeLineClass</code></a>,
drop <code>setLineClass</code>.</li>
<li>Add a <em>lot</em> of
new <a href="http://codemirror.net/3/doc/manual.html#markText">options for marked text</a>
(read-only, atomic, collapsed, widget replacement).</li>
<li>Remove the old code folding interface in favour of these new ranges.</li>
<li>Add <a href="http://codemirror.net/3/doc/manual.html#isClean"><code>isClean</code></a>/<a href="http://codemirror.net/3/doc/manual.html#markClean"><code>markClean</code></a> methods.</li>
<li>Remove <code>compoundChange</code> method, use better undo-event-combining heuristic.</li>
<li>Improve scrolling performance smoothness.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/v3.0beta2...v3.0rc1">list of patches</a>.</li>
</ul>
<p class="rel">22-10-2012: <a href="http://codemirror.net/codemirror-2.35.zip">Version 2.35</a>:</p>
<ul class="rel-note">
<li>New (sub) mode: <a href="mode/javascript/typescript.html">TypeScript</a>.</li>
<li>Don't overwrite (insert key) when pasting.</li>
<li>Fix several bugs in <a href="doc/manual.html#markText"><code>markText</code></a>/undo interaction.</li>
<li>Better indentation of JavaScript code without semicolons.</li>
<li>Add <a href="doc/manual.html#defineInitHook"><code>defineInitHook</code></a> function.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/v2.34...v2.35">list of patches</a>.</li>
</ul>
<p class="rel">22-10-2012: <a href="http://codemirror.net/codemirror-3.0beta2.zip">Version 3.0, beta 2</a>:</p>
<ul class="rel-note">
<li>Fix page-based coordinate computation.</li>
<li>Fix firing of <a href="http://codemirror.net/3/doc/manual.html#event_gutterClick"><code>gutterClick</code></a> event.</li>
<li>Add <a href="http://codemirror.net/3/doc/manual.html#option_cursorHeight"><code>cursorHeight</code></a> option.</li>
<li>Fix bi-directional text regression.</li>
<li>Add <a href="http://codemirror.net/3/doc/manual.html#option_viewportMargin"><code>viewportMargin</code></a> option.</li>
<li>Directly handle mousewheel events (again, hopefully better).</li>
<li>Make vertical cursor movement more robust (through widgets, big line gaps).</li>
<li>Add <a href="http://codemirror.net/3/doc/manual.html#option_flattenSpans"><code>flattenSpans</code></a> option.</li>
<li>Initialization in hidden state works again.</li>
<li>Many optimizations. Poor responsiveness should be fixed.</li>
<li>Full <a href="https://github.com/marijnh/CodeMirror/compare/v3.0beta1...v3.0beta2">list of patches</a>.</li>
</ul>
<p class="rel">19-09-2012: <a href="http://codemirror.net/codemirror-2.34.zip">Version 2.34</a>:</p>
<ul class="rel-note">
<li>New mode: <a href="mode/commonlisp/index.html">Common Lisp</a>.</li>
<li>Fix right-click select-all on most browsers.</li>
<li>Change the way highlighting happens:<br>&nbsp; Saves memory and CPU cycles.<br>&nbsp; <code>compareStates</code> is no longer needed.<br>&nbsp; <code>onHighlightComplete</code> no longer works.</li>
<li>Integrate mode (Markdown, XQuery, CSS, sTex) tests in central testsuite.</li>
<li>Add a <a href="doc/manual.html#version"><code>CodeMirror.version</code></a> property.</li>
<li>More robust handling of nested modes in <a href="demo/formatting.html">formatting</a> and <a href="demo/closetag.html">closetag</a> plug-ins.</li>
<li>Un/redo now preserves <a href="doc/manual.html#markText">marked text</a> and bookmarks.</li>
<li><a href="https://github.com/marijnh/CodeMirror/compare/v2.33...v2.34">Full list</a> of patches.</li>
</ul>
<p class="rel">19-09-2012: <a href="http://codemirror.net/codemirror-3.0beta1.zip">Version 3.0, beta 1</a>:</p>
<ul class="rel-note">
<li>Bi-directional text support.</li>
<li>More powerful gutter model.</li>
<li>Support for arbitrary text/widget height.</li>
<li>In-line widgets.</li>
<li>Generalized event handling.</li>
</ul>
<p class="rel">23-08-2012: <a href="http://codemirror.net/codemirror-2.33.zip">Version 2.33</a>:</p>
<ul class="rel-note">
<li>New mode: <a href="mode/sieve/index.html">Sieve</a>.</li>
<li>New <a href="doc/manual.html#getViewport"><code>getViewPort</code></a> and <a href="doc/manual.html#option_onViewportChange"><code>onViewportChange</code></a> API.</li>
<li><a href="doc/manual.html#option_cursorBlinkRate">Configurable</a> cursor blink rate.</li>
<li>Make binding a key to <code>false</code> disabling handling (again).</li>
<li>Show non-printing characters as red dots.</li>
<li>More tweaks to the scrolling model.</li>
<li>Expanded testsuite. Basic linter added.</li>
<li>Remove most uses of <code>innerHTML</code>. Remove <code>CodeMirror.htmlEscape</code>.</li>
<li><a href="https://github.com/marijnh/CodeMirror/compare/v2.32...v2.33">Full list</a> of patches.</li>
</ul>
<p class="rel">23-07-2012: <a href="http://codemirror.net/codemirror-2.32.zip">Version 2.32</a>:</p>
<p class="rel-note">Emergency fix for a bug where an editor with
line wrapping on IE will break when there is <em>no</em>
scrollbar.</p>
<p class="rel">20-07-2012: <a href="http://codemirror.net/codemirror-2.31.zip">Version 2.31</a>:</p>
<ul class="rel-note">
<li>New modes: <a href="mode/ocaml/index.html">OCaml</a>, <a href="mode/haxe/index.html">Haxe</a>, and <a href="mode/vb/index.html">VB.NET</a>.</li>
<li>Several fixes to the new scrolling model.</li>
<li>Add a <a href="doc/manual.html#setSize"><code>setSize</code></a> method for programmatic resizing.</li>
<li>Add <a href="doc/manual.html#getHistory"><code>getHistory</code></a> and <a href="doc/manual.html#setHistory"><code>setHistory</code></a> methods.</li>
<li>Allow custom line separator string in <a href="doc/manual.html#getValue"><code>getValue</code></a> and <a href="doc/manual.html#getRange"><code>getRange</code></a>.</li>
<li>Support double- and triple-click drag, double-clicking whitespace.</li>
<li>And more... <a href="https://github.com/marijnh/CodeMirror/compare/v2.3...v2.31">(all patches)</a></li>
</ul>
<p class="rel">22-06-2012: <a href="http://codemirror.net/codemirror-2.3.zip">Version 2.3</a>:</p>
<ul class="rel-note">
<li><strong>New scrollbar implementation</strong>. Should flicker less. Changes DOM structure of the editor.</li>
<li>New theme: <a href="demo/theme.html?vibrant-ink">vibrant-ink</a>.</li>
<li>Many extensions to the VIM keymap (including text objects).</li>
<li>Add <a href="demo/multiplex.html">mode-multiplexing</a> utility script.</li>
<li>Fix bug where right-click paste works in read-only mode.</li>
<li>Add a <a href="doc/manual.html#getScrollInfo"><code>getScrollInfo</code></a> method.</li>
<li>Lots of other <a href="https://github.com/marijnh/CodeMirror/compare/v2.25...v2.3">fixes</a>.</li>
</ul>
<p class="rel">23-05-2012: <a href="http://codemirror.net/codemirror-2.25.zip">Version 2.25</a>:</p>
<ul class="rel-note">
<li>New mode: <a href="mode/erlang/index.html">Erlang</a>.</li>
<li><strong>Remove xmlpure mode</strong> (use <a href="mode/xml/index.html">xml.js</a>).</li>
<li>Fix line-wrapping in Opera.</li>
<li>Fix X Windows middle-click paste in Chrome.</li>
<li>Fix bug that broke pasting of huge documents.</li>
<li>Fix backspace and tab key repeat in Opera.</li>
</ul>
<p class="rel">23-04-2012: <a href="http://codemirror.net/codemirror-2.24.zip">Version 2.24</a>:</p>
<ul class="rel-note">
<li><strong>Drop support for Internet Explorer 6</strong>.</li>
<li>New
modes: <a href="mode/shell/index.html">Shell</a>, <a href="mode/tiki/index.html">Tiki
wiki</a>, <a href="mode/pig/index.html">Pig Latin</a>.</li>
<li>New themes: <a href="demo/theme.html?ambiance">Ambiance</a>, <a href="demo/theme.html?blackboard">Blackboard</a>.</li>
<li>More control over drag/drop
with <a href="doc/manual.html#option_dragDrop"><code>dragDrop</code></a>
and <a href="doc/manual.html#option_onDragEvent"><code>onDragEvent</code></a>
options.</li>
<li>Make HTML mode a bit less pedantic.</li>
<li>Add <a href="doc/manual.html#compoundChange"><code>compoundChange</code></a> API method.</li>
<li>Several fixes in undo history and line hiding.</li>
<li>Remove (broken) support for <code>catchall</code> in key maps,
add <code>nofallthrough</code> boolean field instead.</li>
</ul>
<p class="rel">26-03-2012: <a href="http://codemirror.net/codemirror-2.23.zip">Version 2.23</a>:</p>
<ul class="rel-note">
<li>Change <strong>default binding for tab</strong> <a href="javascript:void(document.getElementById('tabbinding').style.display='')">[more]</a>
<div style="display: none" id=tabbinding>
Starting in 2.23, these bindings are default:
<ul><li>Tab: Insert tab character</li>
<li>Shift-tab: Reset line indentation to default</li>
<li>Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)</li>
<li>Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)</li>
</ul>
</div>
</li>
<li>New modes: <a href="mode/xquery/index.html">XQuery</a> and <a href="mode/vbscript/index.html">VBScript</a>.</li>
<li>Two new themes: <a href="mode/less/index.html">lesser-dark</a> and <a href="mode/xquery/index.html">xq-dark</a>.</li>
<li>Differentiate between background and text styles in <a href="doc/manual.html#setLineClass"><code>setLineClass</code></a>.</li>
<li>Fix drag-and-drop in IE9+.</li>
<li>Extend <a href="doc/manual.html#charCoords"><code>charCoords</code></a>
and <a href="doc/manual.html#cursorCoords"><code>cursorCoords</code></a> with a <code>mode</code> argument.</li>
<li>Add <a href="doc/manual.html#option_autofocus"><code>autofocus</code></a> option.</li>
<li>Add <a href="doc/manual.html#findMarksAt"><code>findMarksAt</code></a> method.</li>
</ul>
<p><a href="doc/oldrelease.html">Older releases...</a></p>
</div></div>
<div style="height: 2em">&nbsp;</div>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" id="paypal">
<input type="hidden" name="cmd" value="_s-xclick"/>
<input type="hidden" name="hosted_button_id" value="3FVHS5FGUY7CC"/>
</form>
</body>
</html>

30
codemirror/keymap/emacs.js vendored Normal file
View File

@ -0,0 +1,30 @@
// TODO number prefixes
(function() {
// Really primitive kill-ring implementation.
var killRing = [];
function addToRing(str) {
killRing.push(str);
if (killRing.length > 50) killRing.shift();
}
function getFromRing() { return killRing[killRing.length - 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());},
"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-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
fallthrough: ["basic", "emacsy"]
};
CodeMirror.keyMap["emacs-Ctrl-X"] = {
"Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
auto: "emacs", nofallthrough: true
};
})();

897
codemirror/keymap/vim.js vendored Normal file
View File

@ -0,0 +1,897 @@
// Supported keybindings:
//
// Cursor movement:
// h, j, k, l
// e, E, w, W, b, B
// Ctrl-f, Ctrl-b
// Ctrl-n, Ctrl-p
// $, ^, 0
// G
// ge, gE
// gg
// f<char>, F<char>, t<char>, T<char>
// Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
// /, ?, n, N TODO (does not work)
// #, * TODO
//
// Entering insert mode:
// i, I, a, A, o, O
// s
// ce, cb
// cc
// S, C TODO
// cf<char>, cF<char>, ct<char>, cT<char>
//
// Deleting text:
// x, X
// J
// dd, D
// de, db
// df<char>, dF<char>, dt<char>, dT<char>
//
// Yanking and pasting:
// yy, Y
// p, P
// p'<char> TODO - test
// y'<char> TODO - test
// m<char> TODO - test
//
// Changing text in place:
// ~
// r<char>
//
// Visual mode:
// v, V TODO
//
// Misc:
// . TODO
//
(function() {
var sdir = "f";
var buf = "";
var mark = {};
var repeatCount = 0;
function isLine(cm, line) { return line >= 0 && line < cm.lineCount(); }
function emptyBuffer() { buf = ""; }
function pushInBuffer(str) { buf += str; }
function pushRepeatCountDigit(digit) {return function(cm) {repeatCount = (repeatCount * 10) + digit}; }
function getCountOrOne() {
var i = repeatCount;
return i || 1;
}
function clearCount() {
repeatCount = 0;
}
function iterTimes(func) {
for (var i = 0, c = getCountOrOne(); i < c; ++i) func(i, i == c - 1);
clearCount();
}
function countTimes(func) {
if (typeof func == "string") func = CodeMirror.commands[func];
return function(cm) { iterTimes(function (i, last) { func(cm, i, last); }); };
}
function iterObj(o, f) {
for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
}
function iterList(l, f) {
for (var i = 0; i < l.length; ++i) f(l[i]);
}
function toLetter(ch) {
// T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
if (ch.slice(0, 6) == "Shift-") {
return ch.slice(0, 1);
} else {
if (ch == "Space") return " ";
if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
return ch.toLowerCase();
}
}
var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
function toCombo(ch) {
// t -> T, T -> Shift-T, * -> '*', " " -> "Space"
if (ch == " ") return "Space";
var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
if (specialIdx != -1) return "'" + ch + "'";
if (ch.toLowerCase() == ch) return ch.toUpperCase();
return "Shift-" + ch.toUpperCase();
}
var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
// Finds a word on the given line, and continue searching the next line if it can't find one.
function findWord(cm, lineNum, pos, dir, regexps) {
var line = cm.getLine(lineNum);
while (true) {
var stop = (dir > 0) ? line.length : -1;
var wordStart = stop, wordEnd = stop;
// Find bounds of next word.
for (; pos != stop; pos += dir) {
for (var i = 0; i < regexps.length; ++i) {
if (regexps[i].test(line.charAt(pos))) {
wordStart = pos;
// Advance to end of word.
for (; pos != stop && regexps[i].test(line.charAt(pos)); pos += dir) {}
wordEnd = (dir > 0) ? pos : pos + 1;
return {
from: Math.min(wordStart, wordEnd),
to: Math.max(wordStart, wordEnd),
line: lineNum};
}
}
}
// Advance to next/prev line.
lineNum += dir;
if (!isLine(cm, lineNum)) return null;
line = cm.getLine(lineNum);
pos = (dir > 0) ? 0 : line.length;
}
}
/**
* @param {boolean} cm CodeMirror object.
* @param {regexp} regexps Regular expressions for word characters.
* @param {number} dir Direction, +/- 1.
* @param {number} times Number of times to advance word.
* @param {string} where Go to "start" or "end" of word, 'e' vs 'w'.
* @param {boolean} yank Whether we are finding words to yank. If true,
* do not go to the next line to look for the last word. This is to
* prevent deleting new line on 'dw' at the end of a line.
*/
function moveToWord(cm, regexps, dir, times, where, yank) {
var cur = cm.getCursor();
if (yank) {
where = 'start';
}
for (var i = 0; i < times; i++) {
var startCh = cur.ch, startLine = cur.line, word;
while (true) {
// Search and advance.
word = findWord(cm, cur.line, cur.ch, dir, regexps);
if (word) {
if (yank && times == 1 && dir == 1 && cur.line != word.line) {
// Stop at end of line of last word. Don't want to delete line return
// for dw if the last deleted word is at the end of a line.
cur.ch = cm.getLine(cur.line).length;
break;
} else {
// 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 (dir > 0 && where == 'end') {
// 'e'
if (startCh != word.to - 1 || startLine != word.line) {
cur.ch = word.to - 1;
break;
} else {
cur.ch = word.to;
}
} else if (dir > 0 && where == 'start') {
// 'w'
if (startCh != word.from || startLine != word.line) {
cur.ch = word.from;
break;
} else {
cur.ch = word.to;
}
} else if (dir < 0 && where == 'end') {
// 'ge'
if (startCh != word.to || startLine != word.line) {
cur.ch = word.to;
break;
} else {
cur.ch = word.from - 1;
}
} else if (dir < 0 && where == 'start') {
// 'b'
if (startCh != word.from || startLine != word.line) {
cur.ch = word.from;
break;
} else {
cur.ch = word.from - 1;
}
}
}
} else {
// No more words to be found. Move to end of document.
for (; isLine(cm, cur.line + dir); cur.line += dir) {}
cur.ch = (dir > 0) ? cm.getLine(cur.line).length : 0;
break;
}
}
}
if (where == 'end' && yank) {
// Include the last character of the word for actions.
cur.ch++;
}
return cur;
}
function joinLineNext(cm) {
var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
CodeMirror.commands.goLineEnd(cm);
if (cur.line != cm.lineCount()) {
CodeMirror.commands.goLineEnd(cm);
cm.replaceSelection(" ", "end");
CodeMirror.commands.delCharRight(cm);
}
}
function delTillMark(cm, cHar) {
var i = mark[cHar];
if (i === undefined) {
// console.log("Mark not set"); // TODO - show in status bar
return;
}
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
cm.setCursor(start);
for (var c = start; c <= end; c++) {
pushInBuffer("\n" + cm.getLine(start));
cm.removeLine(start);
}
}
function yankTillMark(cm, cHar) {
var i = mark[cHar];
if (i === undefined) {
// console.log("Mark not set"); // TODO - show in status bar
return;
}
var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
for (var c = start; c <= end; c++) {
pushInBuffer("\n" + cm.getLine(c));
}
cm.setCursor(start);
}
function goLineStartText(cm) {
// Go to the start of the line where the text begins, or the end for whitespace-only lines
var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
}
function charIdxInLine(cm, cHar, motion_options) {
// Search for cHar in line.
// motion_options: {forward, inclusive}
// If inclusive = true, include it too.
// If forward = true, search forward, else search backwards.
// If char is not found on this line, do nothing
var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
var ch = toLetter(cHar), mo = motion_options;
if (mo.forward) {
idx = line.indexOf(ch, cur.ch + 1);
if (idx != -1 && mo.inclusive) idx += 1;
} else {
idx = line.lastIndexOf(ch, cur.ch);
if (idx != -1 && !mo.inclusive) idx += 1;
}
return idx;
}
function moveTillChar(cm, cHar, motion_options) {
// Move to cHar in line, as found by charIdxInLine.
var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
}
function delTillChar(cm, cHar, motion_options) {
// delete text in this line, untill cHar is met,
// as found by charIdxInLine.
// If char is not found on this line, do nothing
var idx = charIdxInLine(cm, cHar, motion_options);
var cur = cm.getCursor();
if (idx !== -1) {
if (motion_options.forward) {
cm.replaceRange("", {line: cur.line, ch: cur.ch}, {line: cur.line, ch: idx});
} else {
cm.replaceRange("", {line: cur.line, ch: idx}, {line: cur.line, ch: cur.ch});
}
}
}
function enterInsertMode(cm) {
// enter insert mode: switch mode and cursor
clearCount();
cm.setOption("keyMap", "vim-insert");
}
function dialog(cm, text, shortText, f) {
if (cm.openDialog) cm.openDialog(text, f);
else f(prompt(shortText, ""));
}
function showAlert(cm, text) {
var esc = text.replace(/[<&]/, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; });
if (cm.openDialog) cm.openDialog(esc + " <button type=button>OK</button>");
else alert(text);
}
// main keymap
var map = CodeMirror.keyMap.vim = {
// Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
"'|'": function(cm) {
cm.setCursor(cm.getCursor().line, getCountOrOne() - 1, true);
clearCount();
},
"A": function(cm) {
cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
enterInsertMode(cm);
},
"Shift-A": function(cm) { CodeMirror.commands.goLineEnd(cm); enterInsertMode(cm);},
"I": function(cm) { enterInsertMode(cm);},
"Shift-I": function(cm) { goLineStartText(cm); enterInsertMode(cm);},
"O": function(cm) {
CodeMirror.commands.goLineEnd(cm);
CodeMirror.commands.newlineAndIndent(cm);
enterInsertMode(cm);
},
"Shift-O": function(cm) {
CodeMirror.commands.goLineStart(cm);
cm.replaceSelection("\n", "start");
cm.indentLine(cm.getCursor().line);
enterInsertMode(cm);
},
"G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
"Shift-D": function(cm) {
var cursor = cm.getCursor();
var lineN = cursor.line;
var line = cm.getLine(lineN);
cm.setLine(lineN, line.slice(0, cursor.ch));
emptyBuffer();
pushInBuffer(line.slice(cursor.ch));
if (repeatCount > 1) {
// we've already done it once
--repeatCount;
// the lines dissapear (ie, cursor stays on the same lineN),
// so only incremenet once
++lineN;
iterTimes(function() {
pushInBuffer(cm.getLine(lineN));
cm.removeLine(lineN);
});
}
},
"S": function (cm) {
countTimes(function (_cm) {
CodeMirror.commands.delCharRight(_cm);
})(cm);
enterInsertMode(cm);
},
"M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = {};},
"Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer();},
"Shift-Y": function(cm) {
emptyBuffer();
iterTimes(function(i) { pushInBuffer("\n" + cm.getLine(cm.getCursor().line + i)); });
},
"/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
"'?'": function(cm) {
var f = CodeMirror.commands.find;
if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; }
},
"N": function(cm) {
var fn = CodeMirror.commands.findNext;
if (fn) sdir != "r" ? fn(cm) : CodeMirror.commands.findPrev(cm);
},
"Shift-N": function(cm) {
var fn = CodeMirror.commands.findNext;
if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
},
"Shift-G": function(cm) {
(repeatCount == 0) ? cm.setCursor(cm.lineCount()) : cm.setCursor(repeatCount - 1);
clearCount();
CodeMirror.commands.goLineStart(cm);
},
"':'": function(cm) {
var exModeDialog = ': <input type="text" style="width: 90%"/>';
dialog(cm, exModeDialog, ':', function(command) {
if (command.match(/^\d+$/)) {
cm.setCursor(command - 1, cm.getCursor().ch);
} else {
showAlert(cm, "Bad command: " + command);
}
});
},
nofallthrough: true, style: "fat-cursor"
};
// standard mode switching
iterList(["d", "t", "T", "f", "F", "c", "r"], function (ch) {
CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
cm.setOption("keyMap", "vim-prefix-" + ch);
emptyBuffer();
};
});
// main num keymap
// Add bindings that are influenced by number keys
iterObj({
"X": function(cm) {CodeMirror.commands.delCharRight(cm);},
"P": function(cm) {
var cur = cm.getCursor().line;
if (buf!= "") {
if (buf[0] == "\n") CodeMirror.commands.goLineEnd(cm);
cm.replaceRange(buf, cm.getCursor());
}
},
"Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm);},
"Shift-J": function(cm) {joinLineNext(cm);},
"Shift-P": function(cm) {
var cur = cm.getCursor().line;
if (buf!= "") {
CodeMirror.commands.goLineUp(cm);
CodeMirror.commands.goLineEnd(cm);
cm.replaceSelection(buf, "end");
}
cm.setCursor(cur+1);
},
"'~'": function(cm) {
var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
cm.setCursor(cur.line, cur.ch+1);
},
"Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm);},
"Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm);},
"Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
"U": "undo", "Ctrl-R": "redo"
}, function(key, cmd) { map[key] = countTimes(cmd); });
// empty key maps
iterList([
"vim-prefix-d'",
"vim-prefix-y'",
"vim-prefix-df",
"vim-prefix-dF",
"vim-prefix-dt",
"vim-prefix-dT",
"vim-prefix-c",
"vim-prefix-cf",
"vim-prefix-cF",
"vim-prefix-ct",
"vim-prefix-cT",
"vim-prefix-",
"vim-prefix-f",
"vim-prefix-F",
"vim-prefix-t",
"vim-prefix-T",
"vim-prefix-r",
"vim-prefix-m"
],
function (prefix) {
CodeMirror.keyMap[prefix] = {
auto: "vim",
nofallthrough: true,
style: "fat-cursor"
};
});
CodeMirror.keyMap["vim-prefix-g"] = {
"E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "end"));}),
"Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "end"));}),
"G": function (cm) {
cm.setCursor({line: repeatCount - 1, ch: cm.getCursor().ch});
clearCount();
},
auto: "vim", nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap["vim-prefix-d"] = {
"D": countTimes(function(cm) {
pushInBuffer("\n" + cm.getLine(cm.getCursor().line));
cm.removeLine(cm.getCursor().line);
cm.setOption("keyMap", "vim");
}),
"'": function(cm) {
cm.setOption("keyMap", "vim-prefix-d'");
emptyBuffer();
},
"B": function(cm) {
var cur = cm.getCursor();
var line = cm.getLine(cur.line);
var index = line.lastIndexOf(" ", cur.ch);
pushInBuffer(line.substring(index, cur.ch));
cm.replaceRange("", {line: cur.line, ch: index}, cur);
cm.setOption("keyMap", "vim");
},
nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap["vim-prefix-c"] = {
"B": function (cm) {
countTimes("delWordLeft")(cm);
enterInsertMode(cm);
},
"C": function (cm) {
iterTimes(function (i, last) {
CodeMirror.commands.deleteLine(cm);
if (i) {
CodeMirror.commands.delCharRight(cm);
if (last) CodeMirror.commands.deleteLine(cm);
}
});
enterInsertMode(cm);
},
nofallthrough: true, style: "fat-cursor"
};
iterList(["vim-prefix-d", "vim-prefix-c", "vim-prefix-"], function (prefix) {
iterList(["f", "F", "T", "t"],
function (ch) {
CodeMirror.keyMap[prefix][toCombo(ch)] = function (cm) {
cm.setOption("keyMap", prefix + ch);
emptyBuffer();
};
});
});
var MOTION_OPTIONS = {
"t": {inclusive: false, forward: true},
"f": {inclusive: true, forward: true},
"T": {inclusive: false, forward: false},
"F": {inclusive: true, forward: false}
};
function setupPrefixBindingForKey(m) {
CodeMirror.keyMap["vim-prefix-m"][m] = function(cm) {
mark[m] = cm.getCursor().line;
};
CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
delTillMark(cm, m);
};
CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
yankTillMark(cm, m);
};
CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
var cur = cm.getCursor();
cm.replaceRange(toLetter(m),
{line: cur.line, ch: cur.ch},
{line: cur.line, ch: cur.ch + 1});
CodeMirror.commands.goColumnLeft(cm);
};
// all commands, related to motions till char in line
iterObj(MOTION_OPTIONS, function (ch, options) {
CodeMirror.keyMap["vim-prefix-" + ch][m] = function(cm) {
moveTillChar(cm, m, options);
};
CodeMirror.keyMap["vim-prefix-d" + ch][m] = function(cm) {
delTillChar(cm, m, options);
};
CodeMirror.keyMap["vim-prefix-c" + ch][m] = function(cm) {
delTillChar(cm, m, options);
enterInsertMode(cm);
};
});
}
for (var i = 65; i < 65 + 26; i++) { // uppercase alphabet char codes
var ch = String.fromCharCode(i);
setupPrefixBindingForKey(toCombo(ch));
setupPrefixBindingForKey(toCombo(ch.toLowerCase()));
}
for (var i = 0; i < SPECIAL_SYMBOLS.length; ++i) {
setupPrefixBindingForKey(toCombo(SPECIAL_SYMBOLS.charAt(i)));
}
setupPrefixBindingForKey("Space");
CodeMirror.keyMap["vim-prefix-y"] = {
"Y": countTimes(function(cm, i, last) {
pushInBuffer("\n" + cm.getLine(cm.getCursor().line + i));
cm.setOption("keyMap", "vim");
}),
"'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap["vim-insert"] = {
// TODO: override navigation keys so that Esc will cancel automatic indentation from o, O, i_<CR>
"Esc": function(cm) {
cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
cm.setOption("keyMap", "vim");
},
"Ctrl-N": "autocomplete",
"Ctrl-P": "autocomplete",
fallthrough: ["default"]
};
function findMatchedSymbol(cm, cur, symb) {
var line = cur.line;
var symb = symb ? symb : cm.getLine(line)[cur.ch];
// Are we at the opening or closing char
var forwards = ['(', '[', '{'].indexOf(symb) != -1;
var reverseSymb = (function(sym) {
switch (sym) {
case '(' : return ')';
case '[' : return ']';
case '{' : return '}';
case ')' : return '(';
case ']' : return '[';
case '}' : return '{';
default : return null;
}
})(symb);
// Couldn't find a matching symbol, abort
if (reverseSymb == null) return cur;
// Tracking our imbalance in open/closing symbols. An opening symbol wii be
// the first thing we pick up if moving forward, this isn't true moving backwards
var disBal = forwards ? 0 : 1;
while (true) {
if (line == cur.line) {
// First pass, do some special stuff
var currLine = forwards ? cm.getLine(line).substr(cur.ch).split('') : cm.getLine(line).substr(0,cur.ch).split('').reverse();
} else {
var currLine = forwards ? cm.getLine(line).split('') : cm.getLine(line).split('').reverse();
}
for (var index = 0; index < currLine.length; index++) {
if (currLine[index] == symb) disBal++;
else if (currLine[index] == reverseSymb) disBal--;
if (disBal == 0) {
if (forwards && cur.line == line) return {line: line, ch: index + cur.ch};
else if (forwards) return {line: line, ch: index};
else return {line: line, ch: currLine.length - index - 1 };
}
}
if (forwards) line++;
else line--;
}
}
function selectCompanionObject(cm, revSymb, inclusive) {
var cur = cm.getCursor();
var end = findMatchedSymbol(cm, cur, revSymb);
var start = findMatchedSymbol(cm, end);
start.ch += inclusive ? 1 : 0;
end.ch += inclusive ? 0 : 1;
return {start: start, end: end};
}
// 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
function findBeginningAndEnd(cm, symb, inclusive) {
var cur = cm.getCursor();
var line = cm.getLine(cur.line);
var chars = line.split('');
var start = undefined;
var end = undefined;
var firstIndex = chars.indexOf(symb);
// the decision tree is to always look backwards for the beginning first,
// but if the cursor is in front of the first instance of the symb,
// then move the cursor forward
if (cur.ch < firstIndex) {
cur.ch = firstIndex;
cm.setCursor(cur.line, firstIndex+1);
}
// otherwise if the cursor is currently on the closing symbol
else if (firstIndex < cur.ch && chars[cur.ch] == symb) {
end = cur.ch; // assign end to the current cursor
--cur.ch; // make sure to look backwards
}
// if we're currently on the symbol, we've got a start
if (chars[cur.ch] == symb && end == null)
start = cur.ch + 1; // assign start to ahead of the cursor
else {
// go backwards to find the start
for (var i = cur.ch; i > -1 && start == null; i--)
if (chars[i] == symb) start = i + 1;
}
// look forwards for the end symbol
if (start != null && end == null) {
for (var i = start, len = chars.length; i < len && end == null; i++) {
if (chars[i] == symb) end = i;
}
}
// nothing found
// FIXME still enters insert mode
if (start == null || end == null) return {
start: cur, end: cur
};
// include the symbols
if (inclusive) {
--start; ++end;
}
return {
start: {line: cur.line, ch: start},
end: {line: cur.line, ch: end}
};
}
function offsetCursor(cm, line, ch) {
var cur = cm.getCursor(); return {line: cur.line + line, ch: cur.ch + ch};
}
// These are the motion commands we use for navigation and selection with
// certain other commands. All should return a cursor object.
var motions = {
"J": function(cm, times) { return offsetCursor(cm, times, 0); },
"Down": function(cm, times) { return offsetCursor(cm, times, 0); },
"K": function(cm, times) { return offsetCursor(cm, -times, 0); },
"Up": function(cm, times) { return offsetCursor(cm, -times, 0); },
"L": function(cm, times) { return offsetCursor(cm, 0, times); },
"Right": function(cm, times) { return offsetCursor(cm, 0, times); },
"Space": function(cm, times) { return offsetCursor(cm, 0, times); },
"H": function(cm, times) { return offsetCursor(cm, 0, -times); },
"Left": function(cm, times) { return offsetCursor(cm, 0, -times); },
"Backspace": function(cm, times) { return offsetCursor(cm, 0, -times); },
"B": function(cm, times, yank) { return moveToWord(cm, word, -1, times, 'start', yank); },
"Shift-B": function(cm, times, yank) { return moveToWord(cm, bigWord, -1, times, 'start', yank); },
"E": function(cm, times, yank) { return moveToWord(cm, word, 1, times, 'end', yank); },
"Shift-E": function(cm, times, yank) { return moveToWord(cm, bigWord, 1, times, 'end', yank); },
"W": function(cm, times, yank) { return moveToWord(cm, word, 1, times, 'start', yank); },
"Shift-W": function(cm, times, yank) { return moveToWord(cm, bigWord, 1, times, 'start', yank); },
"'^'": function(cm, times) {
var cur = cm.getCursor(), line = cm.getLine(cur.line).split('');
for (var i = 0; i < line.length; i++) {
if (line[i].match(/[^\s]/)) return {line: cur.line, ch: index};
}
return cur;
},
"'$'": function(cm) {
var cur = cm.getCursor(), ch = cm.getLine(cur.line).length;
return {line: cur.line, ch: ch};
},
"'%'": function(cm) { return findMatchedSymbol(cm, cm.getCursor()); },
"Esc" : function(cm) { cm.setOption("keyMap", "vim"); repeatCount = 0; return cm.getCursor(); }
};
// Map our movement actions each operator and non-operational movement
iterObj(motions, function(key, motion) {
CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
// Get our selected range
var start = cm.getCursor();
var end = motion(cm, repeatCount ? repeatCount : 1, true);
// Set swap var if range is of negative length
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
// Take action, switching start and end if swap var is set
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
cm.replaceRange("", swap ? end : start, swap ? start : end);
// And clean up
repeatCount = 0;
cm.setOption("keyMap", "vim");
};
CodeMirror.keyMap['vim-prefix-c'][key] = function(cm) {
var start = cm.getCursor();
var end = motion(cm, repeatCount ? repeatCount : 1, true);
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
cm.replaceRange("", swap ? end : start, swap ? start : end);
repeatCount = 0;
cm.setOption('keyMap', 'vim-insert');
};
CodeMirror.keyMap['vim-prefix-y'][key] = function(cm) {
var start = cm.getCursor();
var end = motion(cm, repeatCount ? repeatCount : 1, true);
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
repeatCount = 0;
cm.setOption("keyMap", "vim");
};
CodeMirror.keyMap['vim'][key] = function(cm) {
var cur = motion(cm, repeatCount ? repeatCount : 1);
cm.setCursor(cur.line, cur.ch);
repeatCount = 0;
};
});
function addCountBindings(keyMapName) {
// Add bindings for number keys
keyMap = CodeMirror.keyMap[keyMapName];
keyMap["0"] = function(cm) {
if (repeatCount > 0) {
pushRepeatCountDigit(0)(cm);
} else {
CodeMirror.commands.goLineStart(cm);
}
};
for (var i = 1; i < 10; ++i) {
keyMap[i] = pushRepeatCountDigit(i);
}
}
addCountBindings('vim');
addCountBindings('vim-prefix-d');
addCountBindings('vim-prefix-y');
addCountBindings('vim-prefix-c');
// Create our keymaps for each operator and make xa and xi where x is an operator
// change to the corrosponding keymap
var operators = ['d', 'y', 'c'];
iterList(operators, function(key, index, array) {
CodeMirror.keyMap['vim-prefix-'+key+'a'] = {
auto: 'vim', nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap['vim-prefix-'+key+'i'] = {
auto: 'vim', nofallthrough: true, style: "fat-cursor"
};
CodeMirror.keyMap['vim-prefix-'+key]['A'] = function(cm) {
repeatCount = 0;
cm.setOption('keyMap', 'vim-prefix-' + key + 'a');
};
CodeMirror.keyMap['vim-prefix-'+key]['I'] = function(cm) {
repeatCount = 0;
cm.setOption('keyMap', 'vim-prefix-' + key + 'i');
};
});
function regexLastIndexOf(string, pattern, startIndex) {
for (var i = startIndex == null ? string.length : startIndex; i >= 0; --i)
if (pattern.test(string.charAt(i))) return i;
return -1;
}
// Create our text object functions. They work similar to motions but they
// return a start cursor as well
var textObjectList = ['W', 'Shift-[', 'Shift-9', '[', "'", "Shift-'"];
var textObjects = {
'W': function(cm, inclusive) {
var cur = cm.getCursor();
var line = cm.getLine(cur.line);
var line_to_char = new String(line.substring(0, cur.ch));
var start = regexLastIndexOf(line_to_char, /[^a-zA-Z0-9]/) + 1;
var end = motions["E"](cm, 1) ;
end.ch += inclusive ? 1 : 0 ;
return {start: {line: cur.line, ch: start}, end: end };
},
'Shift-[': function(cm, inclusive) { return selectCompanionObject(cm, '}', inclusive); },
'Shift-9': function(cm, inclusive) { return selectCompanionObject(cm, ')', inclusive); },
'[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); },
"'": function(cm, inclusive) { return findBeginningAndEnd(cm, "'", inclusive); },
"Shift-'": function(cm, inclusive) { return findBeginningAndEnd(cm, '"', inclusive); }
};
// One function to handle all operation upon text objects. Kinda funky but it works
// better than rewriting this code six times
function textObjectManipulation(cm, object, remove, insert, inclusive) {
// Object is the text object, delete object if remove is true, enter insert
// mode if insert is true, inclusive is the difference between a and i
var tmp = textObjects[object](cm, inclusive);
var start = tmp.start;
var end = tmp.end;
if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true ;
pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
if (remove) cm.replaceRange("", swap ? end : start, swap ? start : end);
if (insert) cm.setOption('keyMap', 'vim-insert');
}
// And finally build the keymaps up from the text objects
for (var i = 0; i < textObjectList.length; ++i) {
var object = textObjectList[i];
(function(object) {
CodeMirror.keyMap['vim-prefix-di'][object] = function(cm) { textObjectManipulation(cm, object, true, false, false); };
CodeMirror.keyMap['vim-prefix-da'][object] = function(cm) { textObjectManipulation(cm, object, true, false, true); };
CodeMirror.keyMap['vim-prefix-yi'][object] = function(cm) { textObjectManipulation(cm, object, false, false, false); };
CodeMirror.keyMap['vim-prefix-ya'][object] = function(cm) { textObjectManipulation(cm, object, false, false, true); };
CodeMirror.keyMap['vim-prefix-ci'][object] = function(cm) { textObjectManipulation(cm, object, true, true, false); };
CodeMirror.keyMap['vim-prefix-ca'][object] = function(cm) { textObjectManipulation(cm, object, true, true, true); };
})(object)
}
})();

174
codemirror/lib/codemirror.css vendored Normal file
View File

@ -0,0 +1,174 @@
.CodeMirror {
line-height: 1em;
font-family: monospace;
/* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
position: relative;
/* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
overflow: hidden;
}
.CodeMirror-scroll {
overflow: auto;
height: 300px;
/* This is needed to prevent an IE[67] bug where the scrolled content
is visible outside of the scrolling box. */
position: relative;
outline: none;
}
/* Vertical scrollbar */
.CodeMirror-scrollbar {
position: absolute;
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
z-index: 5;
}
.CodeMirror-scrollbar-inner {
/* This needs to have a nonzero width in order for the scrollbar to appear
in Firefox and IE9. */
width: 1px;
}
.CodeMirror-scrollbar.cm-sb-overlap {
/* Ensure that the scrollbar appears in Lion, and that it overlaps the content
rather than sitting to the right of it. */
position: absolute;
z-index: 1;
float: none;
right: 0;
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-nonoverlap {
min-width: 12px;
}
.CodeMirror-scrollbar.cm-sb-ie7 {
min-width: 18px;
}
.CodeMirror-gutter {
position: absolute; left: 0; top: 0;
z-index: 10;
background-color: #f7f7f7;
border-right: 1px solid #eee;
min-width: 2em;
height: 100%;
}
.CodeMirror-gutter-text {
color: #aaa;
text-align: right;
padding: .4em .2em .4em .4em;
white-space: pre !important;
cursor: default;
}
.CodeMirror-lines {
padding: .4em;
white-space: pre;
cursor: text;
}
.CodeMirror pre {
-moz-border-radius: 0;
-webkit-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
border-width: 0; margin: 0; padding: 0; background: transparent;
font-family: inherit;
font-size: inherit;
padding: 0; margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror textarea {
outline: none !important;
}
.CodeMirror pre.CodeMirror-cursor {
z-index: 10;
position: absolute;
visibility: hidden;
border-left: 1px solid black;
border-right: none;
width: 0;
}
.cm-keymap-fat-cursor pre.CodeMirror-cursor {
width: auto;
border: 0;
background: transparent;
background: rgba(0, 200, 0, .4);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
}
/* Kludge to turn off filter in ie9+, which also accepts rgba */
.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
}
.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
.CodeMirror-focused pre.CodeMirror-cursor {
visibility: visible;
}
div.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* Default theme */
.cm-s-default span.cm-keyword {color: #708;}
.cm-s-default span.cm-atom {color: #219;}
.cm-s-default span.cm-number {color: #164;}
.cm-s-default span.cm-def {color: #00f;}
.cm-s-default span.cm-variable {color: black;}
.cm-s-default span.cm-variable-2 {color: #05a;}
.cm-s-default span.cm-variable-3 {color: #085;}
.cm-s-default span.cm-property {color: black;}
.cm-s-default span.cm-operator {color: black;}
.cm-s-default span.cm-comment {color: #a50;}
.cm-s-default span.cm-string {color: #a11;}
.cm-s-default span.cm-string-2 {color: #f50;}
.cm-s-default span.cm-meta {color: #555;}
.cm-s-default span.cm-error {color: #f00;}
.cm-s-default span.cm-qualifier {color: #555;}
.cm-s-default span.cm-builtin {color: #30a;}
.cm-s-default span.cm-bracket {color: #997;}
.cm-s-default span.cm-tag {color: #170;}
.cm-s-default span.cm-attribute {color: #00c;}
.cm-s-default span.cm-header {color: blue;}
.cm-s-default span.cm-quote {color: #090;}
.cm-s-default span.cm-hr {color: #999;}
.cm-s-default span.cm-link {color: #00c;}
span.cm-header, span.cm-strong {font-weight: bold;}
span.cm-em {font-style: italic;}
span.cm-emstrong {font-style: italic; font-weight: bold;}
span.cm-link {text-decoration: underline;}
span.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
@media print {
/* Hide the cursor when printing */
.CodeMirror pre.CodeMirror-cursor {
visibility: hidden;
}
}

3171
codemirror/lib/codemirror.js vendored Normal file

File diff suppressed because it is too large Load Diff

164
codemirror/lib/util/closetag.js vendored Normal file
View File

@ -0,0 +1,164 @@
/**
* Tag-closer extension for CodeMirror.
*
* This extension adds a "closeTag" utility function that can be used with key bindings to
* insert a matching end tag after the ">" character of a start tag has been typed. It can
* also complete "</" if a matching start tag is found. It will correctly ignore signal
* characters for empty tags, comments, CDATA, etc.
*
* The function depends on internal parser state to identify tags. It is compatible with the
* following CodeMirror modes and will ignore all others:
* - htmlmixed
* - xml
*
* See demos/closetag.html for a usage example.
*
* @author Nathan Williams <nathan@nlwillia.net>
* Contributed under the same license terms as CodeMirror.
*/
(function() {
/** Option that allows tag closing behavior to be toggled. Default is true. */
CodeMirror.defaults['closeTagEnabled'] = true;
/** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
CodeMirror.defaults['closeTagIndent'] = ['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'];
/** Array of tag names where an end tag is forbidden. */
CodeMirror.defaults['closeTagVoid'] = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
function innerState(cm, state) {
return CodeMirror.innerMode(cm.getMode(), state).state;
}
/**
* Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
* - cm: The editor instance.
* - ch: The character being processed.
* - indent: Optional. An array of tag names to indent when closing. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
* Pass false to disable indentation. Pass an array to override the default list of tag names.
* - vd: Optional. An array of tag names that should not be closed. Omit to use the default void (end tag forbidden) tag list defined in the 'closeTagVoid' option. Ignored in xml mode.
*/
CodeMirror.defineExtension("closeTag", function(cm, ch, indent, vd) {
if (!cm.getOption('closeTagEnabled')) {
throw CodeMirror.Pass;
}
/*
* Relevant structure of token:
*
* htmlmixed
* className
* state
* htmlState
* type
* tagName
* context
* tagName
* mode
*
* xml
* className
* state
* tagName
* type
*/
var pos = cm.getCursor();
var tok = cm.getTokenAt(pos);
var state = innerState(cm, tok.state);
if (state) {
if (ch == '>') {
var type = state.type;
if (tok.className == 'tag' && type == 'closeTag') {
throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
}
cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
pos = {line: pos.line, ch: pos.ch + 1};
cm.setCursor(pos);
tok = cm.getTokenAt(cm.getCursor());
state = innerState(cm, tok.state);
if (!state) throw CodeMirror.Pass;
var type = state.type;
if (tok.className == 'tag' && type != 'selfcloseTag') {
var tagName = state.tagName;
if (tagName.length > 0 && shouldClose(cm, vd, tagName)) {
insertEndTag(cm, indent, pos, tagName);
}
return;
}
// Undo the '>' insert and allow cm to handle the key instead.
cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
cm.replaceSelection("");
} else if (ch == '/') {
if (tok.className == 'tag' && tok.string == '<') {
var ctx = state.context, tagName = ctx ? ctx.tagName : '';
if (tagName.length > 0) {
completeEndTag(cm, pos, tagName);
return;
}
}
}
}
throw CodeMirror.Pass; // Bubble if not handled
});
function insertEndTag(cm, indent, pos, tagName) {
if (shouldIndent(cm, indent, tagName)) {
cm.replaceSelection('\n\n</' + tagName + '>', 'end');
cm.indentLine(pos.line + 1);
cm.indentLine(pos.line + 2);
cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
} else {
cm.replaceSelection('</' + tagName + '>');
cm.setCursor(pos);
}
}
function shouldIndent(cm, indent, tagName) {
if (typeof indent == 'undefined' || indent == null || indent == true) {
indent = cm.getOption('closeTagIndent');
}
if (!indent) {
indent = [];
}
return indexOf(indent, tagName.toLowerCase()) != -1;
}
function shouldClose(cm, vd, tagName) {
if (cm.getOption('mode') == 'xml') {
return true; // always close xml tags
}
if (typeof vd == 'undefined' || vd == null) {
vd = cm.getOption('closeTagVoid');
}
if (!vd) {
vd = [];
}
return indexOf(vd, tagName.toLowerCase()) == -1;
}
// C&P from codemirror.js...would be nice if this were visible to utilities.
function indexOf(collection, elt) {
if (collection.indexOf) return collection.indexOf(elt);
for (var i = 0, e = collection.length; i < e; ++i)
if (collection[i] == elt) return i;
return -1;
}
function completeEndTag(cm, pos, tagName) {
cm.replaceSelection('/' + tagName + '>');
cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
}
})();

36
codemirror/lib/util/continuecomment.js vendored Normal file
View File

@ -0,0 +1,36 @@
(function() {
var modes = ["clike", "css", "javascript"];
for (var i = 0; i < modes.length; ++i)
CodeMirror.extendMode(modes[i], {blockCommentStart: "/*",
blockCommentEnd: "*/",
blockCommentContinue: " * "});
CodeMirror.commands.newlineAndIndentContinueComment = function(cm) {
var pos = cm.getCursor(), token = cm.getTokenAt(pos);
var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode;
var space;
if (token.className == "comment" && mode.blockCommentStart) {
var end = token.string.indexOf(mode.blockCommentEnd);
var full = cm.getRange({line: pos.line, ch: 0}, {line: pos.line, ch: 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
cm.execCommand("newlineAndIndent");
};
})();

27
codemirror/lib/util/dialog.css vendored Normal file
View File

@ -0,0 +1,27 @@
.CodeMirror-dialog {
position: relative;
}
.CodeMirror-dialog > div {
position: absolute;
top: 0; left: 0; right: 0;
background: white;
border-bottom: 1px solid #eee;
z-index: 15;
padding: .1em .8em;
overflow: hidden;
color: #333;
}
.CodeMirror-dialog input {
border: none;
outline: none;
background: transparent;
width: 20em;
color: inherit;
font-family: monospace;
}
.CodeMirror-dialog button {
font-size: 70%;
}

70
codemirror/lib/util/dialog.js vendored Normal file
View File

@ -0,0 +1,70 @@
// Open simple dialogs on top of an editor. Relies on dialog.css.
(function() {
function dialogDiv(cm, template) {
var wrap = cm.getWrapperElement();
var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
dialog.className = "CodeMirror-dialog";
dialog.innerHTML = '<div>' + template + '</div>';
return dialog;
}
CodeMirror.defineExtension("openDialog", function(template, callback) {
var dialog = dialogDiv(this, template);
var closed = false, me = this;
function close() {
if (closed) return;
closed = true;
dialog.parentNode.removeChild(dialog);
}
var inp = dialog.getElementsByTagName("input")[0], button;
if (inp) {
CodeMirror.connect(inp, "keydown", function(e) {
if (e.keyCode == 13 || e.keyCode == 27) {
CodeMirror.e_stop(e);
close();
me.focus();
if (e.keyCode == 13) callback(inp.value);
}
});
inp.focus();
CodeMirror.connect(inp, "blur", close);
} else if (button = dialog.getElementsByTagName("button")[0]) {
CodeMirror.connect(button, "click", function() {
close();
me.focus();
});
button.focus();
CodeMirror.connect(button, "blur", close);
}
return close;
});
CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
var dialog = dialogDiv(this, template);
var buttons = dialog.getElementsByTagName("button");
var closed = false, me = this, blurring = 1;
function close() {
if (closed) return;
closed = true;
dialog.parentNode.removeChild(dialog);
me.focus();
}
buttons[0].focus();
for (var i = 0; i < buttons.length; ++i) {
var b = buttons[i];
(function(callback) {
CodeMirror.connect(b, "click", function(e) {
CodeMirror.e_preventDefault(e);
close();
if (callback) callback(me);
});
})(callbacks[i]);
CodeMirror.connect(b, "blur", function() {
--blurring;
setTimeout(function() { if (blurring <= 0) close(); }, 200);
});
CodeMirror.connect(b, "focus", function() { ++blurring; });
}
});
})();

196
codemirror/lib/util/foldcode.js vendored Normal file
View File

@ -0,0 +1,196 @@
// the tagRangeFinder function is
// Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
// released under the MIT license (../../LICENSE) like the rest of CodeMirror
CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
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 xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
var lineText = cm.getLine(line);
var found = false;
var tag = null;
var pos = 0;
while (!found) {
pos = lineText.indexOf("<", pos);
if (-1 == pos) // no tag on line
return;
if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
pos++;
continue;
}
// ok we weem to have a start tag
if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
pos++;
continue;
}
var gtPos = lineText.indexOf(">", pos + 1);
if (-1 == gtPos) { // end of start tag not in line
var l = line + 1;
var foundGt = false;
var lastLine = cm.lineCount();
while (l < lastLine && !foundGt) {
var lt = cm.getLine(l);
var gt = lt.indexOf(">");
if (-1 != gt) { // found a >
foundGt = true;
var slash = lt.lastIndexOf("/", gt);
if (-1 != slash && slash < gt) {
var str = lineText.substr(slash, gt - slash + 1);
if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
if (hideEnd === true) l++;
return l;
}
}
}
l++;
}
found = true;
}
else {
var slashPos = lineText.lastIndexOf("/", gtPos);
if (-1 == slashPos) { // cannot be empty tag
found = true;
// don't continue
}
else { // empty tag?
// check if really empty tag
var str = lineText.substr(slashPos, gtPos - slashPos + 1);
if (!str.match( /\/\s*\>/ )) { // finally not empty
found = true;
// don't continue
}
}
}
if (found) {
var subLine = lineText.substr(pos + 1);
tag = subLine.match(xmlNAMERegExp);
if (tag) {
// we have an element name, wooohooo !
tag = tag[0];
// do we have the close tag on same line ???
if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
{
found = false;
}
// we don't, so we have a candidate...
}
else
found = false;
}
if (!found)
pos++;
}
if (found) {
var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
var startTagRegExp = new RegExp(startTag, "g");
var endTag = "</" + tag + ">";
var depth = 1;
var l = line + 1;
var lastLine = cm.lineCount();
while (l < lastLine) {
lineText = cm.getLine(l);
var match = lineText.match(startTagRegExp);
if (match) {
for (var i = 0; i < match.length; i++) {
if (match[i] == endTag)
depth--;
else
depth++;
if (!depth) {
if (hideEnd === true) l++;
return l;
}
}
}
l++;
}
return;
}
};
CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
for (;;) {
var found = lineText.lastIndexOf("{", at);
if (found < 0) break;
tokenType = cm.getTokenAt({line: line, ch: found}).className;
if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
at = found - 1;
}
if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
var count = 1, lastLine = cm.lineCount(), end;
outer: for (var i = line + 1; i < lastLine; ++i) {
var text = cm.getLine(i), pos = 0;
for (;;) {
var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", 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({line: i, ch: pos + 1}).className == tokenType) {
if (pos == nextOpen) ++count;
else if (!--count) { end = i; break outer; }
}
++pos;
}
}
if (end == null || end == line + 1) return;
if (hideEnd === true) end++;
return end;
};
CodeMirror.indentRangeFinder = function(cm, line) {
var tabSize = cm.getOption("tabSize");
var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
var handle = cm.getLineHandle(i);
if (!/^\s*$/.test(handle.text)) {
if (handle.indentation(tabSize) <= myIndent) break;
last = i;
}
}
if (!last) return null;
return last + 1;
};
CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
var folded = [];
if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
function isFolded(cm, n) {
for (var i = 0; i < folded.length; ++i) {
var start = cm.lineInfo(folded[i].start);
if (!start) folded.splice(i--, 1);
else if (start.line == n) return {pos: i, region: folded[i]};
}
}
function expand(cm, region) {
cm.clearMarker(region.start);
for (var i = 0; i < region.hidden.length; ++i)
cm.showLine(region.hidden[i]);
}
return function(cm, line) {
cm.operation(function() {
var known = isFolded(cm, line);
if (known) {
folded.splice(known.pos, 1);
expand(cm, known.region);
} else {
var end = rangeFinder(cm, line, hideEnd);
if (end == null) return;
var hidden = [];
for (var i = line + 1; i < end; ++i) {
var handle = cm.hideLine(i);
if (handle) hidden.push(handle);
}
var first = cm.setMarker(line, markText);
var region = {start: first, hidden: hidden};
cm.onDeleteLine(first, function() { expand(cm, region); });
folded.push(region);
}
});
};
};

196
codemirror/lib/util/formatting.js vendored Normal file
View File

@ -0,0 +1,196 @@
// ============== Formatting extensions ============================
(function() {
// Define extensions for a few modes
CodeMirror.extendMode("css", {
commentStart: "/*",
commentEnd: "*/",
wordWrapChars: [";", "\\{", "\\}"],
autoFormatLineBreaks: function (text) {
return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
}
});
function jsNonBreakableBlocks(text) {
var nonBreakableRegexes = [/for\s*?\((.*?)\)/,
/\"(.*?)(\"|$)/,
/\'(.*?)(\'|$)/,
/\/\*(.*?)(\*\/|$)/,
/\/\/.*/];
var nonBreakableBlocks = [];
for (var i = 0; i < nonBreakableRegexes.length; i++) {
var curPos = 0;
while (curPos < text.length) {
var m = text.substr(curPos).match(nonBreakableRegexes[i]);
if (m != null) {
nonBreakableBlocks.push({
start: curPos + m.index,
end: curPos + m.index + m[0].length
});
curPos += m.index + Math.max(1, m[0].length);
}
else { // No more matches
break;
}
}
}
nonBreakableBlocks.sort(function (a, b) {
return a.start - b.start;
});
return nonBreakableBlocks;
}
CodeMirror.extendMode("javascript", {
commentStart: "/*",
commentEnd: "*/",
wordWrapChars: [";", "\\{", "\\}"],
autoFormatLineBreaks: function (text) {
var curPos = 0;
var split = this.jsonMode ? function(str) {
return str.replace(/([,{])/g, "$1\n").replace(/}/g, "\n}");
} : function(str) {
return str.replace(/(;|\{|\})([^\r\n;])/g, "$1\n$2");
};
var nonBreakableBlocks = jsNonBreakableBlocks(text), res = "";
if (nonBreakableBlocks != null) {
for (var i = 0; i < nonBreakableBlocks.length; i++) {
if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
res += split(text.substring(curPos, nonBreakableBlocks[i].start));
curPos = nonBreakableBlocks[i].start;
}
if (nonBreakableBlocks[i].start <= curPos
&& nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
res += text.substring(curPos, nonBreakableBlocks[i].end);
curPos = nonBreakableBlocks[i].end;
}
}
if (curPos < text.length)
res += split(text.substr(curPos));
} else {
res = split(text);
}
return res.replace(/^\n*|\n*$/, "");
}
});
CodeMirror.extendMode("xml", {
commentStart: "<!--",
commentEnd: "-->",
wordWrapChars: [">"],
autoFormatLineBreaks: function (text) {
var lines = text.split("\n");
var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
var reOpenBrackets = new RegExp("<", "g");
var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
for (var i = 0; i < lines.length; i++) {
var mToProcess = lines[i].match(reProcessedPortion);
if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
lines[i] = mToProcess[1]
+ mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
+ mToProcess[3];
continue;
}
}
return lines.join("\n");
}
});
function localModeAt(cm, pos) {
return CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(pos).state).mode;
}
function enumerateModesBetween(cm, line, start, end) {
var outer = cm.getMode(), text = cm.getLine(line);
if (end == null) end = text.length;
if (!outer.innerMode) return [{from: start, to: end, mode: outer}];
var state = cm.getTokenAt({line: line, ch: start}).state;
var mode = CodeMirror.innerMode(outer, state).mode;
var found = [], stream = new CodeMirror.StringStream(text);
stream.pos = stream.start = start;
for (;;) {
outer.token(stream, state);
var curMode = CodeMirror.innerMode(outer, state).mode;
if (curMode != mode) {
var cut = stream.start;
// Crappy heuristic to deal with the fact that a change in
// mode can occur both at the end and the start of a token,
// and we don't know which it was.
if (mode.name == "xml" && text.charAt(stream.pos - 1) == ">") cut = stream.pos;
found.push({from: start, to: cut, mode: mode});
start = cut;
mode = curMode;
}
if (stream.pos >= end) break;
stream.start = stream.pos;
}
if (start < end) found.push({from: start, to: end, mode: mode});
return found;
}
// Comment/uncomment the specified range
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
var curMode = localModeAt(this, from), cm = this;
this.operation(function() {
if (isComment) { // Comment range
cm.replaceRange(curMode.commentEnd, to);
cm.replaceRange(curMode.commentStart, from);
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
} else { // Uncomment range
var selText = cm.getRange(from, to);
var startIndex = selText.indexOf(curMode.commentStart);
var endIndex = selText.lastIndexOf(curMode.commentEnd);
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// Take string till comment start
selText = selText.substr(0, startIndex)
// From comment start till comment end
+ selText.substring(startIndex + curMode.commentStart.length, endIndex)
// From comment end till string end
+ selText.substr(endIndex + curMode.commentEnd.length);
}
cm.replaceRange(selText, from, to);
}
});
});
// Applies automatic mode-aware indentation to the specified range
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
var cmInstance = this;
this.operation(function () {
for (var i = from.line; i <= to.line; i++) {
cmInstance.indentLine(i, "smart");
}
});
});
// Applies automatic formatting to the specified range
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
var cm = this;
cm.operation(function () {
for (var cur = from.line, end = to.line; cur <= end; ++cur) {
var f = {line: cur, ch: cur == from.line ? from.ch : 0};
var t = {line: cur, ch: cur == end ? to.ch : null};
var modes = enumerateModesBetween(cm, cur, f.ch, t.ch), mangled = "";
var text = cm.getRange(f, t);
for (var i = 0; i < modes.length; ++i) {
var part = modes.length > 1 ? text.slice(modes[i].from, modes[i].to) : text;
if (mangled) mangled += "\n";
if (modes[i].mode.autoFormatLineBreaks) {
mangled += modes[i].mode.autoFormatLineBreaks(part);
} else mangled += text;
}
if (mangled != text) {
for (var count = 0, pos = mangled.indexOf("\n"); pos != -1; pos = mangled.indexOf("\n", pos + 1), ++count) {}
cm.replaceRange(mangled, f, t);
cur += count;
end += count;
}
}
for (var cur = from.line + 1; cur <= end; ++cur)
cm.indentLine(cur, "smart");
cm.setSelection(from, cm.getCursor(false));
});
});
})();

134
codemirror/lib/util/javascript-hint.js vendored Normal file
View File

@ -0,0 +1,134 @@
(function () {
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) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
// If it's not a 'word-style' token, ignore the token.
if (!/^[\w$_]*$/.test(token.string)) {
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
className: token.string == "." ? "property" : null};
}
// If it is a property, find out what it is a property of.
while (tprop.className == "property") {
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
if (tprop.string != ".") return;
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
if (tprop.string == ')') {
var level = 1;
do {
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
switch (tprop.string) {
case ')': level++; break;
case '(': level--; break;
default: break;
}
} while (level > 0);
tprop = getToken(editor, {line: cur.line, ch: tprop.start});
if (tprop.className == 'variable')
tprop.className = 'function';
else return; // no clue
}
if (!context) var context = [];
context.push(tprop);
}
return {list: getCompletions(token, context, keywords),
from: {line: cur.line, ch: token.start},
to: {line: cur.line, ch: token.end}};
}
CodeMirror.javascriptHint = function(editor) {
return scriptHint(editor, javascriptKeywords,
function (e, cur) {return e.getTokenAt(cur);});
};
function getCoffeeScriptToken(editor, cur) {
// This getToken, it is for coffeescript, imitates the behavior of
// getTokenAt method in javascript.js, that is, returning "property"
// type and treat "." as indepenent token.
var token = editor.getTokenAt(cur);
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
token.end = token.start;
token.string = '.';
token.className = "property";
}
else if (/^\.[\w$_]*$/.test(token.string)) {
token.className = "property";
token.start++;
token.string = token.string.replace(/\./, '');
}
return token;
}
CodeMirror.coffeescriptHint = function(editor) {
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken);
};
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
"toUpperCase toLowerCase split concat match replace search").split(" ");
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
var funcProps = "prototype apply call bind".split(" ");
var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
function getCompletions(token, context, keywords) {
var found = [], start = token.string;
function maybeAdd(str) {
if (str.indexOf(start) == 0 && !arrayContains(found, str)) 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 == "variable")
base = window[obj.string];
else if (obj.className == "string")
base = "";
else if (obj.className == "atom")
base = 1;
else if (obj.className == "function") {
if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
(typeof window.jQuery == 'function'))
base = window.jQuery();
else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
base = window._();
}
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;
}
})();

51
codemirror/lib/util/loadmode.js vendored Normal file
View File

@ -0,0 +1,51 @@
(function() {
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
var loading = {};
function splitCallback(cont, n) {
var countDown = n;
return function() { if (--countDown == 0) cont(); };
}
function ensureDeps(mode, cont) {
var deps = CodeMirror.modes[mode].dependencies;
if (!deps) return cont();
var missing = [];
for (var i = 0; i < deps.length; ++i) {
if (!CodeMirror.modes.hasOwnProperty(deps[i]))
missing.push(deps[i]);
}
if (!missing.length) return cont();
var split = splitCallback(cont, missing.length);
for (var i = 0; i < missing.length; ++i)
CodeMirror.requireMode(missing[i], split);
}
CodeMirror.requireMode = function(mode, cont) {
if (typeof mode != "string") mode = mode.name;
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
var script = document.createElement("script");
script.src = CodeMirror.modeURL.replace(/%N/g, mode);
var others = document.getElementsByTagName("script")[0];
others.parentNode.insertBefore(script, others);
var list = loading[mode] = [cont];
var count = 0, poll = setInterval(function() {
if (++count > 100) return clearInterval(poll);
if (CodeMirror.modes.hasOwnProperty(mode)) {
clearInterval(poll);
loading[mode] = null;
ensureDeps(mode, function() {
for (var i = 0; i < list.length; ++i) list[i]();
});
}
}, 200);
};
CodeMirror.autoLoadMode = function(instance, mode) {
if (!CodeMirror.modes.hasOwnProperty(mode))
CodeMirror.requireMode(mode, function() {
instance.setOption("mode", instance.getOption("mode"));
});
};
}());

View File

@ -0,0 +1,44 @@
// Define match-highlighter commands. Depends on searchcursor.js
// Use by attaching the following function call to the onCursorActivity event:
//myCodeMirror.matchHighlight(minChars);
// And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html)
(function() {
var DEFAULT_MIN_CHARS = 2;
function MatchHighlightState() {
this.marked = [];
}
function getMatchHighlightState(cm) {
return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState());
}
function clearMarks(cm) {
var state = getMatchHighlightState(cm);
for (var i = 0; i < state.marked.length; ++i)
state.marked[i].clear();
state.marked = [];
}
function markDocument(cm, className, minChars) {
clearMarks(cm);
minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS);
if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length >= minChars) {
var state = getMatchHighlightState(cm);
var query = cm.getSelection();
cm.operation(function() {
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
//Only apply matchhighlight to the matches other than the one actually selected
if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch))
state.marked.push(cm.markText(cursor.from(), cursor.to(), className));
}
}
});
}
}
CodeMirror.defineExtension("matchHighlight", function(className, minChars) {
markDocument(this, className, minChars);
});
})();

77
codemirror/lib/util/multiplex.js vendored Normal file
View File

@ -0,0 +1,77 @@
CodeMirror.multiplexingMode = function(outer /*, others */) {
// Others should be {open, close, mode [, delimStyle]} objects
var others = Array.prototype.slice.call(arguments, 1);
var n_others = others.length;
function indexOf(string, pattern, from) {
if (typeof pattern == "string") return string.indexOf(pattern, from);
var m = pattern.exec(from ? string.slice(from) : string);
return m ? m.index + from : -1;
}
return {
startState: function() {
return {
outer: CodeMirror.startState(outer),
innerActive: null,
inner: null
};
},
copyState: function(state) {
return {
outer: CodeMirror.copyState(outer, state.outer),
innerActive: state.innerActive,
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
};
},
token: function(stream, state) {
if (!state.innerActive) {
var cutOff = Infinity, oldContent = stream.string;
for (var i = 0; i < n_others; ++i) {
var other = others[i];
var found = indexOf(oldContent, other.open, stream.pos);
if (found == stream.pos) {
stream.match(other.open);
state.innerActive = other;
state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
return other.delimStyle;
} else if (found != -1 && found < cutOff) {
cutOff = found;
}
}
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
var outerToken = outer.token(stream, state.outer);
if (cutOff != Infinity) stream.string = oldContent;
return outerToken;
} else {
var curInner = state.innerActive, oldContent = stream.string;
var found = indexOf(oldContent, curInner.close, stream.pos);
if (found == stream.pos) {
stream.match(curInner.close);
state.innerActive = state.inner = null;
return curInner.delimStyle;
}
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);
return innerToken;
}
},
indent: function(state, textAfter) {
var mode = state.innerActive ? state.innerActive.mode : outer;
if (!mode.indent) return CodeMirror.Pass;
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
},
electricChars: outer.electricChars,
innerMode: function(state) {
return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
}
};
};

59
codemirror/lib/util/overlay.js vendored Normal file
View File

@ -0,0 +1,59 @@
// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true, in which case
// the styles are combined.
// overlayParser is the old, deprecated name
CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) {
return {
startState: function() {
return {
base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null,
overlayPos: 0, overlayCur: null
};
},
copyState: function(state) {
return {
base: CodeMirror.copyState(base, state.base),
overlay: CodeMirror.copyState(overlay, state.overlay),
basePos: state.basePos, baseCur: null,
overlayPos: state.overlayPos, overlayCur: null
};
},
token: function(stream, state) {
if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos;
}
if (stream.start == state.overlayPos) {
stream.pos = stream.start;
state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos;
}
stream.pos = Math.min(state.basePos, state.overlayPos);
if (stream.eol()) state.basePos = state.overlayPos = 0;
if (state.overlayCur == null) return state.baseCur;
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);
}
};
};

123
codemirror/lib/util/pig-hint.js vendored Normal file
View File

@ -0,0 +1,123 @@
(function () {
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) {
// Find the token at the cursor
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
// If it's not a 'word-style' token, ignore the token.
if (!/^[\w$_]*$/.test(token.string)) {
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);
completionList = completionList.sort();
//prevent autocomplete for last word, instead show dropdown with one word
if(completionList.length == 1) {
completionList.push(" ");
}
return {list: completionList,
from: {line: cur.line, ch: token.start},
to: {line: cur.line, ch: token.end}};
}
CodeMirror.pigHint = function(editor) {
return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
};
function toTitleCase(str) {
return str.replace(/(?:^|\s)\w/g, function(match) {
return match.toUpperCase();
});
}
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 "
+ "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 "
+ "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";
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 "
+ "InvokeForDouble InvokeForFloat InvokeForInt InvokeForLong InvokeForString Invoker "
+ "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);
}
function gatherCompletions(obj) {
if(obj == ":") {
forEach(pigTypesL, maybeAdd);
}
else {
forEach(pigBuiltinsU, maybeAdd);
forEach(pigBuiltinsL, maybeAdd);
forEach(pigBuiltinsC, maybeAdd);
forEach(pigTypesU, maybeAdd);
forEach(pigTypesL, maybeAdd);
forEach(pigKeywordsU, maybeAdd);
forEach(pigKeywordsL, maybeAdd);
}
}
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 == "pig-word")
base = obj.string;
else if(obj.className == "pig-type")
base = ":" + obj.string;
while (base != null && context.length)
base = base[context.pop().string];
if (base != null) gatherCompletions(base);
}
return found;
}
})();

View File

@ -0,0 +1,90 @@
/* Just enough of CodeMirror to run runMode under node.js */
function splitLines(string){ return string.split(/\r?\n|\r/); };
function StringStream(string) {
this.pos = this.start = 0;
this.string = string;
}
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
sol: function() {return this.pos == 0;},
peek: function() {return this.string.charAt(this.pos) || null;},
next: function() {
if (this.pos < this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch && (match.test ? match.test(ch) : match(ch));
if (ok) {++this.pos; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match)){}
return this.pos > start;
},
eatSpace: function() {
var start = this.pos;
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
return this.pos > start;
},
skipToEnd: function() {this.pos = this.string.length;},
skipTo: function(ch) {
var found = this.string.indexOf(ch, this.pos);
if (found > -1) {this.pos = found; return true;}
},
backUp: function(n) {this.pos -= n;},
column: function() {return this.start;},
indentation: function() {return 0;},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
if (consume !== false) this.pos += pattern.length;
return true;
}
}
else {
var match = this.string.slice(this.pos).match(pattern);
if (match && consume !== false) this.pos += match[0].length;
return match;
}
},
current: function(){return this.string.slice(this.start, this.pos);}
};
exports.StringStream = StringStream;
exports.startState = function(mode, a1, a2) {
return mode.startState ? mode.startState(a1, a2) : true;
};
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.runMode = function(string, modespec, callback) {
var mode = exports.getMode({indentUnit: 2}, modespec);
var lines = splitLines(string), 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);
stream.start = stream.pos;
}
}
};

53
codemirror/lib/util/runmode.js vendored Normal file
View File

@ -0,0 +1,53 @@
CodeMirror.runMode = function(string, modespec, callback, options) {
function esc(str) {
return str.replace(/[<&]/g, function(ch) { return ch == "<" ? "&lt;" : "&amp;"; });
}
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
var isNode = callback.nodeType == 1;
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
if (isNode) {
var node = callback, accum = [], col = 0;
callback = function(text, style) {
if (text == "\n") {
accum.push("<br>");
col = 0;
return;
}
var escaped = "";
// HTML-escape and replace tabs
for (var pos = 0;;) {
var idx = text.indexOf("\t", pos);
if (idx == -1) {
escaped += esc(text.slice(pos));
col += text.length - pos;
break;
} else {
col += idx - pos;
escaped += esc(text.slice(pos, idx));
var size = tabSize - col % tabSize;
col += size;
for (var i = 0; i < size; ++i) escaped += " ";
pos = idx + 1;
}
}
if (style)
accum.push("<span class=\"cm-" + esc(style) + "\">" + escaped + "</span>");
else
accum.push(escaped);
};
}
var lines = CodeMirror.splitLines(string), 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);
stream.start = stream.pos;
}
}
if (isNode)
node.innerHTML = accum.join("");
};

118
codemirror/lib/util/search.js vendored Normal file
View File

@ -0,0 +1,118 @@
// Define search commands. Depends on dialog.js or another
// implementation of the openDialog method.
// Replace works a little oddly -- it will do the replace on the next
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
// replace by making sure the match is no longer selected when hitting
// Ctrl-G.
(function() {
function SearchState() {
this.posFrom = this.posTo = this.query = null;
this.marked = [];
}
function getSearchState(cm) {
return cm._searchState || (cm._searchState = new SearchState());
}
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());
}
function dialog(cm, text, shortText, f) {
if (cm.openDialog) cm.openDialog(text, f);
else f(prompt(shortText, ""));
}
function confirmDialog(cm, text, shortText, fs) {
if (cm.openConfirm) cm.openConfirm(text, fs);
else if (confirm(shortText)) fs[0]();
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
}
var queryDialog =
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
function doSearch(cm, rev) {
var state = getSearchState(cm);
if (state.query) return findNext(cm, rev);
dialog(cm, queryDialog, "Search for:", function(query) {
cm.operation(function() {
if (!query || state.query) return;
state.query = parseQuery(query);
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
for (var cursor = getSearchCursor(cm, state.query); cursor.findNext();)
state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
}
state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev);
});
});
}
function findNext(cm, rev) {cm.operation(function() {
var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) {
cursor = getSearchCursor(cm, state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
if (!cursor.find(rev)) return;
}
cm.setSelection(cursor.from(), cursor.to());
state.posFrom = cursor.from(); state.posTo = cursor.to();
});}
function clearSearch(cm) {cm.operation(function() {
var state = getSearchState(cm);
if (!state.query) return;
state.query = null;
for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
state.marked.length = 0;
});}
var replaceQueryDialog =
'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
function replace(cm, all) {
dialog(cm, replaceQueryDialog, "Replace:", function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
if (all) {
cm.compoundChange(function() { cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
} else cursor.replace(text);
}
});});
} else {
clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor());
function advance() {
var start = cursor.from(), match;
if (!(match = cursor.findNext())) {
cursor = getSearchCursor(cm, query);
if (!(match = cursor.findNext()) ||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
}
cm.setSelection(cursor.from(), cursor.to());
confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance]);
}
function doReplace(match) {
cursor.replace(typeof query == "string" ? text :
text.replace(/\$(\d)/, function(w, i) {return match[i];}));
advance();
}
advance();
}
});
});
}
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
CodeMirror.commands.findNext = doSearch;
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
CodeMirror.commands.clearSearch = clearSearch;
CodeMirror.commands.replace = replace;
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
})();

119
codemirror/lib/util/searchcursor.js vendored Normal file
View File

@ -0,0 +1,119 @@
(function(){
function SearchCursor(cm, query, pos, caseFold) {
this.atOccurrence = false; this.cm = cm;
if (caseFold == null && typeof query == "string") caseFold = false;
pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
this.pos = {from: pos, to: pos};
// The matches method is filled in based on the type of query.
// It takes a position and a direction, and returns an object
// describing the next occurrence of the query, or null if no
// more matches were found.
if (typeof query != "string") { // Regexp match
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
this.matches = function(reverse, pos) {
if (reverse) {
query.lastIndex = 0;
var line = cm.getLine(pos.line).slice(0, pos.ch), match = query.exec(line), start = 0;
while (match) {
start += match.index + 1;
line = line.slice(start);
query.lastIndex = 0;
var newmatch = query.exec(line);
if (newmatch) match = newmatch;
else break;
}
start--;
} else {
query.lastIndex = pos.ch;
var line = cm.getLine(pos.line), match = query.exec(line),
start = match && match.index;
}
if (match)
return {from: {line: pos.line, ch: start},
to: {line: pos.line, ch: start + match[0].length},
match: match};
};
} else { // String query
if (caseFold) query = query.toLowerCase();
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
var target = query.split("\n");
// Different methods for single-line and multi-line queries
if (target.length == 1)
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: {line: pos.line, ch: match},
to: {line: pos.line, ch: match + len}};
};
else
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 = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
return {from: reverse ? end : start, to: reverse ? start : end};
}
};
}
}
SearchCursor.prototype = {
findNext: function() {return this.find(false);},
findPrevious: function() {return this.find(true);},
find: function(reverse) {
var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to);
function savePosAndFail(line) {
var pos = {line: line, ch: 0};
self.pos = {from: pos, to: pos};
self.atOccurrence = false;
return false;
}
for (;;) {
if (this.pos = this.matches(reverse, pos)) {
this.atOccurrence = true;
return this.pos.match || true;
}
if (reverse) {
if (!pos.line) return savePosAndFail(0);
pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length};
}
else {
var maxLine = this.cm.lineCount();
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
pos = {line: pos.line+1, ch: 0};
}
}
},
from: function() {if (this.atOccurrence) return this.pos.from;},
to: function() {if (this.atOccurrence) return this.pos.to;},
replace: function(newText) {
var self = this;
if (this.atOccurrence)
self.pos.to = this.cm.replaceRange(newText, self.pos.from, self.pos.to);
}
};
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
return new SearchCursor(this, query, pos, caseFold);
});
})();

16
codemirror/lib/util/simple-hint.css vendored Normal file
View File

@ -0,0 +1,16 @@
.CodeMirror-completions {
position: absolute;
z-index: 10;
overflow: hidden;
-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);
}
.CodeMirror-completions select {
background: #fafafa;
outline: none;
border: none;
padding: 0;
margin: 0;
font-family: monospace;
}

102
codemirror/lib/util/simple-hint.js vendored Normal file
View File

@ -0,0 +1,102 @@
(function() {
CodeMirror.simpleHint = function(editor, getHints, givenOptions) {
// Determine effective options based on given values and defaults.
var options = {}, defaults = CodeMirror.simpleHint.defaults;
for (var opt in defaults)
if (defaults.hasOwnProperty(opt))
options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
function collectHints(previousToken) {
// We want a single cursor position.
if (editor.somethingSelected()) return;
var tempToken = editor.getTokenAt(editor.getCursor());
// Don't show completions if token has changed and the option is set.
if (options.closeOnTokenChange && previousToken != null &&
(tempToken.start != previousToken.start || tempToken.className != previousToken.className)) {
return;
}
var result = getHints(editor);
if (!result || !result.list.length) return;
var completions = result.list;
function insert(str) {
editor.replaceRange(str, result.from, result.to);
}
// When there is only one completion, use it directly.
if (options.completeSingle && completions.length == 1) {
insert(completions[0]);
return true;
}
// Build the select widget
var complete = document.createElement("div");
complete.className = "CodeMirror-completions";
var sel = complete.appendChild(document.createElement("select"));
// Opera doesn't move the selection when pressing up/down in a
// multi-select, but it does properly support the size property on
// single-selects, so no multi-select is necessary.
if (!window.opera) sel.multiple = true;
for (var i = 0; i < completions.length; ++i) {
var opt = sel.appendChild(document.createElement("option"));
opt.appendChild(document.createTextNode(completions[i]));
}
sel.firstChild.selected = true;
sel.size = Math.min(10, completions.length);
var pos = options.alignWithWord ? editor.charCoords(result.from) : editor.cursorCoords();
complete.style.left = pos.x + "px";
complete.style.top = pos.yBot + "px";
document.body.appendChild(complete);
// 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);
if(winW - pos.x < sel.clientWidth)
complete.style.left = (pos.x - sel.clientWidth) + "px";
// Hack to hide the scrollbar.
if (completions.length <= 10)
complete.style.width = (sel.clientWidth - 1) + "px";
var done = false;
function close() {
if (done) return;
done = true;
complete.parentNode.removeChild(complete);
}
function pick() {
insert(completions[sel.selectedIndex]);
close();
setTimeout(function(){editor.focus();}, 50);
}
CodeMirror.connect(sel, "blur", close);
CodeMirror.connect(sel, "keydown", function(event) {
var code = event.keyCode;
// Enter
if (code == 13) {CodeMirror.e_stop(event); pick();}
// Escape
else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
else if (code != 38 && code != 40 && code != 33 && code != 34 && !CodeMirror.isModifierKey(event)) {
close(); editor.focus();
// Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
editor.triggerOnKeyDown(event);
// Don't show completions if the code is backspace and the option is set.
if (!options.closeOnBackspace || code != 8) {
setTimeout(function(){collectHints(tempToken);}, 50);
}
}
});
CodeMirror.connect(sel, "dblclick", pick);
sel.focus();
// Opera sometimes ignores focusing a freshly created node
if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
return true;
}
return collectHints();
};
CodeMirror.simpleHint.defaults = {
closeOnBackspace: true,
closeOnTokenChange: false,
completeSingle: true,
alignWithWord: true
};
})();

131
codemirror/lib/util/xml-hint.js vendored Normal file
View File

@ -0,0 +1,131 @@
(function() {
CodeMirror.xmlHints = [];
CodeMirror.xmlHint = function(cm, simbol) {
if(simbol.length > 0) {
var cursor = cm.getCursor();
cm.replaceSelection(simbol);
cursor = {line: cursor.line, ch: cursor.ch + 1};
cm.setCursor(cursor);
}
CodeMirror.simpleHint(cm, getHint);
};
var getHint = function(cm) {
var cursor = cm.getCursor();
if (cursor.ch > 0) {
var text = cm.getRange({line: 0, ch: 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(cm, 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: { line: cursor.line, ch: cursor.ch - typed.length },
to: cursor
};
};
};
var getActiveElement = function(codeMirror, text) {
var element = '';
if(text.length >= 0) {
var regex = new RegExp('<([^!?][^\\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);
}
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 '';
};
})();

448
codemirror/mode/css/css.js vendored Normal file
View File

@ -0,0 +1,448 @@
CodeMirror.defineMode("css", function(config) {
var indentUnit = config.indentUnit, type;
var atMediaTypes = keySet([
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
]);
var atMediaFeatures = keySet([
"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",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
]);
var propertyKeywords = keySet([
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
"animation-name", "animation-play-state", "animation-timing-function",
"appearance", "azimuth", "backface-visibility", "background",
"background-attachment", "background-clip", "background-color",
"background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"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",
"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",
"font-weight", "grid-cell", "grid-column", "grid-column-align",
"grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
"grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
"grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marker-offset", "marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"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",
"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-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"
]);
var colorKeywords = keySet([
"black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia",
"green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua"
]);
var valueKeywords = keySet([
"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",
"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",
"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",
"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",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
"ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
"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",
"landscape", "lao", "large", "larger", "left", "level", "lighter",
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "malayalam", "match",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
"narrower", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"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",
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"single", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke",
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
"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",
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
"xx-large", "xx-small", "yellow"
]);
function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) keys[array[i]] = true; return keys; }
function ret(style, tp) {type = tp; return style;}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
else if (ch == "<" && stream.eat("!")) {
state.tokenize = tokenSGMLComment;
return tokenSGMLComment(stream, state);
}
else if (ch == "=") ret(null, "compare");
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
}
else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
}
else if (ch === "-") {
if (/\d/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^[^-]+-/)) {
return ret("meta", type);
}
}
else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
}
else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", type);
}
else if (ch == ":") {
return ret("operator", ch);
}
else if (/[;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
}
else {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "variable");
}
}
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
function tokenSGMLComment(stream, state) {
var dashes = 0, ch;
while ((ch = stream.next()) != null) {
if (dashes >= 2 && ch == ">") {
state.tokenize = tokenBase;
break;
}
dashes = (ch == "-") ? dashes + 1 : 0;
}
return ret("comment", "comment");
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped)
break;
escaped = !escaped && ch == "\\";
}
if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
return {
startState: function(base) {
return {tokenize: tokenBase,
baseIndent: base || 0,
stack: []};
},
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.
if (stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
// Changing style returned based on context
var context = state.stack[state.stack.length-1];
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 || 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{") {
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";
}
// Push/pop context stack
if (type == "{") {
if (context == "@media" || context == "@mediaType") {
state.stack.pop();
state.stack[state.stack.length-1] = "@media{";
}
else state.stack.push("rule");
}
else if (type == "}") {
state.stack.pop();
if (context == "propertyValue") state.stack.pop();
}
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" && type == ":") state.stack.push("propertyValue");
else if (context == "propertyValue" && type == ";") state.stack.pop();
return style;
},
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;
},
electricChars: "}"
};
});
CodeMirror.defineMIME("text/css", "css");

58
codemirror/mode/css/index.html vendored Normal file
View File

@ -0,0 +1,58 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>CodeMirror: CSS mode</title>
<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<style>.CodeMirror {background: #f8f8f8;}</style>
<link rel="stylesheet" href="../../doc/docs.css">
</head>
<body>
<h1>CodeMirror: CSS mode</h1>
<form><textarea id="code" name="code">
/* Some example CSS */
@import url("something.css");
body {
margin: 0;
padding: 3em 6em;
font-family: tahoma, arial, sans-serif;
color: #000;
}
#navigation a {
font-weight: bold;
text-decoration: none !important;
}
h1 {
font-size: 2.5em;
}
h2 {
font-size: 1.7em;
}
h1:before, h2:before {
content: "::";
}
code {
font-family: courier, monospace;
font-size: 80%;
color: #418A8A;
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>
<p><strong>MIME types defined:</strong> <code>text/css</code>.</p>
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#css_*">normal</a>, <a href="../../test/index.html#verbose,css_*">verbose</a>.</p>
</body>
</html>

501
codemirror/mode/css/test.js vendored Normal file
View File

@ -0,0 +1,501 @@
// Initiate ModeTest and set defaults
var MT = ModeTest;
MT.modeName = 'css';
MT.modeOptions = {};
// Requires at least one media query
MT.testMode(
'atMediaEmpty',
'@media { }',
[
'def', '@media',
null, ' ',
'error', '{',
null, ' }'
]
);
MT.testMode(
'atMediaMultiple',
'@media not screen and (color), not print and (color) { }',
[
'def', '@media',
null, ' ',
'keyword', 'not',
null, ' ',
'attribute', 'screen',
null, ' ',
'operator', 'and',
null, ' (',
'property', 'color',
null, '), ',
'keyword', 'not',
null, ' ',
'attribute', 'print',
null, ' ',
'operator', 'and',
null, ' (',
'property', 'color',
null, ') { }'
]
);
MT.testMode(
'atMediaCheckStack',
'@media screen { } foo { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' { } ',
'tag', 'foo',
null, ' { }'
]
);
MT.testMode(
'atMediaCheckStack',
'@media screen (color) { } foo { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' (',
'property', 'color',
null, ') { } ',
'tag', 'foo',
null, ' { }'
]
);
MT.testMode(
'atMediaCheckStackInvalidAttribute',
'@media foobarhello { } foo { }',
[
'def', '@media',
null, ' ',
'attribute error', 'foobarhello',
null, ' { } ',
'tag', 'foo',
null, ' { }'
]
);
// Error, because "and" is only allowed immediately preceding a media expression
MT.testMode(
'atMediaInvalidAttribute',
'@media foobarhello { }',
[
'def', '@media',
null, ' ',
'attribute error', 'foobarhello',
null, ' { }'
]
);
// Error, because "and" is only allowed immediately preceding a media expression
MT.testMode(
'atMediaInvalidAnd',
'@media and screen { }',
[
'def', '@media',
null, ' ',
'error', 'and',
null, ' ',
'attribute', 'screen',
null, ' { }'
]
);
// Error, because "not" is only allowed as the first item in each media query
MT.testMode(
'atMediaInvalidNot',
'@media screen not (not) { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'error', 'not',
null, ' (',
'error', 'not',
null, ') { }'
]
);
// Error, because "only" is only allowed as the first item in each media query
MT.testMode(
'atMediaInvalidOnly',
'@media screen only (only) { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'error', 'only',
null, ' (',
'error', 'only',
null, ') { }'
]
);
// Error, because "foobarhello" is neither a known type or property, but
// property was expected (after "and"), and it should be in parenthese.
MT.testMode(
'atMediaUnknownType',
'@media screen and foobarhello { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'operator', 'and',
null, ' ',
'error', 'foobarhello',
null, ' { }'
]
);
// Error, because "color" is not a known type, but is a known property, and
// should be in parentheses.
MT.testMode(
'atMediaInvalidType',
'@media screen and color { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'operator', 'and',
null, ' ',
'error', 'color',
null, ' { }'
]
);
// Error, because "print" is not a known property, but is a known type,
// and should not be in parenthese.
MT.testMode(
'atMediaInvalidProperty',
'@media screen and (print) { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'operator', 'and',
null, ' (',
'error', 'print',
null, ') { }'
]
);
// Soft error, because "foobarhello" is not a known property or type.
MT.testMode(
'atMediaUnknownProperty',
'@media screen and (foobarhello) { }',
[
'def', '@media',
null, ' ',
'attribute', 'screen',
null, ' ',
'operator', 'and',
null, ' (',
'property error', 'foobarhello',
null, ') { }'
]
);
MT.testMode(
'tagSelector',
'foo { }',
[
'tag', 'foo',
null, ' { }'
]
);
MT.testMode(
'classSelector',
'.foo-bar_hello { }',
[
'qualifier', '.foo-bar_hello',
null, ' { }'
]
);
MT.testMode(
'idSelector',
'#foo { #foo }',
[
'builtin', '#foo',
null, ' { ',
'error', '#foo',
null, ' }'
]
);
MT.testMode(
'tagSelectorUnclosed',
'foo { margin: 0 } bar { }',
[
'tag', 'foo',
null, ' { ',
'property', 'margin',
'operator', ':',
null, ' ',
'number', '0',
null, ' } ',
'tag', 'bar',
null, ' { }'
]
);
MT.testMode(
'tagStringNoQuotes',
'foo { font-family: hello world; }',
[
'tag', 'foo',
null, ' { ',
'property', 'font-family',
'operator', ':',
null, ' ',
'variable-2', 'hello',
null, ' ',
'variable-2', 'world',
null, '; }'
]
);
MT.testMode(
'tagStringDouble',
'foo { font-family: "hello world"; }',
[
'tag', 'foo',
null, ' { ',
'property', 'font-family',
'operator', ':',
null, ' ',
'string', '"hello world"',
null, '; }'
]
);
MT.testMode(
'tagStringSingle',
'foo { font-family: \'hello world\'; }',
[
'tag', 'foo',
null, ' { ',
'property', 'font-family',
'operator', ':',
null, ' ',
'string', '\'hello world\'',
null, '; }'
]
);
MT.testMode(
'tagColorKeyword',
'foo { color: black; }',
[
'tag', 'foo',
null, ' { ',
'property', 'color',
'operator', ':',
null, ' ',
'keyword', 'black',
null, '; }'
]
);
MT.testMode(
'tagColorHex3',
'foo { background: #fff; }',
[
'tag', 'foo',
null, ' { ',
'property', 'background',
'operator', ':',
null, ' ',
'atom', '#fff',
null, '; }'
]
);
MT.testMode(
'tagColorHex6',
'foo { background: #ffffff; }',
[
'tag', 'foo',
null, ' { ',
'property', 'background',
'operator', ':',
null, ' ',
'atom', '#ffffff',
null, '; }'
]
);
MT.testMode(
'tagColorHex4',
'foo { background: #ffff; }',
[
'tag', 'foo',
null, ' { ',
'property', 'background',
'operator', ':',
null, ' ',
'atom error', '#ffff',
null, '; }'
]
);
MT.testMode(
'tagColorHexInvalid',
'foo { background: #ffg; }',
[
'tag', 'foo',
null, ' { ',
'property', 'background',
'operator', ':',
null, ' ',
'atom error', '#ffg',
null, '; }'
]
);
MT.testMode(
'tagNegativeNumber',
'foo { margin: -5px; }',
[
'tag', 'foo',
null, ' { ',
'property', 'margin',
'operator', ':',
null, ' ',
'number', '-5px',
null, '; }'
]
);
MT.testMode(
'tagPositiveNumber',
'foo { padding: 5px; }',
[
'tag', 'foo',
null, ' { ',
'property', 'padding',
'operator', ':',
null, ' ',
'number', '5px',
null, '; }'
]
);
MT.testMode(
'tagVendor',
'foo { -foo-box-sizing: -foo-border-box; }',
[
'tag', 'foo',
null, ' { ',
'meta', '-foo-',
'property', 'box-sizing',
'operator', ':',
null, ' ',
'meta', '-foo-',
'string-2', 'border-box',
null, '; }'
]
);
MT.testMode(
'tagBogusProperty',
'foo { barhelloworld: 0; }',
[
'tag', 'foo',
null, ' { ',
'property error', 'barhelloworld',
'operator', ':',
null, ' ',
'number', '0',
null, '; }'
]
);
MT.testMode(
'tagTwoProperties',
'foo { margin: 0; padding: 0; }',
[
'tag', 'foo',
null, ' { ',
'property', 'margin',
'operator', ':',
null, ' ',
'number', '0',
null, '; ',
'property', 'padding',
'operator', ':',
null, ' ',
'number', '0',
null, '; }'
]
);
//
//MT.testMode(
// 'tagClass',
// '@media only screen and (min-width: 500px), print {foo.bar#hello { color: black !important; background: #f00; margin: -5px; padding: 5px; -foo-box-sizing: border-box; } /* world */}',
// [
// 'def', '@media',
// null, ' ',
// 'keyword', 'only',
// null, ' ',
// 'attribute', 'screen',
// null, ' ',
// 'operator', 'and',
// null, ' ',
// 'bracket', '(',
// 'property', 'min-width',
// 'operator', ':',
// null, ' ',
// 'number', '500px',
// 'bracket', ')',
// null, ', ',
// 'attribute', 'print',
// null, ' {',
// 'tag', 'foo',
// 'qualifier', '.bar',
// 'header', '#hello',
// null, ' { ',
// 'property', 'color',
// 'operator', ':',
// null, ' ',
// 'keyword', 'black',
// null, ' ',
// 'keyword', '!important',
// null, '; ',
// 'property', 'background',
// 'operator', ':',
// null, ' ',
// 'atom', '#f00',
// null, '; ',
// 'property', 'padding',
// 'operator', ':',
// null, ' ',
// 'number', '5px',
// null, '; ',
// 'property', 'margin',
// 'operator', ':',
// null, ' ',
// 'number', '-5px',
// null, '; ',
// 'meta', '-foo-',
// 'property', 'box-sizing',
// 'operator', ':',
// null, ' ',
// 'string-2', 'border-box',
// null, '; } ',
// 'comment', '/* world */',
// null, '}'
// ]
//);

21
codemirror/package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "codemirror",
"version":"2.36.0",
"main": "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"},
"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"}]
}

6
codemirror/theme/ambiance-mobile.css vendored Normal file
View File

@ -0,0 +1,6 @@
.CodeMirror .cm-s-ambiance {
-webkit-box-shadow: none;
-moz-box-shadow: none;
-o-box-shadow: none;
box-shadow: none;
}

81
codemirror/theme/ambiance.css vendored Normal file

File diff suppressed because one or more lines are too long

25
codemirror/theme/blackboard.css vendored Normal file
View File

@ -0,0 +1,25 @@
/* Port of TextMate's Blackboard theme */
.cm-s-blackboard { background: #0C1021; color: #F8F8F8; }
.cm-s-blackboard .CodeMirror-selected { background: #253B76 !important; }
.cm-s-blackboard .CodeMirror-gutter { background: #0C1021; border-right: 0; }
.cm-s-blackboard .CodeMirror-gutter-text { color: #888; }
.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7 !important; }
.cm-s-blackboard .cm-keyword { color: #FBDE2D; }
.cm-s-blackboard .cm-atom { color: #D8FA3C; }
.cm-s-blackboard .cm-number { color: #D8FA3C; }
.cm-s-blackboard .cm-def { color: #8DA6CE; }
.cm-s-blackboard .cm-variable { color: #FF6400; }
.cm-s-blackboard .cm-operator { color: #FBDE2D;}
.cm-s-blackboard .cm-comment { color: #AEAEAE; }
.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; }

18
codemirror/theme/cobalt.css vendored Normal file
View File

@ -0,0 +1,18 @@
.cm-s-cobalt { background: #002240; color: white; }
.cm-s-cobalt div.CodeMirror-selected { background: #b36539 !important; }
.cm-s-cobalt .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
.cm-s-cobalt .CodeMirror-gutter-text { color: #d0d0d0; }
.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-cobalt span.cm-comment { color: #08f; }
.cm-s-cobalt span.cm-atom { color: #845dc4; }
.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }
.cm-s-cobalt span.cm-keyword { color: #ffee80; }
.cm-s-cobalt span.cm-string { color: #3ad900; }
.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; }

25
codemirror/theme/eclipse.css vendored Normal file
View File

@ -0,0 +1,25 @@
.cm-s-eclipse span.cm-meta {color: #FF1717;}
.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
.cm-s-eclipse span.cm-atom {color: #219;}
.cm-s-eclipse span.cm-number {color: #164;}
.cm-s-eclipse span.cm-def {color: #00f;}
.cm-s-eclipse span.cm-variable {color: black;}
.cm-s-eclipse span.cm-variable-2 {color: #0000C0;}
.cm-s-eclipse span.cm-variable-3 {color: #0000C0;}
.cm-s-eclipse span.cm-property {color: black;}
.cm-s-eclipse span.cm-operator {color: black;}
.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 .CodeMirror-matchingbracket {
border:1px solid grey;
color:black !important;;
}

10
codemirror/theme/elegant.css vendored Normal file
View File

@ -0,0 +1,10 @@
.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}
.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}
.cm-s-elegant span.cm-variable {color: black;}
.cm-s-elegant span.cm-variable-2 {color: #b11;}
.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;}

21
codemirror/theme/erlang-dark.css vendored Normal file
View File

@ -0,0 +1,21 @@
.cm-s-erlang-dark { background: #002240; color: white; }
.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539 !important; }
.cm-s-erlang-dark .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
.cm-s-erlang-dark .CodeMirror-gutter-text { 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-attribute { color: #ff80e1; }
.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; }
.cm-s-erlang-dark span.cm-builtin { color: #eeaaaa; }
.cm-s-erlang-dark span.cm-comment { color: #7777ff; }
.cm-s-erlang-dark span.cm-def { color: #ee77aa; }
.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: #dd1111; }
.cm-s-erlang-dark span.cm-string { color: #3ad900; }
.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: #ee00ee; }

44
codemirror/theme/lesser-dark.css vendored Normal file
View File

@ -0,0 +1,44 @@
/*
http://lesscss.org/ dark theme
Ported to CodeMirror by Peter Kroon
*/
.cm-s-lesser-dark {
line-height: 1.3em;
}
.cm-s-lesser-dark {
font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', 'Monaco', Courier, monospace !important;
}
.cm-s-lesser-dark { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
.cm-s-lesser-dark div.CodeMirror-selected {background: #45443B !important;} /* 33322B*/
.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-lesser-dark .CodeMirror-lines { margin-left:3px; margin-right:3px; }/*editable code holder*/
div.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
.cm-s-lesser-dark .CodeMirror-gutter { background: #262626; border-right:1px solid #aaa; padding-right:3px; min-width:2.5em; }
.cm-s-lesser-dark .CodeMirror-gutter-text { color: #777; }
.cm-s-lesser-dark span.cm-keyword { color: #599eff; }
.cm-s-lesser-dark span.cm-atom { color: #C2B470; }
.cm-s-lesser-dark span.cm-number { color: #B35E4D; }
.cm-s-lesser-dark span.cm-def {color: white;}
.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }
.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }
.cm-s-lesser-dark span.cm-variable-3 { color: white; }
.cm-s-lesser-dark span.cm-property {color: #92A75C;}
.cm-s-lesser-dark span.cm-operator {color: #92A75C;}
.cm-s-lesser-dark span.cm-comment { color: #666; }
.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; }
.cm-s-lesser-dark span.cm-tag { color: #669199; }
.cm-s-lesser-dark span.cm-attribute {color: #00c;}
.cm-s-lesser-dark span.cm-header {color: #a0a;}
.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;}

28
codemirror/theme/monokai.css vendored Normal file
View File

@ -0,0 +1,28 @@
/* Based on Sublime Text's Monokai theme */
.cm-s-monokai {background: #272822; color: #f8f8f2;}
.cm-s-monokai div.CodeMirror-selected {background: #49483E !important;}
.cm-s-monokai .CodeMirror-gutter {background: #272822; border-right: 0px;}
.cm-s-monokai .CodeMirror-gutter-text {color: #d0d0d0;}
.cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;}
.cm-s-monokai span.cm-comment {color: #75715e;}
.cm-s-monokai span.cm-atom {color: #ae81ff;}
.cm-s-monokai span.cm-number {color: #ae81ff;}
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;}
.cm-s-monokai span.cm-keyword {color: #f92672;}
.cm-s-monokai span.cm-string {color: #e6db74;}
.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 .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

9
codemirror/theme/neat.css vendored Normal file
View File

@ -0,0 +1,9 @@
.cm-s-neat span.cm-comment { color: #a86; }
.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
.cm-s-neat span.cm-string { color: #a22; }
.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
.cm-s-neat span.cm-variable { color: black; }
.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; }

21
codemirror/theme/night.css vendored Normal file
View File

@ -0,0 +1,21 @@
/* Loosely based on the Midnight Textmate theme */
.cm-s-night { background: #0a001f; color: #f8f8f8; }
.cm-s-night div.CodeMirror-selected { background: #447 !important; }
.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-atom { color: #845dc4; }
.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
.cm-s-night span.cm-keyword { color: #599eff; }
.cm-s-night span.cm-string { color: #37f14a; }
.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; }

21
codemirror/theme/rubyblue.css vendored Normal file
View File

@ -0,0 +1,21 @@
.cm-s-rubyblue { font:13px/1.4em Trebuchet, Verdana, sans-serif; } /* - customized editor font - */
.cm-s-rubyblue { background: #112435; color: white; }
.cm-s-rubyblue div.CodeMirror-selected { background: #38566F !important; }
.cm-s-rubyblue .CodeMirror-gutter { background: #1F4661; border-right: 7px solid #3E7087; min-width:2.5em; }
.cm-s-rubyblue .CodeMirror-gutter-text { color: white; }
.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }
.cm-s-rubyblue span.cm-atom { color: #F4C20B; }
.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }
.cm-s-rubyblue span.cm-keyword { color: #F0F; }
.cm-s-rubyblue span.cm-string { color: #F08047; }
.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; }

26
codemirror/theme/twilight.css vendored Normal file
View File

@ -0,0 +1,26 @@
.cm-s-twilight { background: #141414; color: #f7f7f7; } /**/
.cm-s-twilight .CodeMirror-selected { background: #323232 !important; } /**/
.cm-s-twilight .CodeMirror-gutter { background: #222; border-right: 1px solid #aaa; }
.cm-s-twilight .CodeMirror-gutter-text { color: #aaa; }
.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/
.cm-s-twilight .cm-atom { color: #FC0; }
.cm-s-twilight .cm-number { color: #ca7841; } /**/
.cm-s-twilight .cm-def { color: #8DA6CE; }
.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/
.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def { color: #607392; } /**/
.cm-s-twilight .cm-operator { color: #cda869; } /**/
.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/
.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; font-underline:none; } /**/

27
codemirror/theme/vibrant-ink.css vendored Normal file
View File

@ -0,0 +1,27 @@
/* Taken from the popular Visual Studio Vibrant Ink Schema */
.cm-s-vibrant-ink { background: black; color: white; }
.cm-s-vibrant-ink .CodeMirror-selected { background: #35493c !important; }
.cm-s-vibrant-ink .CodeMirror-gutter { background: #002240; border-right: 1px solid #aaa; }
.cm-s-vibrant-ink .CodeMirror-gutter-text { color: #d0d0d0; }
.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }
.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 .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; }

46
codemirror/theme/xq-dark.css vendored Normal file
View File

@ -0,0 +1,46 @@
/*
Copyright (C) 2011 by MarkLogic Corporation
Author: Mike Brevoort <mike@brevoort.com>
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.
*/
.cm-s-xq-dark { background: #0a001f; color: #f8f8f8; }
.cm-s-xq-dark span.CodeMirror-selected { background: #a8f !important; }
.cm-s-xq-dark .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
.cm-s-xq-dark .CodeMirror-gutter-text { color: #f8f8f8; }
.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white !important; }
.cm-s-xq-dark span.cm-keyword {color: #FFBD40;}
.cm-s-xq-dark span.cm-atom {color: #6C8CD5;}
.cm-s-xq-dark span.cm-number {color: #164;}
.cm-s-xq-dark span.cm-def {color: #FFF; text-decoration:underline;}
.cm-s-xq-dark span.cm-variable {color: #FFF;}
.cm-s-xq-dark span.cm-variable-2 {color: #EEE;}
.cm-s-xq-dark span.cm-variable-3 {color: #DDD;}
.cm-s-xq-dark span.cm-property {}
.cm-s-xq-dark span.cm-operator {}
.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;}

View File

@ -1,5 +1,8 @@
<html>
<head>
<script src="codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="codemirror/lib/codemirror.css">
<script src="codemirror/mode/css/css.js"></script>
<style type="text/css">
body {
margin: 0px;
@ -47,6 +50,9 @@
height: 10em;
width: 40em;
}
.CodeMirror {
border: solid #CCC 1px;
}
.applies-to ul {
display: inline-block;
margin: 0;

20
edit.js
View File

@ -11,6 +11,19 @@ appliesToEverythingTemplate.innerHTML = t("appliesToEverything") + ' <button cla
var sectionTemplate = document.createElement("div");
sectionTemplate.innerHTML = '<label>' + t('sectionCode') + '</label><textarea class="code"></textarea><br><div class="applies-to"><label>' + t("appliesLabel") + ' <img class="applies-to-help" src="help.png" alt="' + t('helpAlt') + '"></label><ul class="applies-to-list"></ul></div><button class="remove-section">' + t('sectionRemove') + '</button><button class="add-section">' + t('sectionAdd') + '</button>';
var editors = [] // array of all CodeMirror instances
// replace given textarea with the CodeMirror editor
function setupCodeMirror(textarea) {
var cm = CodeMirror.fromTextArea(textarea, {
mode: 'css',
lineNumbers: true,
lineWrapping: true
});
editors.push(cm);
}
function makeDirty() {
dirty = true;
}
@ -89,6 +102,7 @@ function addSection(section) {
var sections = document.getElementById("sections");
sections.appendChild(div);
setupCodeMirror(div.querySelector('.code'));
}
function removeAppliesTo(event) {
@ -177,6 +191,11 @@ function validate() {
}
function save() {
// save the contents of the CodeMirror editors back into the textareas
for(var i=0; i < editors.length; i++) {
editors[i].save();
}
var error = validate();
if (error) {
alert(error);
@ -312,4 +331,3 @@ document.getElementById("to-mozilla").addEventListener("click", showMozillaForma
document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
document.getElementById("save-button").addEventListener("click", save, false);
document.getElementById("sections-help").addEventListener("click", showSectionHelp, false);