Merge pull request #76 from eric-wood/master
Added CodeMirror editor replacement
This commit is contained in:
commit
88c3eeaf20
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.DS_Store
|
2
codemirror/.gitignore
vendored
Normal file
2
codemirror/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/node_modules
|
||||||
|
/npm-debug.log
|
3
codemirror/.travis.yml
Normal file
3
codemirror/.travis.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.8
|
23
codemirror/LICENSE
Normal file
23
codemirror/LICENSE
Normal 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
8
codemirror/README.md
Normal 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
88
codemirror/bin/compress
Executable 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
480
codemirror/index.html
Normal 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><!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> Saves memory and CPU cycles.<br> <code>compareStates</code> is no longer needed.<br> <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"> </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
30
codemirror/keymap/emacs.js
vendored
Normal 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
897
codemirror/keymap/vim.js
vendored
Normal 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 == "<" ? "<" : "&"; });
|
||||||
|
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
174
codemirror/lib/codemirror.css
vendored
Normal 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
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
164
codemirror/lib/util/closetag.js
vendored
Normal 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
36
codemirror/lib/util/continuecomment.js
vendored
Normal 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
27
codemirror/lib/util/dialog.css
vendored
Normal 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
70
codemirror/lib/util/dialog.js
vendored
Normal 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
196
codemirror/lib/util/foldcode.js
vendored
Normal 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">▼</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
196
codemirror/lib/util/formatting.js
vendored
Normal 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
134
codemirror/lib/util/javascript-hint.js
vendored
Normal 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
51
codemirror/lib/util/loadmode.js
vendored
Normal 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"));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}());
|
44
codemirror/lib/util/match-highlighter.js
vendored
Normal file
44
codemirror/lib/util/match-highlighter.js
vendored
Normal 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
77
codemirror/lib/util/multiplex.js
vendored
Normal 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
59
codemirror/lib/util/overlay.js
vendored
Normal 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
123
codemirror/lib/util/pig-hint.js
vendored
Normal 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;
|
||||||
|
}
|
||||||
|
})();
|
90
codemirror/lib/util/runmode-standalone.js
vendored
Normal file
90
codemirror/lib/util/runmode-standalone.js
vendored
Normal 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
53
codemirror/lib/util/runmode.js
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
CodeMirror.runMode = function(string, modespec, callback, options) {
|
||||||
|
function esc(str) {
|
||||||
|
return str.replace(/[<&]/g, function(ch) { return ch == "<" ? "<" : "&"; });
|
||||||
|
}
|
||||||
|
|
||||||
|
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
118
codemirror/lib/util/search.js
vendored
Normal 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
119
codemirror/lib/util/searchcursor.js
vendored
Normal 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
16
codemirror/lib/util/simple-hint.css
vendored
Normal 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
102
codemirror/lib/util/simple-hint.js
vendored
Normal 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
131
codemirror/lib/util/xml-hint.js
vendored
Normal 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
448
codemirror/mode/css/css.js
vendored
Normal 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
58
codemirror/mode/css/index.html
vendored
Normal 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
501
codemirror/mode/css/test.js
vendored
Normal 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
21
codemirror/package.json
Normal 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
6
codemirror/theme/ambiance-mobile.css
vendored
Normal 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
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
25
codemirror/theme/blackboard.css
vendored
Normal 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
18
codemirror/theme/cobalt.css
vendored
Normal 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
25
codemirror/theme/eclipse.css
vendored
Normal 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
10
codemirror/theme/elegant.css
vendored
Normal 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
21
codemirror/theme/erlang-dark.css
vendored
Normal 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
44
codemirror/theme/lesser-dark.css
vendored
Normal 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
28
codemirror/theme/monokai.css
vendored
Normal 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
9
codemirror/theme/neat.css
vendored
Normal 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
21
codemirror/theme/night.css
vendored
Normal 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
21
codemirror/theme/rubyblue.css
vendored
Normal 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
26
codemirror/theme/twilight.css
vendored
Normal 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
27
codemirror/theme/vibrant-ink.css
vendored
Normal 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
46
codemirror/theme/xq-dark.css
vendored
Normal 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;}
|
|
@ -1,5 +1,8 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<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">
|
<style type="text/css">
|
||||||
body {
|
body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
@ -47,6 +50,9 @@
|
||||||
height: 10em;
|
height: 10em;
|
||||||
width: 40em;
|
width: 40em;
|
||||||
}
|
}
|
||||||
|
.CodeMirror {
|
||||||
|
border: solid #CCC 1px;
|
||||||
|
}
|
||||||
.applies-to ul {
|
.applies-to ul {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
20
edit.js
20
edit.js
|
@ -11,6 +11,19 @@ appliesToEverythingTemplate.innerHTML = t("appliesToEverything") + ' <button cla
|
||||||
var sectionTemplate = document.createElement("div");
|
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>';
|
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() {
|
function makeDirty() {
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
@ -89,6 +102,7 @@ function addSection(section) {
|
||||||
|
|
||||||
var sections = document.getElementById("sections");
|
var sections = document.getElementById("sections");
|
||||||
sections.appendChild(div);
|
sections.appendChild(div);
|
||||||
|
setupCodeMirror(div.querySelector('.code'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAppliesTo(event) {
|
function removeAppliesTo(event) {
|
||||||
|
@ -177,6 +191,11 @@ function validate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
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();
|
var error = validate();
|
||||||
if (error) {
|
if (error) {
|
||||||
alert(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("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
|
||||||
document.getElementById("save-button").addEventListener("click", save, false);
|
document.getElementById("save-button").addEventListener("click", save, false);
|
||||||
document.getElementById("sections-help").addEventListener("click", showSectionHelp, false);
|
document.getElementById("sections-help").addEventListener("click", showSectionHelp, false);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user