##// END OF EJS Templates
update CodeMirror2 to 2.32
Matthias BUSSONNIER -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,453 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror</title>
5 <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans:bold"/>
6 <link rel="stylesheet" type="text/css" href="doc/docs.css"/>
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
8 <link rel="alternate" href="http://twitter.com/statuses/user_timeline/242283288.rss" type="application/rss+xml"/>
9 </head>
10 <body style="margin-top: 9em">
11
12 <div style="background: #eee; border-bottom: 2px solid #df0019; position: absolute; left: 0; top: 0; right: 0; padding: 18px 0;">
13 <div style="max-width: 64.3em; margin: 0 auto;">
14 <a href="http://www.pledgie.com/campaigns/17784">
15 <img style="width: 149px; height: 37px; vertical-align: bottom" alt='Click here to lend your support to: Fund CodeMirror development and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/17784.png?skin_name=chrome' border=0/>
16 </a> &nbsp; <span style="font-size: 1.23em; font-weight: bold;">Please check out our development fundraiser.
17 </div>
18 </div>
19
20 <h1><span class="logo-braces">{ }</span> <a href="http://codemirror.net/">CodeMirror</a></h1>
21
22 <pre class="grey">
23 <img src="doc/baboon.png" class="logo" alt="logo"/>/* In-browser code editing
24 made bearable */
25 </pre>
26
27 <div class="clear"><div class="left blk">
28
29 <p style="margin-top: 0">CodeMirror is a JavaScript component that
30 provides a code editor in the browser. When a mode is available for
31 the language you are coding in, it will color your code, and
32 optionally help with indentation.</p>
33
34 <p>A <a href="doc/manual.html">rich programming API</a> and a CSS
35 theming system are available for customizing CodeMirror to fit your
36 application, and extending it with new functionality.</p>
37
38 <div class="clear"><div class="left1 blk">
39
40 <h2 style="margin-top: 0">Supported modes:</h2>
41
42 <ul>
43 <li><a href="mode/clike/index.html">C, C++, C#</a></li>
44 <li><a href="mode/clojure/index.html">Clojure</a></li>
45 <li><a href="mode/coffeescript/index.html">CoffeeScript</a></li>
46 <li><a href="mode/css/index.html">CSS</a></li>
47 <li><a href="mode/diff/index.html">diff</a></li>
48 <li><a href="mode/ecl/index.html">ECL</a></li>
49 <li><a href="mode/erlang/index.html">Erlang</a></li>
50 <li><a href="mode/go/index.html">Go</a></li>
51 <li><a href="mode/groovy/index.html">Groovy</a></li>
52 <li><a href="mode/haskell/index.html">Haskell</a></li>
53 <li><a href="mode/haxe/index.html">Haxe</a></li>
54 <li><a href="mode/htmlembedded/index.html">HTML embedded scripts</a></li>
55 <li><a href="mode/htmlmixed/index.html">HTML mixed-mode</a></li>
56 <li><a href="mode/clike/index.html">Java</a></li>
57 <li><a href="mode/javascript/index.html">JavaScript</a></li>
58 <li><a href="mode/jinja2/index.html">Jinja2</a></li>
59 <li><a href="mode/less/index.html">LESS</a></li>
60 <li><a href="mode/lua/index.html">Lua</a></li>
61 <li><a href="mode/markdown/index.html">Markdown</a> (<a href="mode/gfm/index.html">Github-flavour</a>)</li>
62 <li><a href="mode/mysql/index.html">MySQL</a></li>
63 <li><a href="mode/ntriples/index.html">NTriples</a></li>
64 <li><a href="mode/ocaml/index.html">OCaml</a></li>
65 <li><a href="mode/pascal/index.html">Pascal</a></li>
66 <li><a href="mode/perl/index.html">Perl</a></li>
67 <li><a href="mode/php/index.html">PHP</a></li>
68 <li><a href="mode/pig/index.html">Pig Latin</a></li>
69 <li><a href="mode/plsql/index.html">PL/SQL</a></li>
70 <li><a href="mode/properties/index.html">Properties files</a></li>
71 <li><a href="mode/python/index.html">Python</a></li>
72 <li><a href="mode/r/index.html">R</a></li>
73 <li>RPM <a href="mode/rpm/spec/index.html">spec</a> and <a href="mode/rpm/changes/index.html">changelog</a></li>
74 <li><a href="mode/rst/index.html">reStructuredText</a></li>
75 <li><a href="mode/ruby/index.html">Ruby</a></li>
76 <li><a href="mode/rust/index.html">Rust</a></li>
77 <li><a href="mode/clike/scala.html">Scala</a></li>
78 <li><a href="mode/scheme/index.html">Scheme</a></li>
79 <li><a href="mode/shell/index.html">Shell</a></li>
80 <li><a href="mode/smalltalk/index.html">Smalltalk</a></li>
81 <li><a href="mode/smarty/index.html">Smarty</a></li>
82 <li><a href="mode/sparql/index.html">SPARQL</a></li>
83 <li><a href="mode/stex/index.html">sTeX, LaTeX</a></li>
84 <li><a href="mode/tiddlywiki/index.html">Tiddlywiki</a></li>
85 <li><a href="mode/tiki/index.html">Tiki wiki</a></li>
86 <li><a href="mode/vb/index.html">VB.NET</a></li>
87 <li><a href="mode/vbscript/index.html">VBScript</a></li>
88 <li><a href="mode/velocity/index.html">Velocity</a></li>
89 <li><a href="mode/verilog/index.html">Verilog</a></li>
90 <li><a href="mode/xml/index.html">XML/HTML</a></li>
91 <li><a href="mode/xquery/index.html">XQuery</a></li>
92 <li><a href="mode/yaml/index.html">YAML</a></li>
93 </ul>
94
95 </div><div class="left2 blk">
96
97 <h2 style="margin-top: 0">Usage demos:</h2>
98
99 <ul>
100 <li><a href="demo/complete.html">Autocompletion</a> (<a href="demo/xmlcomplete.html">XML</a>)</li>
101 <li><a href="demo/search.html">Search/replace</a></li>
102 <li><a href="demo/folding.html">Code folding</a></li>
103 <li><a href="demo/mustache.html">Mode overlays</a></li>
104 <li><a href="demo/multiplex.html">Mode multiplexer</a></li>
105 <li><a href="demo/preview.html">HTML editor with preview</a></li>
106 <li><a href="demo/resize.html">Auto-resizing editor</a></li>
107 <li><a href="demo/marker.html">Setting breakpoints</a></li>
108 <li><a href="demo/activeline.html">Highlighting the current line</a></li>
109 <li><a href="demo/matchhighlighter.html">Highlighting selection matches</a></li>
110 <li><a href="demo/theme.html">Theming</a></li>
111 <li><a href="demo/runmode.html">Stand-alone highlighting</a></li>
112 <li><a href="demo/fullscreen.html">Full-screen editing</a></li>
113 <li><a href="demo/changemode.html">Mode auto-changing</a></li>
114 <li><a href="demo/visibletabs.html">Visible tabs</a></li>
115 <li><a href="demo/formatting.html">Autoformatting of code</a></li>
116 <li><a href="demo/emacs.html">Emacs keybindings</a></li>
117 <li><a href="demo/vim.html">Vim keybindings</a></li>
118 <li><a href="demo/closetag.html">Automatic xml tag closing</a></li>
119 <li><a href="demo/loadmode.html">Lazy mode loading</a></li>
120 </ul>
121
122 <h2>Real-world uses:</h2>
123
124 <ul>
125 <li><a href="http://jsbin.com">jsbin.com</a> (JS playground)</li>
126 <li><a href="http://www.chris-granger.com/2012/04/12/light-table---a-new-ide-concept/">Light Table</a> (experimental IDE)</li>
127 <li><a href="http://brackets.io">Adobe Brackets</a> (code editor)</li>
128 <li><a href="http://www.mergely.com/">Mergely</a> (interactive diffing)</li>
129 <li><a href="https://script.google.com/">Google Apps Script</a></li>
130 <li><a href="http://eloquentjavascript.net/chapter1.html">Eloquent JavaScript</a> (book)</li>
131 <li><a href="http://media.chikuyonok.ru/codemirror2/">Zen Coding</a> (fast XML editing)</li>
132 <li><a href="http://paperjs.org/">Paper.js</a> (graphics scripting)</li>
133 <li><a href="http://tour.golang.org">Go language tour</a></li>
134 <li><a href="http://enjalot.com/tributary/2636296/sinwaves.js">Tributary</a> (augmented editing)</li>
135 <li><a href="http://prose.io/">Prose.io</a> (github content editor)</li>
136 <li><a href="http://www.wescheme.org/">WeScheme</a> (learning tool)</li>
137 <li><a href="http://webglplayground.net/">WebGL playground</a></li>
138 <li><a href="http://ql.io/">ql.io</a> (http API query helper)</li>
139 <li><a href="http://elm-lang.org/Examples.elm">Elm language examples</a></li>
140 <li><a href="https://thefiletree.com">The File Tree</a> (collab editor)</li>
141 <li><a href="http://bluegriffon.org/">BlueGriffon</a> (HTML editor)</li>
142 <li><a href="http://www.jshint.com/">JSHint</a> (JS linter)</li>
143 <li><a href="http://kl1p.com/cmtest/1">kl1p</a> (paste service)</li>
144 <li><a href="http://sqlfiddle.com">SQLFiddle</a> (SQL playground)</li>
145 <li><a href="http://try.haxe.org">Try Haxe</a> (Haxe Playground) </li>
146 <li><a href="http://cssdeck.com/">CSSDeck</a> (CSS showcase)</li>
147 <li><a href="http://www.ckwnc.com/">CKWNC</a> (UML editor)</li>
148 <li><a href="http://www.sketchpatch.net/labs/livecodelabIntro.html">sketchPatch Livecodelab</a></li>
149 </ul>
150
151 </div></div>
152
153 <h2 id="code">Getting the code</h2>
154
155 <p>All of CodeMirror is released under a <a
156 href="LICENSE">MIT-style</a> license. To get it, you can download
157 the <a href="http://codemirror.net/codemirror.zip">latest
158 release</a> or the current <a
159 href="http://codemirror.net/codemirror2-latest.zip">development
160 snapshot</a> as zip files. To create a custom minified script file,
161 you can use the <a href="doc/compress.html">compression API</a>.</p>
162
163 <p>We use <a href="http://git-scm.com/">git</a> for version control.
164 The main repository can be fetched in this way:</p>
165
166 <pre class="code">git clone http://marijnhaverbeke.nl/git/codemirror2</pre>
167
168 <p>CodeMirror can also be found on GitHub at <a
169 href="http://github.com/marijnh/CodeMirror2">marijnh/CodeMirror2</a>.
170 If you plan to hack on the code and contribute patches, the best way
171 to do it is to create a GitHub fork, and send pull requests.</p>
172
173 <h2 id="documention">Documentation</h2>
174
175 <p>The <a href="doc/manual.html">manual</a> is your first stop for
176 learning how to use this library. It starts with a quick explanation
177 of how to use the editor, and then describes the API in detail.</p>
178
179 <p>For those who want to learn more about the code, there is
180 an <a href="doc/internals.html">overview of the internals</a> available.
181 The <a href="http://github.com/marijnh/CodeMirror2">source code</a>
182 itself is, for the most part, also well commented.</p>
183
184 <h2 id="support">Support and bug reports</h2>
185
186 <p>There is
187 a <a href="http://groups.google.com/group/codemirror">Google
188 group</a> (a sort of mailing list/newsgroup thing) for discussion
189 and news related to CodeMirror. When reporting a bug,
190 <a href="doc/reporting.html">read this first</a>. If you have
191 a <a href="http://github.com">github</a> account,
192 simply <a href="http://github.com/marijnh/CodeMirror2/issues">open
193 an issue there</a>. Otherwise, post something to
194 the <a href="http://groups.google.com/group/codemirror">group</a>,
195 or e-mail me directly: <a href="mailto:marijnh@gmail.com">Marijn
196 Haverbeke</a>.</p>
197
198 <h2 id="supported">Supported browsers</h2>
199
200 <p>The following browsers are able to run CodeMirror:</p>
201
202 <ul>
203 <li>Firefox 2 or higher</li>
204 <li>Chrome, any version</li>
205 <li>Safari 3 or higher</li>
206 <li>Opera 9 or higher (with some key-handling problems on OS X)</li>
207 <li>Internet Explorer 7 or higher in standards mode<br>
208 <em>(So not quirks mode. But quasi-standards mode with a
209 transitional doctype is also flaky. <code>&lt;!doctype
210 html></code> is recommended.)</em></li>
211 </ul>
212
213 <p>I am not actively testing against every new browser release, and
214 vendors have a habit of introducing bugs all the time, so I am
215 relying on the community to tell me when something breaks.
216 See <a href="#support">here</a> for information on how to contact
217 me.</p>
218
219 <h2 id="commercial">Commercial support</h2>
220
221 <p>CodeMirror is developed and maintained by me, Marijn Haverbeke,
222 in my own time. If your company is getting value out of CodeMirror,
223 please consider purchasing a support contract.</p>
224
225 <ul>
226 <li>You'll be funding further work on CodeMirror.</li>
227 <li>You ensure that you get a quick response when you have a
228 problem, even when I am otherwise busy.</li>
229 </ul>
230
231 <p>CodeMirror support contracts exist in two
232 forms—<strong>basic</strong> at €100 per month,
233 and <strong>premium</strong> at €500 per
234 month. <a href="mailto:marijnh@gmail.com">Contact me</a> for further
235 information.</p>
236
237 </div>
238
239 <div class="right blk">
240
241 <a href="http://codemirror.net/codemirror.zip" class="download">Download the latest release</a>
242
243 <h2>Support CodeMirror</h2>
244
245 <ul>
246 <li>Donate
247 (<span onclick="document.getElementById('paypal').submit();"
248 class="quasilink">Paypal</span>
249 or <span onclick="document.getElementById('bankinfo').style.display = 'block';"
250 class="quasilink">bank</span>)</li>
251 <li>Purchase <a href="#commercial">commercial support</a></li>
252 </ul>
253
254 <p id="bankinfo" style="display: none;">
255 Bank: <i>Rabobank</i><br/>
256 Country: <i>Netherlands</i><br/>
257 SWIFT: <i>RABONL2U</i><br/>
258 Account: <i>147850770</i><br/>
259 Name: <i>Marijn Haverbeke</i><br/>
260 IBAN: <i>NL26 RABO 0147 8507 70</i>
261 </p>
262
263 <h2>Reading material</h2>
264
265 <ul>
266 <li><a href="doc/manual.html">User manual</a></li>
267 <li><a href="http://github.com/marijnh/CodeMirror2">Browse the code</a></li>
268 </ul>
269
270 <h2 id=releases>Releases</h2>
271
272 <p class="rel">23-07-2012: <a href="http://codemirror.net/codemirror-2.32.zip">Version 2.32</a>:</p>
273
274 <p class="rel-note">Emergency fix for a bug where an editor with
275 line wrapping on IE will break when there is <em>no</em>
276 scrollbar.</p>
277
278 <p class="rel">20-07-2012: <a href="http://codemirror.net/codemirror-2.31.zip">Version 2.31</a>:</p>
279
280 <ul class="rel-note">
281 <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>
282 <li>Several fixes to the new scrolling model.</li>
283 <li>Add a <a href="doc/manual.html#setSize"><code>setSize</code></a> method for programmatic resizing.</li>
284 <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>
285 <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>
286 <li>Support double- and triple-click drag, double-clicking whitespace.</li>
287 <li>And more... <a href="https://github.com/marijnh/CodeMirror2/compare/v2.3...v2.31">(all patches)</a></li>
288 </ul>
289
290 <p class="rel">22-06-2012: <a href="http://codemirror.net/codemirror-2.3.zip">Version 2.3</a>:</p>
291
292 <ul class="rel-note">
293 <li><strong>New scrollbar implementation</strong>. Should flicker less. Changes DOM structure of the editor.</li>
294 <li>New theme: <a href="demo/theme.html?vibrant-ink">vibrant-ink</a>.</li>
295 <li>Many extensions to the VIM keymap (including text objects).</li>
296 <li>Add <a href="demo/multiplex.html">mode-multiplexing</a> utility script.</li>
297 <li>Fix bug where right-click paste works in read-only mode.</li>
298 <li>Add a <a href="doc/manual.html#getScrollInfo"><code>getScrollInfo</code></a> method.</li>
299 <li>Lots of other <a href="https://github.com/marijnh/CodeMirror2/compare/v2.25...v2.3">fixes</a>.</li>
300 </ul>
301
302 <p class="rel">23-05-2012: <a href="http://codemirror.net/codemirror-2.25.zip">Version 2.25</a>:</p>
303
304 <ul class="rel-note">
305 <li>New mode: <a href="mode/erlang/index.html">Erlang</a>.</li>
306 <li><strong>Remove xmlpure mode</strong> (use <a href="mode/xml/index.html">xml.js</a>).</li>
307 <li>Fix line-wrapping in Opera.</li>
308 <li>Fix X Windows middle-click paste in Chrome.</li>
309 <li>Fix bug that broke pasting of huge documents.</li>
310 <li>Fix backspace and tab key repeat in Opera.</li>
311 </ul>
312
313 <p class="rel">23-04-2012: <a href="http://codemirror.net/codemirror-2.24.zip">Version 2.24</a>:</p>
314
315 <ul class="rel-note">
316 <li><strong>Drop support for Internet Explorer 6</strong>.</li>
317 <li>New
318 modes: <a href="mode/shell/index.html">Shell</a>, <a href="mode/tiki/index.html">Tiki
319 wiki</a>, <a href="mode/pig/index.html">Pig Latin</a>.</li>
320 <li>New themes: <a href="demo/theme.html?ambiance">Ambiance</a>, <a href="demo/theme.html?blackboard">Blackboard</a>.</li>
321 <li>More control over drag/drop
322 with <a href="doc/manual.html#option_dragDrop"><code>dragDrop</code></a>
323 and <a href="doc/manual.html#option_onDragEvent"><code>onDragEvent</code></a>
324 options.</li>
325 <li>Make HTML mode a bit less pedantic.</li>
326 <li>Add <a href="doc/manual.html#compoundChange"><code>compoundChange</code></a> API method.</li>
327 <li>Several fixes in undo history and line hiding.</li>
328 <li>Remove (broken) support for <code>catchall</code> in key maps,
329 add <code>nofallthrough</code> boolean field instead.</li>
330 </ul>
331
332 <p class="rel">26-03-2012: <a href="http://codemirror.net/codemirror-2.23.zip">Version 2.23</a>:</p>
333
334 <ul class="rel-note">
335 <li>Change <strong>default binding for tab</strong> <a href="javascript:void(document.getElementById('tabbinding').style.display='')">[more]</a>
336 <div style="display: none" id=tabbinding>
337 Starting in 2.23, these bindings are default:
338 <ul><li>Tab: Insert tab character</li>
339 <li>Shift-tab: Reset line indentation to default</li>
340 <li>Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)</li>
341 <li>Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)</li>
342 </ul>
343 </div>
344 </li>
345 <li>New modes: <a href="mode/xquery/index.html">XQuery</a> and <a href="mode/vbscript/index.html">VBScript</a>.</li>
346 <li>Two new themes: <a href="mode/less/index.html">lesser-dark</a> and <a href="mode/xquery/index.html">xq-dark</a>.</li>
347 <li>Differentiate between background and text styles in <a href="doc/manual.html#setLineClass"><code>setLineClass</code></a>.</li>
348 <li>Fix drag-and-drop in IE9+.</li>
349 <li>Extend <a href="doc/manual.html#charCoords"><code>charCoords</code></a>
350 and <a href="doc/manual.html#cursorCoords"><code>cursorCoords</code></a> with a <code>mode</code> argument.</li>
351 <li>Add <a href="doc/manual.html#option_autofocus"><code>autofocus</code></a> option.</li>
352 <li>Add <a href="doc/manual.html#findMarksAt"><code>findMarksAt</code></a> method.</li>
353 </ul>
354
355 <p class="rel">27-02-2012: <a href="http://codemirror.net/codemirror-2.22.zip">Version 2.22</a>:</p>
356
357 <ul class="rel-note">
358 <li>Allow <a href="doc/manual.html#keymaps">key handlers</a> to pass up events, allow binding characters.</li>
359 <li>Add <a href="doc/manual.html#option_autoClearEmptyLines"><code>autoClearEmptyLines</code></a> option.</li>
360 <li>Properly use tab stops when rendering tabs.</li>
361 <li>Make PHP mode more robust.</li>
362 <li>Support indentation blocks in <a href="doc/manual.html#util_foldcode">code folder</a>.</li>
363 <li>Add a script for <a href="doc/manual.html#util_match-highlighter">highlighting instances of the selection</a>.</li>
364 <li>New <a href="mode/properties/index.html">.properties</a> mode.</li>
365 <li>Fix many bugs.</li>
366 </ul>
367
368 <p class="rel">27-01-2012: <a href="http://codemirror.net/codemirror-2.21.zip">Version 2.21</a>:</p>
369
370 <ul class="rel-note">
371 <li>Added <a href="mode/less/index.html">LESS</a>, <a href="mode/mysql/index.html">MySQL</a>,
372 <a href="mode/go/index.html">Go</a>, and <a href="mode/verilog/index.html">Verilog</a> modes.</li>
373 <li>Add <a href="doc/manual.html#option_smartIndent"><code>smartIndent</code></a>
374 option.</li>
375 <li>Support a cursor in <a href="doc/manual.html#option_readOnly"><code>readOnly</code></a>-mode.</li>
376 <li>Support assigning multiple styles to a token.</li>
377 <li>Use a new approach to drawing the selection.</li>
378 <li>Add <a href="doc/manual.html#scrollTo"><code>scrollTo</code></a> method.</li>
379 <li>Allow undo/redo events to span non-adjacent lines.</li>
380 <li>Lots and lots of bugfixes.</li>
381 </ul>
382
383 <p class="rel">20-12-2011: <a href="http://codemirror.net/codemirror-2.2.zip">Version 2.2</a>:</p>
384
385 <ul class="rel-note">
386 <li>Slightly incompatible API changes. Read <a href="doc/upgrade_v2.2.html">this</a>.</li>
387 <li>New approach
388 to <a href="doc/manual.html#option_extraKeys">binding</a> keys,
389 support for <a href="doc/manual.html#option_keyMap">custom
390 bindings</a>.</li>
391 <li>Support for overwrite (insert).</li>
392 <li><a href="doc/manual.html#option_tabSize">Custom-width</a>
393 and <a href="demo/visibletabs.html">stylable</a> tabs.</li>
394 <li>Moved more code into <a href="doc/manual.html#addons">add-on scripts</a>.</li>
395 <li>Support for sane vertical cursor movement in wrapped lines.</li>
396 <li>More reliable handling of
397 editing <a href="doc/manual.html#markText">marked text</a>.</li>
398 <li>Add minimal <a href="demo/emacs.html">emacs</a>
399 and <a href="demo/vim.html">vim</a> bindings.</li>
400 <li>Rename <code>coordsFromIndex</code>
401 to <a href="doc/manual.html#posFromIndex"><code>posFromIndex</code></a>,
402 add <a href="doc/manual.html#indexFromPos"><code>indexFromPos</code></a>
403 method.</li>
404 </ul>
405
406 <p class="rel">21-11-2011: <a href="http://codemirror.net/codemirror-2.18.zip">Version 2.18</a>:</p>
407 <p class="rel-note">Fixes <code>TextMarker.clear</code>, which is broken in 2.17.</p>
408
409 <p class="rel">21-11-2011: <a href="http://codemirror.net/codemirror-2.17.zip">Version 2.17</a>:</p>
410 <ul class="rel-note">
411 <li>Add support for <a href="doc/manual.html#option_lineWrapping">line
412 wrapping</a> and <a href="doc/manual.html#hideLine">code
413 folding</a>.</li>
414 <li>Add <a href="mode/gfm/index.html">Github-style Markdown</a> mode.</li>
415 <li>Add <a href="theme/monokai.css">Monokai</a>
416 and <a href="theme/rubyblue.css">Rubyblue</a> themes.</li>
417 <li>Add <a href="doc/manual.html#setBookmark"><code>setBookmark</code></a> method.</li>
418 <li>Move some of the demo code into reusable components
419 under <a href="lib/util/"><code>lib/util</code></a>.</li>
420 <li>Make screen-coord-finding code faster and more reliable.</li>
421 <li>Fix drag-and-drop in Firefox.</li>
422 <li>Improve support for IME.</li>
423 <li>Speed up content rendering.</li>
424 <li>Fix browser's built-in search in Webkit.</li>
425 <li>Make double- and triple-click work in IE.</li>
426 <li>Various fixes to modes.</li>
427 </ul>
428
429 <p class="rel">27-10-2011: <a href="http://codemirror.net/codemirror-2.16.zip">Version 2.16</a>:</p>
430 <ul class="rel-note">
431 <li>Add <a href="mode/perl/index.html">Perl</a>, <a href="mode/rust/index.html">Rust</a>, <a href="mode/tiddlywiki/index.html">TiddlyWiki</a>, and <a href="mode/groovy/index.html">Groovy</a> modes.</li>
432 <li>Dragging text inside the editor now moves, rather than copies.</li>
433 <li>Add a <a href="doc/manual.html#coordsFromIndex"><code>coordsFromIndex</code></a> method.</li>
434 <li><strong>API change</strong>: <code>setValue</code> now no longer clears history. Use <a href="doc/manual.html#clearHistory"><code>clearHistory</code></a> for that.</li>
435 <li><strong>API change</strong>: <a href="doc/manual.html#markText"><code>markText</code></a> now
436 returns an object with <code>clear</code> and <code>find</code>
437 methods. Marked text is now more robust when edited.</li>
438 <li>Fix editing code with tabs in Internet Explorer.</li>
439 </ul>
440
441 <p><a href="doc/oldrelease.html">Older releases...</a></p>
442
443 </div></div>
444
445 <div style="height: 2em">&nbsp;</div>
446
447 <form action="https://www.paypal.com/cgi-bin/webscr" method="post" id="paypal">
448 <input type="hidden" name="cmd" value="_s-xclick"/>
449 <input type="hidden" name="hosted_button_id" value="3FVHS5FGUY7CC"/>
450 </form>
451
452 </body>
453 </html>
@@ -0,0 +1,29 b''
1 // TODO number prefixes
2 (function() {
3 // Really primitive kill-ring implementation.
4 var killRing = [];
5 function addToRing(str) {
6 killRing.push(str);
7 if (killRing.length > 50) killRing.shift();
8 }
9 function getFromRing() { return killRing[killRing.length - 1] || ""; }
10 function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
11
12 CodeMirror.keyMap.emacs = {
13 "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");},
14 "Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
15 "Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");},
16 "Alt-W": function(cm) {addToRing(cm.getSelection());},
17 "Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());},
18 "Alt-Y": function(cm) {cm.replaceSelection(popFromRing());},
19 "Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
20 "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace",
21 "Ctrl-Z": "undo", "Cmd-Z": "undo", "Alt-/": "autocomplete",
22 fallthrough: ["basic", "emacsy"]
23 };
24
25 CodeMirror.keyMap["emacs-Ctrl-X"] = {
26 "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close",
27 auto: "emacs", nofallthrough: true
28 };
29 })();
This diff has been collapsed as it changes many lines, (785 lines changed) Show them Hide them
@@ -0,0 +1,785 b''
1 // Supported keybindings:
2 //
3 // Cursor movement:
4 // h, j, k, l
5 // e, E, w, W, b, B
6 // Ctrl-f, Ctrl-b
7 // Ctrl-n, Ctrl-p
8 // $, ^, 0
9 // G
10 // ge, gE
11 // gg
12 // f<char>, F<char>, t<char>, T<char>
13 // Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
14 // /, ?, n, N TODO (does not work)
15 // #, * TODO
16 //
17 // Entering insert mode:
18 // i, I, a, A, o, O
19 // s
20 // ce, cb (without support for number of actions like c3e - TODO)
21 // cc
22 // S, C TODO
23 // cf<char>, cF<char>, ct<char>, cT<char>
24 //
25 // Deleting text:
26 // x, X
27 // J
28 // dd, D
29 // de, db (without support for number of actions like d3e - TODO)
30 // df<char>, dF<char>, dt<char>, dT<char>
31 //
32 // Yanking and pasting:
33 // yy, Y
34 // p, P
35 // p'<char> TODO - test
36 // y'<char> TODO - test
37 // m<char> TODO - test
38 //
39 // Changing text in place:
40 // ~
41 // r<char>
42 //
43 // Visual mode:
44 // v, V TODO
45 //
46 // Misc:
47 // . TODO
48 //
49
50 (function() {
51 var count = "";
52 var sdir = "f";
53 var buf = "";
54 var yank = 0;
55 var mark = [];
56 var reptTimes = 0;
57 function emptyBuffer() { buf = ""; }
58 function pushInBuffer(str) { buf += str; }
59 function pushCountDigit(digit) { return function(cm) {count += digit;}; }
60 function popCount() { var i = parseInt(count, 10); count = ""; return i || 1; }
61 function iterTimes(func) {
62 for (var i = 0, c = popCount(); i < c; ++i) func(i, i == c - 1);
63 }
64 function countTimes(func) {
65 if (typeof func == "string") func = CodeMirror.commands[func];
66 return function(cm) { iterTimes(function () { func(cm); }); };
67 }
68
69 function iterObj(o, f) {
70 for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
71 }
72 function iterList(l, f) {
73 for (var i in l) f(l[i]);
74 }
75 function toLetter(ch) {
76 // T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
77 if (ch.slice(0, 6) == "Shift-") {
78 return ch.slice(0, 1);
79 } else {
80 if (ch == "Space") return " ";
81 if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
82 return ch.toLowerCase();
83 }
84 }
85 var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
86 function toCombo(ch) {
87 // t -> T, T -> Shift-T, * -> '*', " " -> "Space"
88 if (ch == " ") return "Space";
89 var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
90 if (specialIdx != -1) return "'" + ch + "'";
91 if (ch.toLowerCase() == ch) return ch.toUpperCase();
92 return "Shift-" + ch.toUpperCase();
93 }
94
95 var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
96 function findWord(line, pos, dir, regexps) {
97 var stop = 0, next = -1;
98 if (dir > 0) { stop = line.length; next = 0; }
99 var start = stop, end = stop;
100 // Find bounds of next one.
101 outer: for (; pos != stop; pos += dir) {
102 for (var i = 0; i < regexps.length; ++i) {
103 if (regexps[i].test(line.charAt(pos + next))) {
104 start = pos;
105 for (; pos != stop; pos += dir) {
106 if (!regexps[i].test(line.charAt(pos + next))) break;
107 }
108 end = pos;
109 break outer;
110 }
111 }
112 }
113 return {from: Math.min(start, end), to: Math.max(start, end)};
114 }
115 function moveToWord(cm, regexps, dir, times, where) {
116 var cur = cm.getCursor();
117
118 for (var i = 0; i < times; i++) {
119 var line = cm.getLine(cur.line), startCh = cur.ch, word;
120 while (true) {
121 // If we're at start/end of line, start on prev/next respectivly
122 if (cur.ch == line.length && dir > 0) {
123 cur.line++;
124 cur.ch = 0;
125 line = cm.getLine(cur.line);
126 } else if (cur.ch == 0 && dir < 0) {
127 cur.line--;
128 cur.ch = line.length;
129 line = cm.getLine(cur.line);
130 }
131 if (!line) break;
132
133 // On to the actual searching
134 word = findWord(line, cur.ch, dir, regexps);
135 cur.ch = word[where == "end" ? "to" : "from"];
136 if (startCh == cur.ch && word.from != word.to) cur.ch = word[dir < 0 ? "from" : "to"];
137 else break;
138 }
139 }
140 return cur;
141 }
142 function joinLineNext(cm) {
143 var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
144 CodeMirror.commands.goLineEnd(cm);
145 if (cur.line != cm.lineCount()) {
146 CodeMirror.commands.goLineEnd(cm);
147 cm.replaceSelection(" ", "end");
148 CodeMirror.commands.delCharRight(cm);
149 }
150 }
151 function delTillMark(cm, cHar) {
152 var i = mark[cHar];
153 if (i === undefined) {
154 // console.log("Mark not set"); // TODO - show in status bar
155 return;
156 }
157 var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
158 cm.setCursor(start);
159 for (var c = start; c <= end; c++) {
160 pushInBuffer("\n"+cm.getLine(start));
161 cm.removeLine(start);
162 }
163 }
164 function yankTillMark(cm, cHar) {
165 var i = mark[cHar];
166 if (i === undefined) {
167 // console.log("Mark not set"); // TODO - show in status bar
168 return;
169 }
170 var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
171 for (var c = start; c <= end; c++) {
172 pushInBuffer("\n"+cm.getLine(c));
173 }
174 cm.setCursor(start);
175 }
176 function goLineStartText(cm) {
177 // Go to the start of the line where the text begins, or the end for whitespace-only lines
178 var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
179 cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
180 }
181
182 function charIdxInLine(cm, cHar, motion_options) {
183 // Search for cHar in line.
184 // motion_options: {forward, inclusive}
185 // If inclusive = true, include it too.
186 // If forward = true, search forward, else search backwards.
187 // If char is not found on this line, do nothing
188 var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
189 var ch = toLetter(cHar), mo = motion_options;
190 if (mo.forward) {
191 idx = line.indexOf(ch, cur.ch + 1);
192 if (idx != -1 && mo.inclusive) idx += 1;
193 } else {
194 idx = line.lastIndexOf(ch, cur.ch);
195 if (idx != -1 && !mo.inclusive) idx += 1;
196 }
197 return idx;
198 }
199
200 function moveTillChar(cm, cHar, motion_options) {
201 // Move to cHar in line, as found by charIdxInLine.
202 var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
203 if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
204 }
205
206 function delTillChar(cm, cHar, motion_options) {
207 // delete text in this line, untill cHar is met,
208 // as found by charIdxInLine.
209 // If char is not found on this line, do nothing
210 var idx = charIdxInLine(cm, cHar, motion_options);
211 var cur = cm.getCursor();
212 if (idx !== -1) {
213 if (motion_options.forward) {
214 cm.replaceRange("", {line: cur.line, ch: cur.ch}, {line: cur.line, ch: idx});
215 } else {
216 cm.replaceRange("", {line: cur.line, ch: idx}, {line: cur.line, ch: cur.ch});
217 }
218 }
219 }
220
221 function enterInsertMode(cm) {
222 // enter insert mode: switch mode and cursor
223 popCount();
224 cm.setOption("keyMap", "vim-insert");
225 }
226
227 function dialog(cm, text, shortText, f) {
228 if (cm.openDialog) cm.openDialog(text, f);
229 else f(prompt(shortText, ""));
230 }
231 function showAlert(cm, text) {
232 if (cm.openDialog) cm.openDialog(CodeMirror.htmlEscape(text) + " <button type=button>OK</button>");
233 else alert(text);
234 }
235
236 // main keymap
237 var map = CodeMirror.keyMap.vim = {
238 // Pipe (|); TODO: should be *screen* chars, so need a util function to turn tabs into spaces?
239 "'|'": function(cm) {
240 cm.setCursor(cm.getCursor().line, popCount() - 1, true);
241 },
242 "A": function(cm) {
243 cm.setCursor(cm.getCursor().line, cm.getCursor().ch+1, true);
244 enterInsertMode(cm);
245 },
246 "Shift-A": function(cm) { CodeMirror.commands.goLineEnd(cm); enterInsertMode(cm);},
247 "I": function(cm) { enterInsertMode(cm);},
248 "Shift-I": function(cm) { goLineStartText(cm); enterInsertMode(cm);},
249 "O": function(cm) {
250 CodeMirror.commands.goLineEnd(cm);
251 CodeMirror.commands.newlineAndIndent(cm);
252 enterInsertMode(cm);
253 },
254 "Shift-O": function(cm) {
255 CodeMirror.commands.goLineStart(cm);
256 cm.replaceSelection("\n", "start");
257 cm.indentLine(cm.getCursor().line);
258 enterInsertMode(cm);
259 },
260 "G": function(cm) { cm.setOption("keyMap", "vim-prefix-g");},
261 "Shift-D": function(cm) {
262 // commented out verions works, but I left original, cause maybe
263 // I don't know vim enouth to see what it does
264 /* var cur = cm.getCursor();
265 var f = {line: cur.line, ch: cur.ch}, t = {line: cur.line};
266 pushInBuffer(cm.getRange(f, t));
267 */
268 emptyBuffer();
269 mark["Shift-D"] = cm.getCursor(false).line;
270 cm.setCursor(cm.getCursor(true).line);
271 delTillMark(cm,"Shift-D"); mark = [];
272 },
273
274 "S": function (cm) {
275 countTimes(function (_cm) {
276 CodeMirror.commands.delCharRight(_cm);
277 })(cm);
278 enterInsertMode(cm);
279 },
280 "M": function(cm) {cm.setOption("keyMap", "vim-prefix-m"); mark = [];},
281 "Y": function(cm) {cm.setOption("keyMap", "vim-prefix-y"); emptyBuffer(); yank = 0;},
282 "Shift-Y": function(cm) {
283 emptyBuffer();
284 mark["Shift-D"] = cm.getCursor(false).line;
285 cm.setCursor(cm.getCursor(true).line);
286 yankTillMark(cm,"Shift-D"); mark = [];
287 },
288 "/": function(cm) {var f = CodeMirror.commands.find; f && f(cm); sdir = "f";},
289 "'?'": function(cm) {
290 var f = CodeMirror.commands.find;
291 if (f) { f(cm); CodeMirror.commands.findPrev(cm); sdir = "r"; }
292 },
293 "N": function(cm) {
294 var fn = CodeMirror.commands.findNext;
295 if (fn) sdir != "r" ? fn(cm) : CodeMirror.commands.findPrev(cm);
296 },
297 "Shift-N": function(cm) {
298 var fn = CodeMirror.commands.findNext;
299 if (fn) sdir != "r" ? CodeMirror.commands.findPrev(cm) : fn.findNext(cm);
300 },
301 "Shift-G": function(cm) {
302 count == "" ? cm.setCursor(cm.lineCount()) : cm.setCursor(parseInt(count, 10)-1);
303 popCount();
304 CodeMirror.commands.goLineStart(cm);
305 },
306 "':'": function(cm) {
307 var exModeDialog = ': <input type="text" style="width: 90%"/>';
308 dialog(cm, exModeDialog, ':', function(command) {
309 if (command.match(/^\d+$/)) {
310 cm.setCursor(command - 1, cm.getCursor().ch);
311 } else {
312 showAlert(cm, "Bad command: " + command);
313 }
314 });
315 },
316 nofallthrough: true, style: "fat-cursor"
317 };
318
319 // standard mode switching
320 iterList(["d", "t", "T", "f", "F", "c", "r"],
321 function (ch) {
322 CodeMirror.keyMap.vim[toCombo(ch)] = function (cm) {
323 cm.setOption("keyMap", "vim-prefix-" + ch);
324 emptyBuffer();
325 };
326 });
327
328 function addCountBindings(keyMap) {
329 // Add bindings for number keys
330 keyMap["0"] = function(cm) {
331 count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);
332 };
333 for (var i = 1; i < 10; ++i) keyMap[i] = pushCountDigit(i);
334 }
335 addCountBindings(CodeMirror.keyMap.vim);
336
337 // main num keymap
338 // Add bindings that are influenced by number keys
339 iterObj({
340 "Left": "goColumnLeft", "Right": "goColumnRight",
341 "Down": "goLineDown", "Up": "goLineUp", "Backspace": "goCharLeft",
342 "Space": "goCharRight",
343 "X": function(cm) {CodeMirror.commands.delCharRight(cm);},
344 "P": function(cm) {
345 var cur = cm.getCursor().line;
346 if (buf!= "") {
347 if (buf[0] == "\n") CodeMirror.commands.goLineEnd(cm);
348 cm.replaceRange(buf, cm.getCursor());
349 }
350 },
351 "Shift-X": function(cm) {CodeMirror.commands.delCharLeft(cm);},
352 "Shift-J": function(cm) {joinLineNext(cm);},
353 "Shift-P": function(cm) {
354 var cur = cm.getCursor().line;
355 if (buf!= "") {
356 CodeMirror.commands.goLineUp(cm);
357 CodeMirror.commands.goLineEnd(cm);
358 cm.replaceSelection(buf, "end");
359 }
360 cm.setCursor(cur+1);
361 },
362 "'~'": function(cm) {
363 var cur = cm.getCursor(), cHar = cm.getRange({line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
364 cHar = cHar != cHar.toLowerCase() ? cHar.toLowerCase() : cHar.toUpperCase();
365 cm.replaceRange(cHar, {line: cur.line, ch: cur.ch}, {line: cur.line, ch: cur.ch+1});
366 cm.setCursor(cur.line, cur.ch+1);
367 },
368 "Ctrl-B": function(cm) {CodeMirror.commands.goPageUp(cm);},
369 "Ctrl-F": function(cm) {CodeMirror.commands.goPageDown(cm);},
370 "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
371 "U": "undo", "Ctrl-R": "redo"
372 }, function(key, cmd) { map[key] = countTimes(cmd); });
373
374 // empty key maps
375 iterList([
376 "vim-prefix-d'",
377 "vim-prefix-y'",
378 "vim-prefix-df",
379 "vim-prefix-dF",
380 "vim-prefix-dt",
381 "vim-prefix-dT",
382 "vim-prefix-c",
383 "vim-prefix-cf",
384 "vim-prefix-cF",
385 "vim-prefix-ct",
386 "vim-prefix-cT",
387 "vim-prefix-",
388 "vim-prefix-f",
389 "vim-prefix-F",
390 "vim-prefix-t",
391 "vim-prefix-T",
392 "vim-prefix-r",
393 "vim-prefix-m"
394 ],
395 function (prefix) {
396 CodeMirror.keyMap[prefix] = {
397 auto: "vim",
398 nofallthrough: true,
399 style: "fat-cursor"
400 };
401 });
402
403 CodeMirror.keyMap["vim-prefix-g"] = {
404 "E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, word, -1, 1, "start"));}),
405 "Shift-E": countTimes(function(cm) { cm.setCursor(moveToWord(cm, bigWord, -1, 1, "start"));}),
406 "G": function (cm) { cm.setCursor({line: 0, ch: cm.getCursor().ch});},
407 auto: "vim", nofallthrough: true, style: "fat-cursor"
408 };
409
410 CodeMirror.keyMap["vim-prefix-d"] = {
411 "D": countTimes(function(cm) {
412 pushInBuffer("\n"+cm.getLine(cm.getCursor().line));
413 cm.removeLine(cm.getCursor().line);
414 cm.setOption("keyMap", "vim");
415 }),
416 "'": function(cm) {
417 cm.setOption("keyMap", "vim-prefix-d'");
418 emptyBuffer();
419 },
420 "B": function(cm) {
421 var cur = cm.getCursor();
422 var line = cm.getLine(cur.line);
423 var index = line.lastIndexOf(" ", cur.ch);
424
425 pushInBuffer(line.substring(index, cur.ch));
426 cm.replaceRange("", {line: cur.line, ch: index}, cur);
427 cm.setOption("keyMap", "vim");
428 },
429 nofallthrough: true, style: "fat-cursor"
430 };
431 // FIXME - does not work for bindings like "d3e"
432 addCountBindings(CodeMirror.keyMap["vim-prefix-d"]);
433
434 CodeMirror.keyMap["vim-prefix-c"] = {
435 "B": function (cm) {
436 countTimes("delWordLeft")(cm);
437 enterInsertMode(cm);
438 },
439 "C": function (cm) {
440 iterTimes(function (i, last) {
441 CodeMirror.commands.deleteLine(cm);
442 if (i) {
443 CodeMirror.commands.delCharRight(cm);
444 if (last) CodeMirror.commands.deleteLine(cm);
445 }
446 });
447 enterInsertMode(cm);
448 },
449 nofallthrough: true, style: "fat-cursor"
450 };
451
452 iterList(["vim-prefix-d", "vim-prefix-c", "vim-prefix-"], function (prefix) {
453 iterList(["f", "F", "T", "t"],
454 function (ch) {
455 CodeMirror.keyMap[prefix][toCombo(ch)] = function (cm) {
456 cm.setOption("keyMap", prefix + ch);
457 emptyBuffer();
458 };
459 });
460 });
461
462 var MOTION_OPTIONS = {
463 "t": {inclusive: false, forward: true},
464 "f": {inclusive: true, forward: true},
465 "T": {inclusive: false, forward: false},
466 "F": {inclusive: true, forward: false}
467 };
468
469 function setupPrefixBindingForKey(m) {
470 CodeMirror.keyMap["vim-prefix-m"][m] = function(cm) {
471 mark[m] = cm.getCursor().line;
472 };
473 CodeMirror.keyMap["vim-prefix-d'"][m] = function(cm) {
474 delTillMark(cm,m);
475 };
476 CodeMirror.keyMap["vim-prefix-y'"][m] = function(cm) {
477 yankTillMark(cm,m);
478 };
479 CodeMirror.keyMap["vim-prefix-r"][m] = function (cm) {
480 var cur = cm.getCursor();
481 cm.replaceRange(toLetter(m),
482 {line: cur.line, ch: cur.ch},
483 {line: cur.line, ch: cur.ch + 1});
484 CodeMirror.commands.goColumnLeft(cm);
485 };
486 // all commands, related to motions till char in line
487 iterObj(MOTION_OPTIONS, function (ch, options) {
488 CodeMirror.keyMap["vim-prefix-" + ch][m] = function(cm) {
489 moveTillChar(cm, m, options);
490 };
491 CodeMirror.keyMap["vim-prefix-d" + ch][m] = function(cm) {
492 delTillChar(cm, m, options);
493 };
494 CodeMirror.keyMap["vim-prefix-c" + ch][m] = function(cm) {
495 delTillChar(cm, m, options);
496 enterInsertMode(cm);
497 };
498 });
499 }
500 for (var i = 65; i < 65 + 26; i++) { // uppercase alphabet char codes
501 var ch = String.fromCharCode(i);
502 setupPrefixBindingForKey(toCombo(ch));
503 setupPrefixBindingForKey(toCombo(ch.toLowerCase()));
504 }
505 iterList(SPECIAL_SYMBOLS, function (ch) {
506 setupPrefixBindingForKey(toCombo(ch));
507 });
508 setupPrefixBindingForKey("Space");
509
510 CodeMirror.keyMap["vim-prefix-y"] = {
511 "Y": countTimes(function(cm) { pushInBuffer("\n"+cm.getLine(cm.getCursor().line+yank)); yank++; }),
512 "'": function(cm) {cm.setOption("keyMap", "vim-prefix-y'"); emptyBuffer();},
513 nofallthrough: true, style: "fat-cursor"
514 };
515
516 CodeMirror.keyMap["vim-insert"] = {
517 // TODO: override navigation keys so that Esc will cancel automatic indentation from o, O, i_<CR>
518 "Esc": function(cm) {
519 cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
520 cm.setOption("keyMap", "vim");
521 },
522 "Ctrl-N": "autocomplete",
523 "Ctrl-P": "autocomplete",
524 fallthrough: ["default"]
525 };
526
527 function findMatchedSymbol(cm, cur, symb) {
528 var line = cur.line;
529 var symb = symb ? symb : cm.getLine(line)[cur.ch];
530
531 // Are we at the opening or closing char
532 var forwards = ['(', '[', '{'].indexOf(symb) != -1;
533
534 var reverseSymb = (function(sym) {
535 switch (sym) {
536 case '(' : return ')';
537 case '[' : return ']';
538 case '{' : return '}';
539 case ')' : return '(';
540 case ']' : return '[';
541 case '}' : return '{';
542 default : return null;
543 }
544 })(symb);
545
546 // Couldn't find a matching symbol, abort
547 if (reverseSymb == null) return cur;
548
549 // Tracking our imbalance in open/closing symbols. An opening symbol wii be
550 // the first thing we pick up if moving forward, this isn't true moving backwards
551 var disBal = forwards ? 0 : 1;
552
553 while (true) {
554 if (line == cur.line) {
555 // First pass, do some special stuff
556 var currLine = forwards ? cm.getLine(line).substr(cur.ch).split('') : cm.getLine(line).substr(0,cur.ch).split('').reverse();
557 } else {
558 var currLine = forwards ? cm.getLine(line).split('') : cm.getLine(line).split('').reverse();
559 }
560
561 for (var index = 0; index < currLine.length; index++) {
562 if (currLine[index] == symb) disBal++;
563 else if (currLine[index] == reverseSymb) disBal--;
564
565 if (disBal == 0) {
566 if (forwards && cur.line == line) return {line: line, ch: index + cur.ch};
567 else if (forwards) return {line: line, ch: index};
568 else return {line: line, ch: currLine.length - index - 1 };
569 }
570 }
571
572 if (forwards) line++;
573 else line--;
574 }
575 }
576
577 function selectCompanionObject(cm, revSymb, inclusive) {
578 var cur = cm.getCursor();
579
580 var end = findMatchedSymbol(cm, cur, revSymb);
581 var start = findMatchedSymbol(cm, end);
582 start.ch += inclusive ? 1 : 0;
583 end.ch += inclusive ? 0 : 1;
584
585 return {start: start, end: end};
586 }
587
588 // These are our motion commands to be used for navigation and selection with
589 // certian other commands. All should return a cursor object.
590 var motionList = ['B', 'E', 'J', 'K', 'H', 'L', 'W', 'Shift-W', "'^'", "'$'", "'%'", 'Esc'];
591
592 motions = {
593 'B': function(cm, times) { return moveToWord(cm, word, -1, times); },
594 'Shift-B': function(cm, times) { return moveToWord(cm, bigWord, -1, times); },
595 'E': function(cm, times) { return moveToWord(cm, word, 1, times, 'end'); },
596 'Shift-E': function(cm, times) { return moveToWord(cm, bigWord, 1, times, 'end'); },
597 'J': function(cm, times) {
598 var cur = cm.getCursor();
599 return {line: cur.line+times, ch : cur.ch};
600 },
601
602 'K': function(cm, times) {
603 var cur = cm.getCursor();
604 return {line: cur.line-times, ch: cur.ch};
605 },
606
607 'H': function(cm, times) {
608 var cur = cm.getCursor();
609 return {line: cur.line, ch: cur.ch-times};
610 },
611
612 'L': function(cm, times) {
613 var cur = cm.getCursor();
614 return {line: cur.line, ch: cur.ch+times};
615 },
616 'W': function(cm, times) { return moveToWord(cm, word, 1, times); },
617 'Shift-W': function(cm, times) { return moveToWord(cm, bigWord, 1, times); },
618 "'^'": function(cm, times) {
619 var cur = cm.getCursor();
620 var line = cm.getLine(cur.line).split('');
621
622 // Empty line :o
623 if (line.length == 0) return cur;
624
625 for (var index = 0; index < line.length; index++) {
626 if (line[index].match(/[^\s]/)) return {line: cur.line, ch: index};
627 }
628 },
629 "'$'": function(cm) {
630 var cur = cm.getCursor();
631 var line = cm.getLine(cur.line);
632 return {line: cur.line, ch: line.length};
633 },
634 "'%'": function(cm) { return findMatchedSymbol(cm, cm.getCursor()); },
635 "Esc" : function(cm) {
636 cm.setOption('vim');
637 reptTimes = 0;
638
639 return cm.getCursor();
640 }
641 };
642
643 // Map our movement actions each operator and non-operational movement
644 motionList.forEach(function(key, index, array) {
645 CodeMirror.keyMap['vim-prefix-d'][key] = function(cm) {
646 // Get our selected range
647 var start = cm.getCursor();
648 var end = motions[key](cm, reptTimes ? reptTimes : 1);
649
650 // Set swap var if range is of negative length
651 if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
652
653 // Take action, switching start and end if swap var is set
654 pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
655 cm.replaceRange("", swap ? end : start, swap ? start : end);
656
657 // And clean up
658 reptTimes = 0;
659 cm.setOption("keyMap", "vim");
660 };
661
662 CodeMirror.keyMap['vim-prefix-c'][key] = function(cm) {
663 var start = cm.getCursor();
664 var end = motions[key](cm, reptTimes ? reptTimes : 1);
665
666 if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
667 pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
668 cm.replaceRange("", swap ? end : start, swap ? start : end);
669
670 reptTimes = 0;
671 cm.setOption('keyMap', 'vim-insert');
672 };
673
674 CodeMirror.keyMap['vim-prefix-y'][key] = function(cm) {
675 var start = cm.getCursor();
676 var end = motions[key](cm, reptTimes ? reptTimes : 1);
677
678 if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true;
679 pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
680
681 reptTimes = 0;
682 cm.setOption("keyMap", "vim");
683 };
684
685 CodeMirror.keyMap['vim'][key] = function(cm) {
686 var cur = motions[key](cm, reptTimes ? reptTimes : 1);
687 cm.setCursor(cur.line, cur.ch);
688
689 reptTimes = 0;
690 };
691 });
692
693 var nums = [1,2,3,4,5,6,7,8,9];
694 nums.forEach(function(key, index, array) {
695 CodeMirror.keyMap['vim'][key] = function (cm) {
696 reptTimes = (reptTimes * 10) + key;
697 };
698 CodeMirror.keyMap['vim-prefix-d'][key] = function (cm) {
699 reptTimes = (reptTimes * 10) + key;
700 };
701 CodeMirror.keyMap['vim-prefix-y'][key] = function (cm) {
702 reptTimes = (reptTimes * 10) + key;
703 };
704 CodeMirror.keyMap['vim-prefix-c'][key] = function (cm) {
705 reptTimes = (reptTimes * 10) + key;
706 };
707 });
708
709 // Create our keymaps for each operator and make xa and xi where x is an operator
710 // change to the corrosponding keymap
711 var operators = ['d', 'y', 'c'];
712 operators.forEach(function(key, index, array) {
713 CodeMirror.keyMap['vim-prefix-'+key+'a'] = {
714 auto: 'vim', nofallthrough: true, style: "fat-cursor"
715 };
716 CodeMirror.keyMap['vim-prefix-'+key+'i'] = {
717 auto: 'vim', nofallthrough: true, style: "fat-cursor"
718 };
719
720 CodeMirror.keyMap['vim-prefix-'+key]['A'] = function(cm) {
721 reptTimes = 0;
722 cm.setOption('keyMap', 'vim-prefix-' + key + 'a');
723 };
724
725 CodeMirror.keyMap['vim-prefix-'+key]['I'] = function(cm) {
726 reptTimes = 0;
727 cm.setOption('keyMap', 'vim-prefix-' + key + 'i');
728 };
729 });
730
731 function regexLastIndexOf(string, pattern, startIndex) {
732 for (var i = startIndex == null ? string.length : startIndex; i >= 0; --i)
733 if (pattern.test(string.charAt(i))) return i;
734 return -1;
735 }
736
737 // Create our text object functions. They work similar to motions but they
738 // return a start cursor as well
739 var textObjectList = ['W', 'Shift-[', 'Shift-9', '['];
740 var textObjects = {
741 'W': function(cm, inclusive) {
742 var cur = cm.getCursor();
743 var line = cm.getLine(cur.line);
744
745 var line_to_char = new String(line.substring(0, cur.ch));
746 var start = regexLastIndexOf(line_to_char, /[^a-zA-Z0-9]/) + 1;
747 var end = motions["E"](cm, 1) ;
748
749 end.ch += inclusive ? 1 : 0 ;
750 return {start: {line: cur.line, ch: start}, end: end };
751 },
752 'Shift-[': function(cm, inclusive) { return selectCompanionObject(cm, '}', inclusive); },
753 'Shift-9': function(cm, inclusive) { return selectCompanionObject(cm, ')', inclusive); },
754 '[': function(cm, inclusive) { return selectCompanionObject(cm, ']', inclusive); }
755 };
756
757 // One function to handle all operation upon text objects. Kinda funky but it works
758 // better than rewriting this code six times
759 function textObjectManipulation(cm, object, remove, insert, inclusive) {
760 // Object is the text object, delete object if remove is true, enter insert
761 // mode if insert is true, inclusive is the difference between a and i
762 var tmp = textObjects[object](cm, inclusive);
763 var start = tmp.start;
764 var end = tmp.end;
765
766 if ((start.line > end.line) || (start.line == end.line && start.ch > end.ch)) var swap = true ;
767
768 pushInBuffer(cm.getRange(swap ? end : start, swap ? start : end));
769 if (remove) cm.replaceRange("", swap ? end : start, swap ? start : end);
770 if (insert) cm.setOption('keyMap', 'vim-insert');
771 }
772
773 // And finally build the keymaps up from the text objects
774 for (var i = 0; i < textObjectList.length; ++i) {
775 var object = textObjectList[i];
776 (function(object) {
777 CodeMirror.keyMap['vim-prefix-di'][object] = function(cm) { textObjectManipulation(cm, object, true, false, false); };
778 CodeMirror.keyMap['vim-prefix-da'][object] = function(cm) { textObjectManipulation(cm, object, true, false, true); };
779 CodeMirror.keyMap['vim-prefix-yi'][object] = function(cm) { textObjectManipulation(cm, object, false, false, false); };
780 CodeMirror.keyMap['vim-prefix-ya'][object] = function(cm) { textObjectManipulation(cm, object, false, false, true); };
781 CodeMirror.keyMap['vim-prefix-ci'][object] = function(cm) { textObjectManipulation(cm, object, true, true, false); };
782 CodeMirror.keyMap['vim-prefix-ca'][object] = function(cm) { textObjectManipulation(cm, object, true, true, true); };
783 })(object)
784 }
785 })();
@@ -0,0 +1,164 b''
1 /**
2 * Tag-closer extension for CodeMirror.
3 *
4 * This extension adds a "closeTag" utility function that can be used with key bindings to
5 * insert a matching end tag after the ">" character of a start tag has been typed. It can
6 * also complete "</" if a matching start tag is found. It will correctly ignore signal
7 * characters for empty tags, comments, CDATA, etc.
8 *
9 * The function depends on internal parser state to identify tags. It is compatible with the
10 * following CodeMirror modes and will ignore all others:
11 * - htmlmixed
12 * - xml
13 *
14 * See demos/closetag.html for a usage example.
15 *
16 * @author Nathan Williams <nathan@nlwillia.net>
17 * Contributed under the same license terms as CodeMirror.
18 */
19 (function() {
20 /** Option that allows tag closing behavior to be toggled. Default is true. */
21 CodeMirror.defaults['closeTagEnabled'] = true;
22
23 /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
24 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'];
25
26 /** Array of tag names where an end tag is forbidden. */
27 CodeMirror.defaults['closeTagVoid'] = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
28
29 /**
30 * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
31 * - cm: The editor instance.
32 * - ch: The character being processed.
33 * - 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.
34 * Pass false to disable indentation. Pass an array to override the default list of tag names.
35 * - 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.
36 */
37 CodeMirror.defineExtension("closeTag", function(cm, ch, indent, vd) {
38 if (!cm.getOption('closeTagEnabled')) {
39 throw CodeMirror.Pass;
40 }
41
42 var mode = cm.getOption('mode');
43
44 if (mode == 'text/html' || mode == 'xml') {
45
46 /*
47 * Relevant structure of token:
48 *
49 * htmlmixed
50 * className
51 * state
52 * htmlState
53 * type
54 * tagName
55 * context
56 * tagName
57 * mode
58 *
59 * xml
60 * className
61 * state
62 * tagName
63 * type
64 */
65
66 var pos = cm.getCursor();
67 var tok = cm.getTokenAt(pos);
68 var state = tok.state;
69
70 if (state.mode && state.mode != 'html') {
71 throw CodeMirror.Pass; // With htmlmixed, we only care about the html sub-mode.
72 }
73
74 if (ch == '>') {
75 var type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
76
77 if (tok.className == 'tag' && type == 'closeTag') {
78 throw CodeMirror.Pass; // Don't process the '>' at the end of an end-tag.
79 }
80
81 cm.replaceSelection('>'); // Mode state won't update until we finish the tag.
82 pos = {line: pos.line, ch: pos.ch + 1};
83 cm.setCursor(pos);
84
85 tok = cm.getTokenAt(cm.getCursor());
86 state = tok.state;
87 type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
88
89 if (tok.className == 'tag' && type != 'selfcloseTag') {
90 var tagName = state.htmlState ? state.htmlState.tagName : state.tagName; // htmlmixed : xml
91 if (tagName.length > 0 && shouldClose(cm, vd, tagName)) {
92 insertEndTag(cm, indent, pos, tagName);
93 }
94 return;
95 }
96
97 // Undo the '>' insert and allow cm to handle the key instead.
98 cm.setSelection({line: pos.line, ch: pos.ch - 1}, pos);
99 cm.replaceSelection("");
100
101 } else if (ch == '/') {
102 if (tok.className == 'tag' && tok.string == '<') {
103 var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : (state.context ? state.context.tagName : ''); // htmlmixed : xml
104 if (tagName.length > 0) {
105 completeEndTag(cm, pos, tagName);
106 return;
107 }
108 }
109 }
110
111 }
112
113 throw CodeMirror.Pass; // Bubble if not handled
114 });
115
116 function insertEndTag(cm, indent, pos, tagName) {
117 if (shouldIndent(cm, indent, tagName)) {
118 cm.replaceSelection('\n\n</' + tagName + '>', 'end');
119 cm.indentLine(pos.line + 1);
120 cm.indentLine(pos.line + 2);
121 cm.setCursor({line: pos.line + 1, ch: cm.getLine(pos.line + 1).length});
122 } else {
123 cm.replaceSelection('</' + tagName + '>');
124 cm.setCursor(pos);
125 }
126 }
127
128 function shouldIndent(cm, indent, tagName) {
129 if (typeof indent == 'undefined' || indent == null || indent == true) {
130 indent = cm.getOption('closeTagIndent');
131 }
132 if (!indent) {
133 indent = [];
134 }
135 return indexOf(indent, tagName.toLowerCase()) != -1;
136 }
137
138 function shouldClose(cm, vd, tagName) {
139 if (cm.getOption('mode') == 'xml') {
140 return true; // always close xml tags
141 }
142 if (typeof vd == 'undefined' || vd == null) {
143 vd = cm.getOption('closeTagVoid');
144 }
145 if (!vd) {
146 vd = [];
147 }
148 return indexOf(vd, tagName.toLowerCase()) == -1;
149 }
150
151 // C&P from codemirror.js...would be nice if this were visible to utilities.
152 function indexOf(collection, elt) {
153 if (collection.indexOf) return collection.indexOf(elt);
154 for (var i = 0, e = collection.length; i < e; ++i)
155 if (collection[i] == elt) return i;
156 return -1;
157 }
158
159 function completeEndTag(cm, pos, tagName) {
160 cm.replaceSelection('/' + tagName + '>');
161 cm.setCursor({line: pos.line, ch: pos.ch + tagName.length + 2 });
162 }
163
164 })();
@@ -0,0 +1,51 b''
1 (function() {
2 if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
3
4 var loading = {};
5 function splitCallback(cont, n) {
6 var countDown = n;
7 return function() { if (--countDown == 0) cont(); }
8 }
9 function ensureDeps(mode, cont) {
10 var deps = CodeMirror.modes[mode].dependencies;
11 if (!deps) return cont();
12 var missing = [];
13 for (var i = 0; i < deps.length; ++i) {
14 if (!CodeMirror.modes.hasOwnProperty(deps[i]))
15 missing.push(deps[i]);
16 }
17 if (!missing.length) return cont();
18 var split = splitCallback(cont, missing.length);
19 for (var i = 0; i < missing.length; ++i)
20 CodeMirror.requireMode(missing[i], split);
21 }
22
23 CodeMirror.requireMode = function(mode, cont) {
24 if (typeof mode != "string") mode = mode.name;
25 if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
26 if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
27
28 var script = document.createElement("script");
29 script.src = CodeMirror.modeURL.replace(/%N/g, mode);
30 var others = document.getElementsByTagName("script")[0];
31 others.parentNode.insertBefore(script, others);
32 var list = loading[mode] = [cont];
33 var count = 0, poll = setInterval(function() {
34 if (++count > 100) return clearInterval(poll);
35 if (CodeMirror.modes.hasOwnProperty(mode)) {
36 clearInterval(poll);
37 loading[mode] = null;
38 ensureDeps(mode, function() {
39 for (var i = 0; i < list.length; ++i) list[i]();
40 });
41 }
42 }, 200);
43 };
44
45 CodeMirror.autoLoadMode = function(instance, mode) {
46 if (!CodeMirror.modes.hasOwnProperty(mode))
47 CodeMirror.requireMode(mode, function() {
48 instance.setOption("mode", instance.getOption("mode"));
49 });
50 };
51 }());
@@ -0,0 +1,44 b''
1 // Define match-highlighter commands. Depends on searchcursor.js
2 // Use by attaching the following function call to the onCursorActivity event:
3 //myCodeMirror.matchHighlight(minChars);
4 // And including a special span.CodeMirror-matchhighlight css class (also optionally a separate one for .CodeMirror-focused -- see demo matchhighlighter.html)
5
6 (function() {
7 var DEFAULT_MIN_CHARS = 2;
8
9 function MatchHighlightState() {
10 this.marked = [];
11 }
12 function getMatchHighlightState(cm) {
13 return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState());
14 }
15
16 function clearMarks(cm) {
17 var state = getMatchHighlightState(cm);
18 for (var i = 0; i < state.marked.length; ++i)
19 state.marked[i].clear();
20 state.marked = [];
21 }
22
23 function markDocument(cm, className, minChars) {
24 clearMarks(cm);
25 minChars = (typeof minChars !== 'undefined' ? minChars : DEFAULT_MIN_CHARS);
26 if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length >= minChars) {
27 var state = getMatchHighlightState(cm);
28 var query = cm.getSelection();
29 cm.operation(function() {
30 if (cm.lineCount() < 2000) { // This is too expensive on big documents.
31 for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
32 //Only apply matchhighlight to the matches other than the one actually selected
33 if (!(cursor.from().line === cm.getCursor(true).line && cursor.from().ch === cm.getCursor(true).ch))
34 state.marked.push(cm.markText(cursor.from(), cursor.to(), className));
35 }
36 }
37 });
38 }
39 }
40
41 CodeMirror.defineExtension("matchHighlight", function(className, minChars) {
42 markDocument(this, className, minChars);
43 });
44 })();
@@ -0,0 +1,81 b''
1 CodeMirror.multiplexingMode = function(outer /*, others */) {
2 // Others should be {open, close, mode [, delimStyle]} objects
3 var others = Array.prototype.slice.call(arguments, 1);
4 var n_others = others.length;
5
6 function indexOf(string, pattern, from) {
7 if (typeof pattern == "string") return string.indexOf(pattern, from);
8 var m = pattern.exec(from ? string.slice(from) : string);
9 return m ? m.index + from : -1;
10 }
11
12 return {
13 startState: function() {
14 return {
15 outer: CodeMirror.startState(outer),
16 innerActive: null,
17 inner: null
18 };
19 },
20
21 copyState: function(state) {
22 return {
23 outer: CodeMirror.copyState(outer, state.outer),
24 innerActive: state.innerActive,
25 inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
26 };
27 },
28
29 token: function(stream, state) {
30 if (!state.innerActive) {
31 var cutOff = Infinity, oldContent = stream.string;
32 for (var i = 0; i < n_others; ++i) {
33 var other = others[i];
34 var found = indexOf(oldContent, other.open, stream.pos);
35 if (found == stream.pos) {
36 stream.match(other.open);
37 state.innerActive = other;
38 state.inner = CodeMirror.startState(other.mode, outer.indent(state.outer, ""));
39 return other.delimStyle;
40 } else if (found != -1 && found < cutOff) {
41 cutOff = found;
42 }
43 }
44 if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
45 var outerToken = outer.token(stream, state.outer);
46 if (cutOff != Infinity) stream.string = oldContent;
47 return outerToken;
48 } else {
49 var curInner = state.innerActive, oldContent = stream.string;
50 var found = indexOf(oldContent, curInner.close, stream.pos);
51 if (found == stream.pos) {
52 stream.match(curInner.close);
53 state.innerActive = state.inner = null;
54 return curInner.delimStyle;
55 }
56 if (found > -1) stream.string = oldContent.slice(0, found);
57 var innerToken = curInner.mode.token(stream, state.inner);
58 if (found > -1) stream.string = oldContent;
59 var cur = stream.current(), found = cur.indexOf(curInner.close);
60 if (found > -1) stream.backUp(cur.length - found);
61 return innerToken;
62 }
63 },
64
65 indent: function(state, textAfter) {
66 var mode = state.innerActive ? state.innerActive.mode : outer;
67 if (!mode.indent) return CodeMirror.Pass;
68 return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
69 },
70
71 compareStates: function(a, b) {
72 if (a.innerActive != b.innerActive) return false;
73 var mode = a.innerActive || outer;
74 if (!mode.compareStates) return CodeMirror.Pass;
75 return mode.compareStates(a.innerActive ? a.inner : a.outer,
76 b.innerActive ? b.inner : b.outer);
77 },
78
79 electricChars: outer.electricChars
80 };
81 };
@@ -0,0 +1,123 b''
1 (function () {
2 function forEach(arr, f) {
3 for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
4 }
5
6 function arrayContains(arr, item) {
7 if (!Array.prototype.indexOf) {
8 var i = arr.length;
9 while (i--) {
10 if (arr[i] === item) {
11 return true;
12 }
13 }
14 return false;
15 }
16 return arr.indexOf(item) != -1;
17 }
18
19 function scriptHint(editor, keywords, getToken) {
20 // Find the token at the cursor
21 var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
22 // If it's not a 'word-style' token, ignore the token.
23
24 if (!/^[\w$_]*$/.test(token.string)) {
25 token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
26 className: token.string == ":" ? "pig-type" : null};
27 }
28
29 if (!context) var context = [];
30 context.push(tprop);
31
32 var completionList = getCompletions(token, context);
33 completionList = completionList.sort();
34 //prevent autocomplete for last word, instead show dropdown with one word
35 if(completionList.length == 1) {
36 completionList.push(" ");
37 }
38
39 return {list: completionList,
40 from: {line: cur.line, ch: token.start},
41 to: {line: cur.line, ch: token.end}};
42 }
43
44 CodeMirror.pigHint = function(editor) {
45 return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
46 }
47
48 function toTitleCase(str) {
49 return str.replace(/(?:^|\s)\w/g, function(match) {
50 return match.toUpperCase();
51 });
52 }
53
54 var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP "
55 + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL "
56 + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE "
57 + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE "
58 + "NEQ MATCHES TRUE FALSE";
59 var pigKeywordsU = pigKeywords.split(" ");
60 var pigKeywordsL = pigKeywords.toLowerCase().split(" ");
61
62 var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP";
63 var pigTypesU = pigTypes.split(" ");
64 var pigTypesL = pigTypes.toLowerCase().split(" ");
65
66 var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL "
67 + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS "
68 + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG "
69 + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN "
70 + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER "
71 + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS "
72 + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA "
73 + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE "
74 + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG "
75 + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER";
76 var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" ");
77 var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" ");
78 var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs "
79 + "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax "
80 + "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum "
81 + "InvokeForDouble InvokeForFloat InvokeForInt InvokeForLong InvokeForString Invoker "
82 + "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize "
83 + "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax "
84 + "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" ");
85
86 function getCompletions(token, context) {
87 var found = [], start = token.string;
88 function maybeAdd(str) {
89 if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
90 }
91
92 function gatherCompletions(obj) {
93 if(obj == ":") {
94 forEach(pigTypesL, maybeAdd);
95 }
96 else {
97 forEach(pigBuiltinsU, maybeAdd);
98 forEach(pigBuiltinsL, maybeAdd);
99 forEach(pigBuiltinsC, maybeAdd);
100 forEach(pigTypesU, maybeAdd);
101 forEach(pigTypesL, maybeAdd);
102 forEach(pigKeywordsU, maybeAdd);
103 forEach(pigKeywordsL, maybeAdd);
104 }
105 }
106
107 if (context) {
108 // If this is a property, see if it belongs to some object we can
109 // find in the current environment.
110 var obj = context.pop(), base;
111
112 if (obj.className == "pig-word")
113 base = obj.string;
114 else if(obj.className == "pig-type")
115 base = ":" + obj.string;
116
117 while (base != null && context.length)
118 base = base[context.pop().string];
119 if (base != null) gatherCompletions(base);
120 }
121 return found;
122 }
123 })();
@@ -0,0 +1,137 b''
1
2 (function() {
3
4 CodeMirror.xmlHints = [];
5
6 CodeMirror.xmlHint = function(cm, simbol) {
7
8 if(simbol.length > 0) {
9 var cursor = cm.getCursor();
10 cm.replaceSelection(simbol);
11 cursor = {line: cursor.line, ch: cursor.ch + 1};
12 cm.setCursor(cursor);
13 }
14
15 // dirty hack for simple-hint to receive getHint event on space
16 var getTokenAt = editor.getTokenAt;
17
18 editor.getTokenAt = function() { return 'disabled'; }
19 CodeMirror.simpleHint(cm, getHint);
20
21 editor.getTokenAt = getTokenAt;
22 };
23
24 var getHint = function(cm) {
25
26 var cursor = cm.getCursor();
27
28 if (cursor.ch > 0) {
29
30 var text = cm.getRange({line: 0, ch: 0}, cursor);
31 var typed = '';
32 var simbol = '';
33 for(var i = text.length - 1; i >= 0; i--) {
34 if(text[i] == ' ' || text[i] == '<') {
35 simbol = text[i];
36 break;
37 }
38 else {
39 typed = text[i] + typed;
40 }
41 }
42
43 text = text.substr(0, text.length - typed.length);
44
45 var path = getActiveElement(cm, text) + simbol;
46 var hints = CodeMirror.xmlHints[path];
47
48 if(typeof hints === 'undefined')
49 hints = [''];
50 else {
51 hints = hints.slice(0);
52 for (var i = hints.length - 1; i >= 0; i--) {
53 if(hints[i].indexOf(typed) != 0)
54 hints.splice(i, 1);
55 }
56 }
57
58 return {
59 list: hints,
60 from: { line: cursor.line, ch: cursor.ch - typed.length },
61 to: cursor,
62 };
63 };
64 }
65
66 var getActiveElement = function(codeMirror, text) {
67
68 var element = '';
69
70 if(text.length >= 0) {
71
72 var regex = new RegExp('<([^!?][^\\s/>]*).*?>', 'g');
73
74 var matches = [];
75 var match;
76 while ((match = regex.exec(text)) != null) {
77 matches.push({
78 tag: match[1],
79 selfclose: (match[0].substr(-1) === '/>')
80 });
81 }
82
83 for (var i = matches.length - 1, skip = 0; i >= 0; i--) {
84
85 var item = matches[i];
86
87 if (item.tag[0] == '/')
88 {
89 skip++;
90 }
91 else if (item.selfclose == false)
92 {
93 if (skip > 0)
94 {
95 skip--;
96 }
97 else
98 {
99 element = '<' + item.tag + '>' + element;
100 }
101 }
102 }
103
104 element += getOpenTag(text);
105 }
106
107 return element;
108 };
109
110 var getOpenTag = function(text) {
111
112 var open = text.lastIndexOf('<');
113 var close = text.lastIndexOf('>');
114
115 if (close < open)
116 {
117 text = text.substr(open);
118
119 if(text != '<') {
120
121 var space = text.indexOf(' ');
122 if(space < 0)
123 space = text.indexOf('\t');
124 if(space < 0)
125 space = text.indexOf('\n');
126
127 if (space < 0)
128 space = text.length;
129
130 return text.substr(0, space);
131 }
132 }
133
134 return '';
135 };
136
137 })();
@@ -0,0 +1,280 b''
1 CodeMirror.defineMode("clike", function(config, parserConfig) {
2 var indentUnit = config.indentUnit,
3 keywords = parserConfig.keywords || {},
4 builtin = parserConfig.builtin || {},
5 blockKeywords = parserConfig.blockKeywords || {},
6 atoms = parserConfig.atoms || {},
7 hooks = parserConfig.hooks || {},
8 multiLineStrings = parserConfig.multiLineStrings;
9 var isOperatorChar = /[+\-*&%=<>!?|\/]/;
10
11 var curPunc;
12
13 function tokenBase(stream, state) {
14 var ch = stream.next();
15 if (hooks[ch]) {
16 var result = hooks[ch](stream, state);
17 if (result !== false) return result;
18 }
19 if (ch == '"' || ch == "'") {
20 state.tokenize = tokenString(ch);
21 return state.tokenize(stream, state);
22 }
23 if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
24 curPunc = ch;
25 return null;
26 }
27 if (/\d/.test(ch)) {
28 stream.eatWhile(/[\w\.]/);
29 return "number";
30 }
31 if (ch == "/") {
32 if (stream.eat("*")) {
33 state.tokenize = tokenComment;
34 return tokenComment(stream, state);
35 }
36 if (stream.eat("/")) {
37 stream.skipToEnd();
38 return "comment";
39 }
40 }
41 if (isOperatorChar.test(ch)) {
42 stream.eatWhile(isOperatorChar);
43 return "operator";
44 }
45 stream.eatWhile(/[\w\$_]/);
46 var cur = stream.current();
47 if (keywords.propertyIsEnumerable(cur)) {
48 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
49 return "keyword";
50 }
51 if (builtin.propertyIsEnumerable(cur)) {
52 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
53 return "builtin";
54 }
55 if (atoms.propertyIsEnumerable(cur)) return "atom";
56 return "variable";
57 }
58
59 function tokenString(quote) {
60 return function(stream, state) {
61 var escaped = false, next, end = false;
62 while ((next = stream.next()) != null) {
63 if (next == quote && !escaped) {end = true; break;}
64 escaped = !escaped && next == "\\";
65 }
66 if (end || !(escaped || multiLineStrings))
67 state.tokenize = null;
68 return "string";
69 };
70 }
71
72 function tokenComment(stream, state) {
73 var maybeEnd = false, ch;
74 while (ch = stream.next()) {
75 if (ch == "/" && maybeEnd) {
76 state.tokenize = null;
77 break;
78 }
79 maybeEnd = (ch == "*");
80 }
81 return "comment";
82 }
83
84 function Context(indented, column, type, align, prev) {
85 this.indented = indented;
86 this.column = column;
87 this.type = type;
88 this.align = align;
89 this.prev = prev;
90 }
91 function pushContext(state, col, type) {
92 return state.context = new Context(state.indented, col, type, null, state.context);
93 }
94 function popContext(state) {
95 var t = state.context.type;
96 if (t == ")" || t == "]" || t == "}")
97 state.indented = state.context.indented;
98 return state.context = state.context.prev;
99 }
100
101 // Interface
102
103 return {
104 startState: function(basecolumn) {
105 return {
106 tokenize: null,
107 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
108 indented: 0,
109 startOfLine: true
110 };
111 },
112
113 token: function(stream, state) {
114 var ctx = state.context;
115 if (stream.sol()) {
116 if (ctx.align == null) ctx.align = false;
117 state.indented = stream.indentation();
118 state.startOfLine = true;
119 }
120 if (stream.eatSpace()) return null;
121 curPunc = null;
122 var style = (state.tokenize || tokenBase)(stream, state);
123 if (style == "comment" || style == "meta") return style;
124 if (ctx.align == null) ctx.align = true;
125
126 if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
127 else if (curPunc == "{") pushContext(state, stream.column(), "}");
128 else if (curPunc == "[") pushContext(state, stream.column(), "]");
129 else if (curPunc == "(") pushContext(state, stream.column(), ")");
130 else if (curPunc == "}") {
131 while (ctx.type == "statement") ctx = popContext(state);
132 if (ctx.type == "}") ctx = popContext(state);
133 while (ctx.type == "statement") ctx = popContext(state);
134 }
135 else if (curPunc == ctx.type) popContext(state);
136 else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
137 pushContext(state, stream.column(), "statement");
138 state.startOfLine = false;
139 return style;
140 },
141
142 indent: function(state, textAfter) {
143 if (state.tokenize != tokenBase && state.tokenize != null) return 0;
144 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
145 if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
146 var closing = firstChar == ctx.type;
147 if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
148 else if (ctx.align) return ctx.column + (closing ? 0 : 1);
149 else return ctx.indented + (closing ? 0 : indentUnit);
150 },
151
152 electricChars: "{}"
153 };
154 });
155
156 (function() {
157 function words(str) {
158 var obj = {}, words = str.split(" ");
159 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
160 return obj;
161 }
162 var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
163 "double static else struct entry switch extern typedef float union for unsigned " +
164 "goto while enum void const signed volatile";
165
166 function cppHook(stream, state) {
167 if (!state.startOfLine) return false;
168 stream.skipToEnd();
169 return "meta";
170 }
171
172 // C#-style strings where "" escapes a quote.
173 function tokenAtString(stream, state) {
174 var next;
175 while ((next = stream.next()) != null) {
176 if (next == '"' && !stream.eat('"')) {
177 state.tokenize = null;
178 break;
179 }
180 }
181 return "string";
182 }
183
184 CodeMirror.defineMIME("text/x-csrc", {
185 name: "clike",
186 keywords: words(cKeywords),
187 blockKeywords: words("case do else for if switch while struct"),
188 atoms: words("null"),
189 hooks: {"#": cppHook}
190 });
191 CodeMirror.defineMIME("text/x-c++src", {
192 name: "clike",
193 keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
194 "static_cast typeid catch operator template typename class friend private " +
195 "this using const_cast inline public throw virtual delete mutable protected " +
196 "wchar_t"),
197 blockKeywords: words("catch class do else finally for if struct switch try while"),
198 atoms: words("true false null"),
199 hooks: {"#": cppHook}
200 });
201 CodeMirror.defineMIME("text/x-java", {
202 name: "clike",
203 keywords: words("abstract assert boolean break byte case catch char class const continue default " +
204 "do double else enum extends final finally float for goto if implements import " +
205 "instanceof int interface long native new package private protected public " +
206 "return short static strictfp super switch synchronized this throw throws transient " +
207 "try void volatile while"),
208 blockKeywords: words("catch class do else finally for if switch try while"),
209 atoms: words("true false null"),
210 hooks: {
211 "@": function(stream, state) {
212 stream.eatWhile(/[\w\$_]/);
213 return "meta";
214 }
215 }
216 });
217 CodeMirror.defineMIME("text/x-csharp", {
218 name: "clike",
219 keywords: words("abstract as base break case catch checked class const continue" +
220 " default delegate do else enum event explicit extern finally fixed for" +
221 " foreach goto if implicit in interface internal is lock namespace new" +
222 " operator out override params private protected public readonly ref return sealed" +
223 " sizeof stackalloc static struct switch this throw try typeof unchecked" +
224 " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
225 " global group into join let orderby partial remove select set value var yield"),
226 blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
227 builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
228 " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
229 " UInt64 bool byte char decimal double short int long object" +
230 " sbyte float string ushort uint ulong"),
231 atoms: words("true false null"),
232 hooks: {
233 "@": function(stream, state) {
234 if (stream.eat('"')) {
235 state.tokenize = tokenAtString;
236 return tokenAtString(stream, state);
237 }
238 stream.eatWhile(/[\w\$_]/);
239 return "meta";
240 }
241 }
242 });
243 CodeMirror.defineMIME("text/x-scala", {
244 name: "clike",
245 keywords: words(
246
247 /* scala */
248 "abstract case catch class def do else extends false final finally for forSome if " +
249 "implicit import lazy match new null object override package private protected return " +
250 "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
251 "<% >: # @ " +
252
253 /* package scala */
254 "assert assume require print println printf readLine readBoolean readByte readShort " +
255 "readChar readInt readLong readFloat readDouble " +
256
257 "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
258 "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
259 "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
260 "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
261 "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
262
263 /* package java.lang */
264 "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
265 "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
266 "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
267 "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
268
269
270 ),
271 blockKeywords: words("catch class do else finally for forSome if match switch try while"),
272 atoms: words("true false null"),
273 hooks: {
274 "@": function(stream, state) {
275 stream.eatWhile(/[\w\$_]/);
276 return "meta";
277 }
278 }
279 });
280 }());
@@ -0,0 +1,101 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: C-like mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="clike.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style>.CodeMirror {border: 2px inset #dee;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: C-like mode</h1>
13
14 <form><textarea id="code" name="code">
15 /* C demo code */
16
17 #include <zmq.h>
18 #include <pthread.h>
19 #include <semaphore.h>
20 #include <time.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <malloc.h>
24
25 typedef struct {
26 void* arg_socket;
27 zmq_msg_t* arg_msg;
28 char* arg_string;
29 unsigned long arg_len;
30 int arg_int, arg_command;
31
32 int signal_fd;
33 int pad;
34 void* context;
35 sem_t sem;
36 } acl_zmq_context;
37
38 #define p(X) (context->arg_##X)
39
40 void* zmq_thread(void* context_pointer) {
41 acl_zmq_context* context = (acl_zmq_context*)context_pointer;
42 char ok = 'K', err = 'X';
43 int res;
44
45 while (1) {
46 while ((res = sem_wait(&amp;context->sem)) == EINTR);
47 if (res) {write(context->signal_fd, &amp;err, 1); goto cleanup;}
48 switch(p(command)) {
49 case 0: goto cleanup;
50 case 1: p(socket) = zmq_socket(context->context, p(int)); break;
51 case 2: p(int) = zmq_close(p(socket)); break;
52 case 3: p(int) = zmq_bind(p(socket), p(string)); break;
53 case 4: p(int) = zmq_connect(p(socket), p(string)); break;
54 case 5: p(int) = zmq_getsockopt(p(socket), p(int), (void*)p(string), &amp;p(len)); break;
55 case 6: p(int) = zmq_setsockopt(p(socket), p(int), (void*)p(string), p(len)); break;
56 case 7: p(int) = zmq_send(p(socket), p(msg), p(int)); break;
57 case 8: p(int) = zmq_recv(p(socket), p(msg), p(int)); break;
58 case 9: p(int) = zmq_poll(p(socket), p(int), p(len)); break;
59 }
60 p(command) = errno;
61 write(context->signal_fd, &amp;ok, 1);
62 }
63 cleanup:
64 close(context->signal_fd);
65 free(context_pointer);
66 return 0;
67 }
68
69 void* zmq_thread_init(void* zmq_context, int signal_fd) {
70 acl_zmq_context* context = malloc(sizeof(acl_zmq_context));
71 pthread_t thread;
72
73 context->context = zmq_context;
74 context->signal_fd = signal_fd;
75 sem_init(&amp;context->sem, 1, 0);
76 pthread_create(&amp;thread, 0, &amp;zmq_thread, context);
77 pthread_detach(thread);
78 return context;
79 }
80 </textarea></form>
81
82 <script>
83 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
84 lineNumbers: true,
85 matchBrackets: true,
86 mode: "text/x-csrc"
87 });
88 </script>
89
90 <p>Simple mode that tries to handle C-like languages as well as it
91 can. Takes two configuration parameters: <code>keywords</code>, an
92 object whose property names are the keywords in the language,
93 and <code>useCPP</code>, which determines whether C preprocessor
94 directives are recognized.</p>
95
96 <p><strong>MIME types defined:</strong> <code>text/x-csrc</code>
97 (C code), <code>text/x-c++src</code> (C++
98 code), <code>text/x-java</code> (Java
99 code), <code>text/x-csharp</code> (C#).</p>
100 </body>
101 </html>
This diff has been collapsed as it changes many lines, (765 lines changed) Show them Hide them
@@ -0,0 +1,765 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: C-like mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <link rel="stylesheet" href="../../theme/ambiance.css">
7 <script src="../../lib/codemirror.js"></script>
8 <script src="clike.js"></script>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 <style>
11 body
12 {
13 margin: 0;
14 padding: 0;
15 max-width:inherit;
16 height: 100%;
17 }
18 html, form, .CodeMirror, .CodeMirror-scroll
19 {
20 height: 100%;
21 }
22 </style>
23 </head>
24 <body>
25 <form>
26 <textarea id="code" name="code">
27
28 /* __ *\
29 ** ________ ___ / / ___ Scala API **
30 ** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
31 ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
32 ** /____/\___/_/ |_/____/_/ | | **
33 ** |/ **
34 \* */
35
36 package scala.collection
37
38 import generic._
39 import mutable.{ Builder, ListBuffer }
40 import annotation.{tailrec, migration, bridge}
41 import annotation.unchecked.{ uncheckedVariance => uV }
42 import parallel.ParIterable
43
44 /** A template trait for traversable collections of type `Traversable[A]`.
45 *
46 * $traversableInfo
47 * @define mutability
48 * @define traversableInfo
49 * This is a base trait of all kinds of $mutability Scala collections. It
50 * implements the behavior common to all collections, in terms of a method
51 * `foreach` with signature:
52 * {{{
53 * def foreach[U](f: Elem => U): Unit
54 * }}}
55 * Collection classes mixing in this trait provide a concrete
56 * `foreach` method which traverses all the
57 * elements contained in the collection, applying a given function to each.
58 * They also need to provide a method `newBuilder`
59 * which creates a builder for collections of the same kind.
60 *
61 * A traversable class might or might not have two properties: strictness
62 * and orderedness. Neither is represented as a type.
63 *
64 * The instances of a strict collection class have all their elements
65 * computed before they can be used as values. By contrast, instances of
66 * a non-strict collection class may defer computation of some of their
67 * elements until after the instance is available as a value.
68 * A typical example of a non-strict collection class is a
69 * <a href="../immutable/Stream.html" target="ContentFrame">
70 * `scala.collection.immutable.Stream`</a>.
71 * A more general class of examples are `TraversableViews`.
72 *
73 * If a collection is an instance of an ordered collection class, traversing
74 * its elements with `foreach` will always visit elements in the
75 * same order, even for different runs of the program. If the class is not
76 * ordered, `foreach` can visit elements in different orders for
77 * different runs (but it will keep the same order in the same run).'
78 *
79 * A typical example of a collection class which is not ordered is a
80 * `HashMap` of objects. The traversal order for hash maps will
81 * depend on the hash codes of its elements, and these hash codes might
82 * differ from one run to the next. By contrast, a `LinkedHashMap`
83 * is ordered because it's `foreach` method visits elements in the
84 * order they were inserted into the `HashMap`.
85 *
86 * @author Martin Odersky
87 * @version 2.8
88 * @since 2.8
89 * @tparam A the element type of the collection
90 * @tparam Repr the type of the actual collection containing the elements.
91 *
92 * @define Coll Traversable
93 * @define coll traversable collection
94 */
95 trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr]
96 with FilterMonadic[A, Repr]
97 with TraversableOnce[A]
98 with GenTraversableLike[A, Repr]
99 with Parallelizable[A, ParIterable[A]]
100 {
101 self =>
102
103 import Traversable.breaks._
104
105 /** The type implementing this traversable */
106 protected type Self = Repr
107
108 /** The collection of type $coll underlying this `TraversableLike` object.
109 * By default this is implemented as the `TraversableLike` object itself,
110 * but this can be overridden.
111 */
112 def repr: Repr = this.asInstanceOf[Repr]
113
114 /** The underlying collection seen as an instance of `$Coll`.
115 * By default this is implemented as the current collection object itself,
116 * but this can be overridden.
117 */
118 protected[this] def thisCollection: Traversable[A] = this.asInstanceOf[Traversable[A]]
119
120 /** A conversion from collections of type `Repr` to `$Coll` objects.
121 * By default this is implemented as just a cast, but this can be overridden.
122 */
123 protected[this] def toCollection(repr: Repr): Traversable[A] = repr.asInstanceOf[Traversable[A]]
124
125 /** Creates a new builder for this collection type.
126 */
127 protected[this] def newBuilder: Builder[A, Repr]
128
129 protected[this] def parCombiner = ParIterable.newCombiner[A]
130
131 /** Applies a function `f` to all elements of this $coll.
132 *
133 * Note: this method underlies the implementation of most other bulk operations.
134 * It's important to implement this method in an efficient way.
135 *
136 *
137 * @param f the function that is applied for its side-effect to every element.
138 * The result of function `f` is discarded.
139 *
140 * @tparam U the type parameter describing the result of function `f`.
141 * This result will always be ignored. Typically `U` is `Unit`,
142 * but this is not necessary.
143 *
144 * @usecase def foreach(f: A => Unit): Unit
145 */
146 def foreach[U](f: A => U): Unit
147
148 /** Tests whether this $coll is empty.
149 *
150 * @return `true` if the $coll contain no elements, `false` otherwise.
151 */
152 def isEmpty: Boolean = {
153 var result = true
154 breakable {
155 for (x <- this) {
156 result = false
157 break
158 }
159 }
160 result
161 }
162
163 /** Tests whether this $coll is known to have a finite size.
164 * All strict collections are known to have finite size. For a non-strict collection
165 * such as `Stream`, the predicate returns `true` if all elements have been computed.
166 * It returns `false` if the stream is not yet evaluated to the end.
167 *
168 * Note: many collection methods will not work on collections of infinite sizes.
169 *
170 * @return `true` if this collection is known to have finite size, `false` otherwise.
171 */
172 def hasDefiniteSize = true
173
174 def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
175 val b = bf(repr)
176 if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.seq.size)
177 b ++= thisCollection
178 b ++= that.seq
179 b.result
180 }
181
182 @bridge
183 def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =
184 ++(that: GenTraversableOnce[B])(bf)
185
186 /** Concatenates this $coll with the elements of a traversable collection.
187 * It differs from ++ in that the right operand determines the type of the
188 * resulting collection rather than the left one.
189 *
190 * @param that the traversable to append.
191 * @tparam B the element type of the returned collection.
192 * @tparam That $thatinfo
193 * @param bf $bfinfo
194 * @return a new collection of type `That` which contains all elements
195 * of this $coll followed by all elements of `that`.
196 *
197 * @usecase def ++:[B](that: TraversableOnce[B]): $Coll[B]
198 *
199 * @return a new $coll which contains all elements of this $coll
200 * followed by all elements of `that`.
201 */
202 def ++:[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
203 val b = bf(repr)
204 if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.size)
205 b ++= that
206 b ++= thisCollection
207 b.result
208 }
209
210 /** This overload exists because: for the implementation of ++: we should reuse
211 * that of ++ because many collections override it with more efficient versions.
212 * Since TraversableOnce has no '++' method, we have to implement that directly,
213 * but Traversable and down can use the overload.
214 */
215 def ++:[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That =
216 (that ++ seq)(breakOut)
217
218 def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
219 val b = bf(repr)
220 b.sizeHint(this)
221 for (x <- this) b += f(x)
222 b.result
223 }
224
225 def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
226 val b = bf(repr)
227 for (x <- this) b ++= f(x).seq
228 b.result
229 }
230
231 /** Selects all elements of this $coll which satisfy a predicate.
232 *
233 * @param p the predicate used to test elements.
234 * @return a new $coll consisting of all elements of this $coll that satisfy the given
235 * predicate `p`. The order of the elements is preserved.
236 */
237 def filter(p: A => Boolean): Repr = {
238 val b = newBuilder
239 for (x <- this)
240 if (p(x)) b += x
241 b.result
242 }
243
244 /** Selects all elements of this $coll which do not satisfy a predicate.
245 *
246 * @param p the predicate used to test elements.
247 * @return a new $coll consisting of all elements of this $coll that do not satisfy the given
248 * predicate `p`. The order of the elements is preserved.
249 */
250 def filterNot(p: A => Boolean): Repr = filter(!p(_))
251
252 def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
253 val b = bf(repr)
254 for (x <- this) if (pf.isDefinedAt(x)) b += pf(x)
255 b.result
256 }
257
258 /** Builds a new collection by applying an option-valued function to all
259 * elements of this $coll on which the function is defined.
260 *
261 * @param f the option-valued function which filters and maps the $coll.
262 * @tparam B the element type of the returned collection.
263 * @tparam That $thatinfo
264 * @param bf $bfinfo
265 * @return a new collection of type `That` resulting from applying the option-valued function
266 * `f` to each element and collecting all defined results.
267 * The order of the elements is preserved.
268 *
269 * @usecase def filterMap[B](f: A => Option[B]): $Coll[B]
270 *
271 * @param pf the partial function which filters and maps the $coll.
272 * @return a new $coll resulting from applying the given option-valued function
273 * `f` to each element and collecting all defined results.
274 * The order of the elements is preserved.
275 def filterMap[B, That](f: A => Option[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
276 val b = bf(repr)
277 for (x <- this)
278 f(x) match {
279 case Some(y) => b += y
280 case _ =>
281 }
282 b.result
283 }
284 */
285
286 /** Partitions this $coll in two ${coll}s according to a predicate.
287 *
288 * @param p the predicate on which to partition.
289 * @return a pair of ${coll}s: the first $coll consists of all elements that
290 * satisfy the predicate `p` and the second $coll consists of all elements
291 * that don't. The relative order of the elements in the resulting ${coll}s
292 * is the same as in the original $coll.
293 */
294 def partition(p: A => Boolean): (Repr, Repr) = {
295 val l, r = newBuilder
296 for (x <- this) (if (p(x)) l else r) += x
297 (l.result, r.result)
298 }
299
300 def groupBy[K](f: A => K): immutable.Map[K, Repr] = {
301 val m = mutable.Map.empty[K, Builder[A, Repr]]
302 for (elem <- this) {
303 val key = f(elem)
304 val bldr = m.getOrElseUpdate(key, newBuilder)
305 bldr += elem
306 }
307 val b = immutable.Map.newBuilder[K, Repr]
308 for ((k, v) <- m)
309 b += ((k, v.result))
310
311 b.result
312 }
313
314 /** Tests whether a predicate holds for all elements of this $coll.
315 *
316 * $mayNotTerminateInf
317 *
318 * @param p the predicate used to test elements.
319 * @return `true` if the given predicate `p` holds for all elements
320 * of this $coll, otherwise `false`.
321 */
322 def forall(p: A => Boolean): Boolean = {
323 var result = true
324 breakable {
325 for (x <- this)
326 if (!p(x)) { result = false; break }
327 }
328 result
329 }
330
331 /** Tests whether a predicate holds for some of the elements of this $coll.
332 *
333 * $mayNotTerminateInf
334 *
335 * @param p the predicate used to test elements.
336 * @return `true` if the given predicate `p` holds for some of the
337 * elements of this $coll, otherwise `false`.
338 */
339 def exists(p: A => Boolean): Boolean = {
340 var result = false
341 breakable {
342 for (x <- this)
343 if (p(x)) { result = true; break }
344 }
345 result
346 }
347
348 /** Finds the first element of the $coll satisfying a predicate, if any.
349 *
350 * $mayNotTerminateInf
351 * $orderDependent
352 *
353 * @param p the predicate used to test elements.
354 * @return an option value containing the first element in the $coll
355 * that satisfies `p`, or `None` if none exists.
356 */
357 def find(p: A => Boolean): Option[A] = {
358 var result: Option[A] = None
359 breakable {
360 for (x <- this)
361 if (p(x)) { result = Some(x); break }
362 }
363 result
364 }
365
366 def scan[B >: A, That](z: B)(op: (B, B) => B)(implicit cbf: CanBuildFrom[Repr, B, That]): That = scanLeft(z)(op)
367
368 def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
369 val b = bf(repr)
370 b.sizeHint(this, 1)
371 var acc = z
372 b += acc
373 for (x <- this) { acc = op(acc, x); b += acc }
374 b.result
375 }
376
377 @migration(2, 9,
378 "This scanRight definition has changed in 2.9.\n" +
379 "The previous behavior can be reproduced with scanRight.reverse."
380 )
381 def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
382 var scanned = List(z)
383 var acc = z
384 for (x <- reversed) {
385 acc = op(x, acc)
386 scanned ::= acc
387 }
388 val b = bf(repr)
389 for (elem <- scanned) b += elem
390 b.result
391 }
392
393 /** Selects the first element of this $coll.
394 * $orderDependent
395 * @return the first element of this $coll.
396 * @throws `NoSuchElementException` if the $coll is empty.
397 */
398 def head: A = {
399 var result: () => A = () => throw new NoSuchElementException
400 breakable {
401 for (x <- this) {
402 result = () => x
403 break
404 }
405 }
406 result()
407 }
408
409 /** Optionally selects the first element.
410 * $orderDependent
411 * @return the first element of this $coll if it is nonempty, `None` if it is empty.
412 */
413 def headOption: Option[A] = if (isEmpty) None else Some(head)
414
415 /** Selects all elements except the first.
416 * $orderDependent
417 * @return a $coll consisting of all elements of this $coll
418 * except the first one.
419 * @throws `UnsupportedOperationException` if the $coll is empty.
420 */
421 override def tail: Repr = {
422 if (isEmpty) throw new UnsupportedOperationException("empty.tail")
423 drop(1)
424 }
425
426 /** Selects the last element.
427 * $orderDependent
428 * @return The last element of this $coll.
429 * @throws NoSuchElementException If the $coll is empty.
430 */
431 def last: A = {
432 var lst = head
433 for (x <- this)
434 lst = x
435 lst
436 }
437
438 /** Optionally selects the last element.
439 * $orderDependent
440 * @return the last element of this $coll$ if it is nonempty, `None` if it is empty.
441 */
442 def lastOption: Option[A] = if (isEmpty) None else Some(last)
443
444 /** Selects all elements except the last.
445 * $orderDependent
446 * @return a $coll consisting of all elements of this $coll
447 * except the last one.
448 * @throws `UnsupportedOperationException` if the $coll is empty.
449 */
450 def init: Repr = {
451 if (isEmpty) throw new UnsupportedOperationException("empty.init")
452 var lst = head
453 var follow = false
454 val b = newBuilder
455 b.sizeHint(this, -1)
456 for (x <- this.seq) {
457 if (follow) b += lst
458 else follow = true
459 lst = x
460 }
461 b.result
462 }
463
464 def take(n: Int): Repr = slice(0, n)
465
466 def drop(n: Int): Repr =
467 if (n <= 0) {
468 val b = newBuilder
469 b.sizeHint(this)
470 b ++= thisCollection result
471 }
472 else sliceWithKnownDelta(n, Int.MaxValue, -n)
473
474 def slice(from: Int, until: Int): Repr = sliceWithKnownBound(math.max(from, 0), until)
475
476 // Precondition: from >= 0, until > 0, builder already configured for building.
477 private[this] def sliceInternal(from: Int, until: Int, b: Builder[A, Repr]): Repr = {
478 var i = 0
479 breakable {
480 for (x <- this.seq) {
481 if (i >= from) b += x
482 i += 1
483 if (i >= until) break
484 }
485 }
486 b.result
487 }
488 // Precondition: from >= 0
489 private[scala] def sliceWithKnownDelta(from: Int, until: Int, delta: Int): Repr = {
490 val b = newBuilder
491 if (until <= from) b.result
492 else {
493 b.sizeHint(this, delta)
494 sliceInternal(from, until, b)
495 }
496 }
497 // Precondition: from >= 0
498 private[scala] def sliceWithKnownBound(from: Int, until: Int): Repr = {
499 val b = newBuilder
500 if (until <= from) b.result
501 else {
502 b.sizeHintBounded(until - from, this)
503 sliceInternal(from, until, b)
504 }
505 }
506
507 def takeWhile(p: A => Boolean): Repr = {
508 val b = newBuilder
509 breakable {
510 for (x <- this) {
511 if (!p(x)) break
512 b += x
513 }
514 }
515 b.result
516 }
517
518 def dropWhile(p: A => Boolean): Repr = {
519 val b = newBuilder
520 var go = false
521 for (x <- this) {
522 if (!p(x)) go = true
523 if (go) b += x
524 }
525 b.result
526 }
527
528 def span(p: A => Boolean): (Repr, Repr) = {
529 val l, r = newBuilder
530 var toLeft = true
531 for (x <- this) {
532 toLeft = toLeft && p(x)
533 (if (toLeft) l else r) += x
534 }
535 (l.result, r.result)
536 }
537
538 def splitAt(n: Int): (Repr, Repr) = {
539 val l, r = newBuilder
540 l.sizeHintBounded(n, this)
541 if (n >= 0) r.sizeHint(this, -n)
542 var i = 0
543 for (x <- this) {
544 (if (i < n) l else r) += x
545 i += 1
546 }
547 (l.result, r.result)
548 }
549
550 /** Iterates over the tails of this $coll. The first value will be this
551 * $coll and the final one will be an empty $coll, with the intervening
552 * values the results of successive applications of `tail`.
553 *
554 * @return an iterator over all the tails of this $coll
555 * @example `List(1,2,3).tails = Iterator(List(1,2,3), List(2,3), List(3), Nil)`
556 */
557 def tails: Iterator[Repr] = iterateUntilEmpty(_.tail)
558
559 /** Iterates over the inits of this $coll. The first value will be this
560 * $coll and the final one will be an empty $coll, with the intervening
561 * values the results of successive applications of `init`.
562 *
563 * @return an iterator over all the inits of this $coll
564 * @example `List(1,2,3).inits = Iterator(List(1,2,3), List(1,2), List(1), Nil)`
565 */
566 def inits: Iterator[Repr] = iterateUntilEmpty(_.init)
567
568 /** Copies elements of this $coll to an array.
569 * Fills the given array `xs` with at most `len` elements of
570 * this $coll, starting at position `start`.
571 * Copying will stop once either the end of the current $coll is reached,
572 * or the end of the array is reached, or `len` elements have been copied.
573 *
574 * $willNotTerminateInf
575 *
576 * @param xs the array to fill.
577 * @param start the starting index.
578 * @param len the maximal number of elements to copy.
579 * @tparam B the type of the elements of the array.
580 *
581 *
582 * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
583 */
584 def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {
585 var i = start
586 val end = (start + len) min xs.length
587 breakable {
588 for (x <- this) {
589 if (i >= end) break
590 xs(i) = x
591 i += 1
592 }
593 }
594 }
595
596 def toTraversable: Traversable[A] = thisCollection
597 def toIterator: Iterator[A] = toStream.iterator
598 def toStream: Stream[A] = toBuffer.toStream
599
600 /** Converts this $coll to a string.
601 *
602 * @return a string representation of this collection. By default this
603 * string consists of the `stringPrefix` of this $coll,
604 * followed by all elements separated by commas and enclosed in parentheses.
605 */
606 override def toString = mkString(stringPrefix + "(", ", ", ")")
607
608 /** Defines the prefix of this object's `toString` representation.
609 *
610 * @return a string representation which starts the result of `toString`
611 * applied to this $coll. By default the string prefix is the
612 * simple name of the collection class $coll.
613 */
614 def stringPrefix : String = {
615 var string = repr.asInstanceOf[AnyRef].getClass.getName
616 val idx1 = string.lastIndexOf('.' : Int)
617 if (idx1 != -1) string = string.substring(idx1 + 1)
618 val idx2 = string.indexOf('$')
619 if (idx2 != -1) string = string.substring(0, idx2)
620 string
621 }
622
623 /** Creates a non-strict view of this $coll.
624 *
625 * @return a non-strict view of this $coll.
626 */
627 def view = new TraversableView[A, Repr] {
628 protected lazy val underlying = self.repr
629 override def foreach[U](f: A => U) = self foreach f
630 }
631
632 /** Creates a non-strict view of a slice of this $coll.
633 *
634 * Note: the difference between `view` and `slice` is that `view` produces
635 * a view of the current $coll, whereas `slice` produces a new $coll.
636 *
637 * Note: `view(from, to)` is equivalent to `view.slice(from, to)`
638 * $orderDependent
639 *
640 * @param from the index of the first element of the view
641 * @param until the index of the element following the view
642 * @return a non-strict view of a slice of this $coll, starting at index `from`
643 * and extending up to (but not including) index `until`.
644 */
645 def view(from: Int, until: Int): TraversableView[A, Repr] = view.slice(from, until)
646
647 /** Creates a non-strict filter of this $coll.
648 *
649 * Note: the difference between `c filter p` and `c withFilter p` is that
650 * the former creates a new collection, whereas the latter only
651 * restricts the domain of subsequent `map`, `flatMap`, `foreach`,
652 * and `withFilter` operations.
653 * $orderDependent
654 *
655 * @param p the predicate used to test elements.
656 * @return an object of class `WithFilter`, which supports
657 * `map`, `flatMap`, `foreach`, and `withFilter` operations.
658 * All these operations apply to those elements of this $coll which
659 * satisfy the predicate `p`.
660 */
661 def withFilter(p: A => Boolean): FilterMonadic[A, Repr] = new WithFilter(p)
662
663 /** A class supporting filtered operations. Instances of this class are
664 * returned by method `withFilter`.
665 */
666 class WithFilter(p: A => Boolean) extends FilterMonadic[A, Repr] {
667
668 /** Builds a new collection by applying a function to all elements of the
669 * outer $coll containing this `WithFilter` instance that satisfy predicate `p`.
670 *
671 * @param f the function to apply to each element.
672 * @tparam B the element type of the returned collection.
673 * @tparam That $thatinfo
674 * @param bf $bfinfo
675 * @return a new collection of type `That` resulting from applying
676 * the given function `f` to each element of the outer $coll
677 * that satisfies predicate `p` and collecting the results.
678 *
679 * @usecase def map[B](f: A => B): $Coll[B]
680 *
681 * @return a new $coll resulting from applying the given function
682 * `f` to each element of the outer $coll that satisfies
683 * predicate `p` and collecting the results.
684 */
685 def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
686 val b = bf(repr)
687 for (x <- self)
688 if (p(x)) b += f(x)
689 b.result
690 }
691
692 /** Builds a new collection by applying a function to all elements of the
693 * outer $coll containing this `WithFilter` instance that satisfy
694 * predicate `p` and concatenating the results.
695 *
696 * @param f the function to apply to each element.
697 * @tparam B the element type of the returned collection.
698 * @tparam That $thatinfo
699 * @param bf $bfinfo
700 * @return a new collection of type `That` resulting from applying
701 * the given collection-valued function `f` to each element
702 * of the outer $coll that satisfies predicate `p` and
703 * concatenating the results.
704 *
705 * @usecase def flatMap[B](f: A => TraversableOnce[B]): $Coll[B]
706 *
707 * @return a new $coll resulting from applying the given collection-valued function
708 * `f` to each element of the outer $coll that satisfies predicate `p` and concatenating the results.
709 */
710 def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
711 val b = bf(repr)
712 for (x <- self)
713 if (p(x)) b ++= f(x).seq
714 b.result
715 }
716
717 /** Applies a function `f` to all elements of the outer $coll containing
718 * this `WithFilter` instance that satisfy predicate `p`.
719 *
720 * @param f the function that is applied for its side-effect to every element.
721 * The result of function `f` is discarded.
722 *
723 * @tparam U the type parameter describing the result of function `f`.
724 * This result will always be ignored. Typically `U` is `Unit`,
725 * but this is not necessary.
726 *
727 * @usecase def foreach(f: A => Unit): Unit
728 */
729 def foreach[U](f: A => U): Unit =
730 for (x <- self)
731 if (p(x)) f(x)
732
733 /** Further refines the filter for this $coll.
734 *
735 * @param q the predicate used to test elements.
736 * @return an object of class `WithFilter`, which supports
737 * `map`, `flatMap`, `foreach`, and `withFilter` operations.
738 * All these operations apply to those elements of this $coll which
739 * satisfy the predicate `q` in addition to the predicate `p`.
740 */
741 def withFilter(q: A => Boolean): WithFilter =
742 new WithFilter(x => p(x) && q(x))
743 }
744
745 // A helper for tails and inits.
746 private def iterateUntilEmpty(f: Traversable[A @uV] => Traversable[A @uV]): Iterator[Repr] = {
747 val it = Iterator.iterate(thisCollection)(f) takeWhile (x => !x.isEmpty)
748 it ++ Iterator(Nil) map (newBuilder ++= _ result)
749 }
750 }
751
752
753 </textarea>
754 </form>
755
756 <script>
757 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
758 lineNumbers: true,
759 matchBrackets: true,
760 theme: "ambiance",
761 mode: "text/x-scala"
762 });
763 </script>
764 </body>
765 </html>
@@ -0,0 +1,207 b''
1 /**
2 * Author: Hans Engel
3 * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
4 */
5 CodeMirror.defineMode("clojure", function (config, mode) {
6 var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", TAG = "tag",
7 ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword";
8 var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;
9
10 function makeKeywords(str) {
11 var obj = {}, words = str.split(" ");
12 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
13 return obj;
14 }
15
16 var atoms = makeKeywords("true false nil");
17
18 var keywords = makeKeywords(
19 "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
20
21 var builtins = makeKeywords(
22 "* *1 *2 *3 *agent* *allow-unresolved-vars* *assert *clojure-version* *command-line-args* *compile-files* *compile-path* *e *err* *file* *flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *use-context-classloader* *warn-on-reflection* + - / < <= = == > >= accessor aclone agent agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec decimal? declare definline defmacro defmethod defmulti defn defn- defonce defstruct delay delay? deliver deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall doc dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq eval even? every? extend extend-protocol extend-type extends? extenders false? ffirst file-seq filter find find-doc find-ns find-var first float float-array float? floats flush fn fn? fnext for force format future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator hash hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map? mapcat max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod name namespace neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? or parents partial partition pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-doc print-dup print-method print-namespace-doc print-simple print-special-doc print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string reify reduce ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure release-pending-sends rem remove remove-method remove-ns repeat repeatedly replace replicate require reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-validator! set? short short-array shorts shutdown-agents slurp some sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-form-anchor special-symbol? split-at split-with str stream? string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync syntax-symbol-anchor take take-last take-nth take-while test the-ns time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-dec unchecked-divide unchecked-inc unchecked-multiply unchecked-negate unchecked-remainder unchecked-subtract underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision xml-seq");
23
24 var indentKeys = makeKeywords(
25 // Built-ins
26 "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
27
28 // Binding forms
29 "let letfn binding loop for doseq dotimes when-let if-let " +
30
31 // Data structures
32 "defstruct struct-map assoc " +
33
34 // clojure.test
35 "testing deftest " +
36
37 // contrib
38 "handler-case handle dotrace deftrace");
39
40 var tests = {
41 digit: /\d/,
42 digit_or_colon: /[\d:]/,
43 hex: /[0-9a-fA-F]/,
44 sign: /[+-]/,
45 exponent: /[eE]/,
46 keyword_char: /[^\s\(\[\;\)\]]/,
47 basic: /[\w\$_\-]/,
48 lang_keyword: /[\w*+!\-_?:\/]/
49 };
50
51 function stateStack(indent, type, prev) { // represents a state stack object
52 this.indent = indent;
53 this.type = type;
54 this.prev = prev;
55 }
56
57 function pushStack(state, indent, type) {
58 state.indentStack = new stateStack(indent, type, state.indentStack);
59 }
60
61 function popStack(state) {
62 state.indentStack = state.indentStack.prev;
63 }
64
65 function isNumber(ch, stream){
66 // hex
67 if ( ch === '0' && 'x' == stream.peek().toLowerCase() ) {
68 stream.eat('x');
69 stream.eatWhile(tests.hex);
70 return true;
71 }
72
73 // leading sign
74 if ( ch == '+' || ch == '-' ) {
75 stream.eat(tests.sign);
76 ch = stream.next();
77 }
78
79 if ( tests.digit.test(ch) ) {
80 stream.eat(ch);
81 stream.eatWhile(tests.digit);
82
83 if ( '.' == stream.peek() ) {
84 stream.eat('.');
85 stream.eatWhile(tests.digit);
86 }
87
88 if ( 'e' == stream.peek().toLowerCase() ) {
89 stream.eat(tests.exponent);
90 stream.eat(tests.sign);
91 stream.eatWhile(tests.digit);
92 }
93
94 return true;
95 }
96
97 return false;
98 }
99
100 return {
101 startState: function () {
102 return {
103 indentStack: null,
104 indentation: 0,
105 mode: false
106 };
107 },
108
109 token: function (stream, state) {
110 if (state.indentStack == null && stream.sol()) {
111 // update indentation, but only if indentStack is empty
112 state.indentation = stream.indentation();
113 }
114
115 // skip spaces
116 if (stream.eatSpace()) {
117 return null;
118 }
119 var returnType = null;
120
121 switch(state.mode){
122 case "string": // multi-line string parsing mode
123 var next, escaped = false;
124 while ((next = stream.next()) != null) {
125 if (next == "\"" && !escaped) {
126
127 state.mode = false;
128 break;
129 }
130 escaped = !escaped && next == "\\";
131 }
132 returnType = STRING; // continue on in string mode
133 break;
134 default: // default parsing mode
135 var ch = stream.next();
136
137 if (ch == "\"") {
138 state.mode = "string";
139 returnType = STRING;
140 } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
141 returnType = ATOM;
142 } else if (ch == ";") { // comment
143 stream.skipToEnd(); // rest of the line is a comment
144 returnType = COMMENT;
145 } else if (isNumber(ch,stream)){
146 returnType = NUMBER;
147 } else if (ch == "(" || ch == "[") {
148 var keyWord = ''; var indentTemp = stream.column();
149 /**
150 Either
151 (indent-word ..
152 (non-indent-word ..
153 (;something else, bracket, etc.
154 */
155
156 if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
157 keyWord += letter;
158 }
159
160 if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word
161 pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
162 } else { // non-indent word
163 // we continue eating the spaces
164 stream.eatSpace();
165 if (stream.eol() || stream.peek() == ";") {
166 // nothing significant after
167 // we restart indentation 1 space after
168 pushStack(state, indentTemp + 1, ch);
169 } else {
170 pushStack(state, indentTemp + stream.current().length, ch); // else we match
171 }
172 }
173 stream.backUp(stream.current().length - 1); // undo all the eating
174
175 returnType = BRACKET;
176 } else if (ch == ")" || ch == "]") {
177 returnType = BRACKET;
178 if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
179 popStack(state);
180 }
181 } else if ( ch == ":" ) {
182 stream.eatWhile(tests.lang_keyword);
183 return ATOM;
184 } else {
185 stream.eatWhile(tests.basic);
186
187 if (keywords && keywords.propertyIsEnumerable(stream.current())) {
188 returnType = KEYWORD;
189 } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
190 returnType = BUILTIN;
191 } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
192 returnType = ATOM;
193 } else returnType = null;
194 }
195 }
196
197 return returnType;
198 },
199
200 indent: function (state, textAfter) {
201 if (state.indentStack == null) return state.indentation;
202 return state.indentStack.indent;
203 }
204 };
205 });
206
207 CodeMirror.defineMIME("text/x-clojure", "clojure");
@@ -0,0 +1,66 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Clojure mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="clojure.js"></script>
8 <style>.CodeMirror {background: #f8f8f8;}</style>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 </head>
11 <body>
12 <h1>CodeMirror: Clojure mode</h1>
13 <form><textarea id="code" name="code">
14 ; Conway's Game of Life, based on the work of:
15 ;; Laurent Petit https://gist.github.com/1200343
16 ;; Christophe Grand http://clj-me.cgrand.net/2011/08/19/conways-game-of-life
17
18 (ns ^{:doc "Conway's Game of Life."}
19 game-of-life)
20
21 ;; Core game of life's algorithm functions
22
23 (defn neighbours
24 "Given a cell's coordinates, returns the coordinates of its neighbours."
25 [[x y]]
26 (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
27 [(+ dx x) (+ dy y)]))
28
29 (defn step
30 "Given a set of living cells, computes the new set of living cells."
31 [cells]
32 (set (for [[cell n] (frequencies (mapcat neighbours cells))
33 :when (or (= n 3) (and (= n 2) (cells cell)))]
34 cell)))
35
36 ;; Utility methods for displaying game on a text terminal
37
38 (defn print-board
39 "Prints a board on *out*, representing a step in the game."
40 [board w h]
41 (doseq [x (range (inc w)) y (range (inc h))]
42 (if (= y 0) (print "\n"))
43 (print (if (board [x y]) "[X]" " . "))))
44
45 (defn display-grids
46 "Prints a squence of boards on *out*, representing several steps."
47 [grids w h]
48 (doseq [board grids]
49 (print-board board w h)
50 (print "\n")))
51
52 ;; Launches an example board
53
54 (def
55 ^{:doc "board represents the initial set of living cells"}
56 board #{[2 1] [2 2] [2 3]})
57
58 (display-grids (take 3 (iterate step board)) 5 5) </textarea></form>
59 <script>
60 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
61 </script>
62
63 <p><strong>MIME types defined:</strong> <code>text/x-clojure</code>.</p>
64
65 </body>
66 </html>
@@ -0,0 +1,22 b''
1 The MIT License
2
3 Copyright (c) 2011 Jeff Pickhardt
4 Modified from the Python CodeMirror mode, Copyright (c) 2010 Timothy Farrell
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE. No newline at end of file
@@ -0,0 +1,346 b''
1 /**
2 * Link to the project's GitHub page:
3 * https://github.com/pickhardt/coffeescript-codemirror-mode
4 */
5 CodeMirror.defineMode('coffeescript', function(conf) {
6 var ERRORCLASS = 'error';
7
8 function wordRegexp(words) {
9 return new RegExp("^((" + words.join(")|(") + "))\\b");
10 }
11
12 var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\?]");
13 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\},:`=;\\.]');
14 var doubleOperators = new RegExp("^((\->)|(\=>)|(\\+\\+)|(\\+\\=)|(\\-\\-)|(\\-\\=)|(\\*\\*)|(\\*\\=)|(\\/\\/)|(\\/\\=)|(==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//))");
15 var doubleDelimiters = new RegExp("^((\\.\\.)|(\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
16 var tripleDelimiters = new RegExp("^((\\.\\.\\.)|(//=)|(>>=)|(<<=)|(\\*\\*=))");
17 var identifiers = new RegExp("^[_A-Za-z$][_A-Za-z$0-9]*");
18 var properties = new RegExp("^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*");
19
20 var wordOperators = wordRegexp(['and', 'or', 'not',
21 'is', 'isnt', 'in',
22 'instanceof', 'typeof']);
23 var indentKeywords = ['for', 'while', 'loop', 'if', 'unless', 'else',
24 'switch', 'try', 'catch', 'finally', 'class'];
25 var commonKeywords = ['break', 'by', 'continue', 'debugger', 'delete',
26 'do', 'in', 'of', 'new', 'return', 'then',
27 'this', 'throw', 'when', 'until'];
28
29 var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
30
31 indentKeywords = wordRegexp(indentKeywords);
32
33
34 var stringPrefixes = new RegExp("^('{3}|\"{3}|['\"])");
35 var regexPrefixes = new RegExp("^(/{3}|/)");
36 var commonConstants = ['Infinity', 'NaN', 'undefined', 'null', 'true', 'false', 'on', 'off', 'yes', 'no'];
37 var constants = wordRegexp(commonConstants);
38
39 // Tokenizers
40 function tokenBase(stream, state) {
41 // Handle scope changes
42 if (stream.sol()) {
43 var scopeOffset = state.scopes[0].offset;
44 if (stream.eatSpace()) {
45 var lineOffset = stream.indentation();
46 if (lineOffset > scopeOffset) {
47 return 'indent';
48 } else if (lineOffset < scopeOffset) {
49 return 'dedent';
50 }
51 return null;
52 } else {
53 if (scopeOffset > 0) {
54 dedent(stream, state);
55 }
56 }
57 }
58 if (stream.eatSpace()) {
59 return null;
60 }
61
62 var ch = stream.peek();
63
64 // Handle docco title comment (single line)
65 if (stream.match("####")) {
66 stream.skipToEnd();
67 return 'comment';
68 }
69
70 // Handle multi line comments
71 if (stream.match("###")) {
72 state.tokenize = longComment;
73 return state.tokenize(stream, state);
74 }
75
76 // Single line comment
77 if (ch === '#') {
78 stream.skipToEnd();
79 return 'comment';
80 }
81
82 // Handle number literals
83 if (stream.match(/^-?[0-9\.]/, false)) {
84 var floatLiteral = false;
85 // Floats
86 if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
87 floatLiteral = true;
88 }
89 if (stream.match(/^-?\d+\.\d*/)) {
90 floatLiteral = true;
91 }
92 if (stream.match(/^-?\.\d+/)) {
93 floatLiteral = true;
94 }
95
96 if (floatLiteral) {
97 // prevent from getting extra . on 1..
98 if (stream.peek() == "."){
99 stream.backUp(1);
100 }
101 return 'number';
102 }
103 // Integers
104 var intLiteral = false;
105 // Hex
106 if (stream.match(/^-?0x[0-9a-f]+/i)) {
107 intLiteral = true;
108 }
109 // Decimal
110 if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
111 intLiteral = true;
112 }
113 // Zero by itself with no other piece of number.
114 if (stream.match(/^-?0(?![\dx])/i)) {
115 intLiteral = true;
116 }
117 if (intLiteral) {
118 return 'number';
119 }
120 }
121
122 // Handle strings
123 if (stream.match(stringPrefixes)) {
124 state.tokenize = tokenFactory(stream.current(), 'string');
125 return state.tokenize(stream, state);
126 }
127 // Handle regex literals
128 if (stream.match(regexPrefixes)) {
129 if (stream.current() != '/' || stream.match(/^.*\//, false)) { // prevent highlight of division
130 state.tokenize = tokenFactory(stream.current(), 'string-2');
131 return state.tokenize(stream, state);
132 } else {
133 stream.backUp(1);
134 }
135 }
136
137 // Handle operators and delimiters
138 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
139 return 'punctuation';
140 }
141 if (stream.match(doubleOperators)
142 || stream.match(singleOperators)
143 || stream.match(wordOperators)) {
144 return 'operator';
145 }
146 if (stream.match(singleDelimiters)) {
147 return 'punctuation';
148 }
149
150 if (stream.match(constants)) {
151 return 'atom';
152 }
153
154 if (stream.match(keywords)) {
155 return 'keyword';
156 }
157
158 if (stream.match(identifiers)) {
159 return 'variable';
160 }
161
162 if (stream.match(properties)) {
163 return 'property';
164 }
165
166 // Handle non-detected items
167 stream.next();
168 return ERRORCLASS;
169 }
170
171 function tokenFactory(delimiter, outclass) {
172 var singleline = delimiter.length == 1;
173 return function tokenString(stream, state) {
174 while (!stream.eol()) {
175 stream.eatWhile(/[^'"\/\\]/);
176 if (stream.eat('\\')) {
177 stream.next();
178 if (singleline && stream.eol()) {
179 return outclass;
180 }
181 } else if (stream.match(delimiter)) {
182 state.tokenize = tokenBase;
183 return outclass;
184 } else {
185 stream.eat(/['"\/]/);
186 }
187 }
188 if (singleline) {
189 if (conf.mode.singleLineStringErrors) {
190 outclass = ERRORCLASS
191 } else {
192 state.tokenize = tokenBase;
193 }
194 }
195 return outclass;
196 };
197 }
198
199 function longComment(stream, state) {
200 while (!stream.eol()) {
201 stream.eatWhile(/[^#]/);
202 if (stream.match("###")) {
203 state.tokenize = tokenBase;
204 break;
205 }
206 stream.eatWhile("#");
207 }
208 return "comment"
209 }
210
211 function indent(stream, state, type) {
212 type = type || 'coffee';
213 var indentUnit = 0;
214 if (type === 'coffee') {
215 for (var i = 0; i < state.scopes.length; i++) {
216 if (state.scopes[i].type === 'coffee') {
217 indentUnit = state.scopes[i].offset + conf.indentUnit;
218 break;
219 }
220 }
221 } else {
222 indentUnit = stream.column() + stream.current().length;
223 }
224 state.scopes.unshift({
225 offset: indentUnit,
226 type: type
227 });
228 }
229
230 function dedent(stream, state) {
231 if (state.scopes.length == 1) return;
232 if (state.scopes[0].type === 'coffee') {
233 var _indent = stream.indentation();
234 var _indent_index = -1;
235 for (var i = 0; i < state.scopes.length; ++i) {
236 if (_indent === state.scopes[i].offset) {
237 _indent_index = i;
238 break;
239 }
240 }
241 if (_indent_index === -1) {
242 return true;
243 }
244 while (state.scopes[0].offset !== _indent) {
245 state.scopes.shift();
246 }
247 return false
248 } else {
249 state.scopes.shift();
250 return false;
251 }
252 }
253
254 function tokenLexer(stream, state) {
255 var style = state.tokenize(stream, state);
256 var current = stream.current();
257
258 // Handle '.' connected identifiers
259 if (current === '.') {
260 style = state.tokenize(stream, state);
261 current = stream.current();
262 if (style === 'variable') {
263 return 'variable';
264 } else {
265 return ERRORCLASS;
266 }
267 }
268
269 // Handle scope changes.
270 if (current === 'return') {
271 state.dedent += 1;
272 }
273 if (((current === '->' || current === '=>') &&
274 !state.lambda &&
275 state.scopes[0].type == 'coffee' &&
276 stream.peek() === '')
277 || style === 'indent') {
278 indent(stream, state);
279 }
280 var delimiter_index = '[({'.indexOf(current);
281 if (delimiter_index !== -1) {
282 indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
283 }
284 if (indentKeywords.exec(current)){
285 indent(stream, state);
286 }
287 if (current == 'then'){
288 dedent(stream, state);
289 }
290
291
292 if (style === 'dedent') {
293 if (dedent(stream, state)) {
294 return ERRORCLASS;
295 }
296 }
297 delimiter_index = '])}'.indexOf(current);
298 if (delimiter_index !== -1) {
299 if (dedent(stream, state)) {
300 return ERRORCLASS;
301 }
302 }
303 if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
304 if (state.scopes.length > 1) state.scopes.shift();
305 state.dedent -= 1;
306 }
307
308 return style;
309 }
310
311 var external = {
312 startState: function(basecolumn) {
313 return {
314 tokenize: tokenBase,
315 scopes: [{offset:basecolumn || 0, type:'coffee'}],
316 lastToken: null,
317 lambda: false,
318 dedent: 0
319 };
320 },
321
322 token: function(stream, state) {
323 var style = tokenLexer(stream, state);
324
325 state.lastToken = {style:style, content: stream.current()};
326
327 if (stream.eol() && stream.lambda) {
328 state.lambda = false;
329 }
330
331 return style;
332 },
333
334 indent: function(state, textAfter) {
335 if (state.tokenize != tokenBase) {
336 return 0;
337 }
338
339 return state.scopes[0].offset;
340 }
341
342 };
343 return external;
344 });
345
346 CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');
This diff has been collapsed as it changes many lines, (727 lines changed) Show them Hide them
@@ -0,0 +1,727 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: CoffeeScript mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="coffeescript.js"></script>
8 <style>.CodeMirror {border-top: 1px solid silver; border-bottom: 1px solid silver;}</style>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 </head>
11 <body>
12 <h1>CodeMirror: CoffeeScript mode</h1>
13 <form><textarea id="code" name="code">
14 # CoffeeScript mode for CodeMirror
15 # Copyright (c) 2011 Jeff Pickhardt, released under
16 # the MIT License.
17 #
18 # Modified from the Python CodeMirror mode, which also is
19 # under the MIT License Copyright (c) 2010 Timothy Farrell.
20 #
21 # The following script, Underscore.coffee, is used to
22 # demonstrate CoffeeScript mode for CodeMirror.
23 #
24 # To download CoffeeScript mode for CodeMirror, go to:
25 # https://github.com/pickhardt/coffeescript-codemirror-mode
26
27 # **Underscore.coffee
28 # (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**
29 # Underscore is freely distributable under the terms of the
30 # [MIT license](http://en.wikipedia.org/wiki/MIT_License).
31 # Portions of Underscore are inspired by or borrowed from
32 # [Prototype.js](http://prototypejs.org/api), Oliver Steele's
33 # [Functional](http://osteele.com), and John Resig's
34 # [Micro-Templating](http://ejohn.org).
35 # For all details and documentation:
36 # http://documentcloud.github.com/underscore/
37
38
39 # Baseline setup
40 # --------------
41
42 # Establish the root object, `window` in the browser, or `global` on the server.
43 root = this
44
45
46 # Save the previous value of the `_` variable.
47 previousUnderscore = root._
48
49 ### Multiline
50 comment
51 ###
52
53 # Establish the object that gets thrown to break out of a loop iteration.
54 # `StopIteration` is SOP on Mozilla.
55 breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
56
57
58 #### Docco style single line comment (title)
59
60
61 # Helper function to escape **RegExp** contents, because JS doesn't have one.
62 escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')
63
64
65 # Save bytes in the minified (but not gzipped) version:
66 ArrayProto = Array.prototype
67 ObjProto = Object.prototype
68
69
70 # Create quick reference variables for speed access to core prototypes.
71 slice = ArrayProto.slice
72 unshift = ArrayProto.unshift
73 toString = ObjProto.toString
74 hasOwnProperty = ObjProto.hasOwnProperty
75 propertyIsEnumerable = ObjProto.propertyIsEnumerable
76
77
78 # All **ECMA5** native implementations we hope to use are declared here.
79 nativeForEach = ArrayProto.forEach
80 nativeMap = ArrayProto.map
81 nativeReduce = ArrayProto.reduce
82 nativeReduceRight = ArrayProto.reduceRight
83 nativeFilter = ArrayProto.filter
84 nativeEvery = ArrayProto.every
85 nativeSome = ArrayProto.some
86 nativeIndexOf = ArrayProto.indexOf
87 nativeLastIndexOf = ArrayProto.lastIndexOf
88 nativeIsArray = Array.isArray
89 nativeKeys = Object.keys
90
91
92 # Create a safe reference to the Underscore object for use below.
93 _ = (obj) -> new wrapper(obj)
94
95
96 # Export the Underscore object for **CommonJS**.
97 if typeof(exports) != 'undefined' then exports._ = _
98
99
100 # Export Underscore to global scope.
101 root._ = _
102
103
104 # Current version.
105 _.VERSION = '1.1.0'
106
107
108 # Collection Functions
109 # --------------------
110
111 # The cornerstone, an **each** implementation.
112 # Handles objects implementing **forEach**, arrays, and raw objects.
113 _.each = (obj, iterator, context) ->
114 try
115 if nativeForEach and obj.forEach is nativeForEach
116 obj.forEach iterator, context
117 else if _.isNumber obj.length
118 iterator.call context, obj[i], i, obj for i in [0...obj.length]
119 else
120 iterator.call context, val, key, obj for own key, val of obj
121 catch e
122 throw e if e isnt breaker
123 obj
124
125
126 # Return the results of applying the iterator to each element. Use JavaScript
127 # 1.6's version of **map**, if possible.
128 _.map = (obj, iterator, context) ->
129 return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
130 results = []
131 _.each obj, (value, index, list) ->
132 results.push iterator.call context, value, index, list
133 results
134
135
136 # **Reduce** builds up a single result from a list of values. Also known as
137 # **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.
138 _.reduce = (obj, iterator, memo, context) ->
139 if nativeReduce and obj.reduce is nativeReduce
140 iterator = _.bind iterator, context if context
141 return obj.reduce iterator, memo
142 _.each obj, (value, index, list) ->
143 memo = iterator.call context, memo, value, index, list
144 memo
145
146
147 # The right-associative version of **reduce**, also known as **foldr**. Uses
148 # JavaScript 1.8's version of **reduceRight**, if available.
149 _.reduceRight = (obj, iterator, memo, context) ->
150 if nativeReduceRight and obj.reduceRight is nativeReduceRight
151 iterator = _.bind iterator, context if context
152 return obj.reduceRight iterator, memo
153 reversed = _.clone(_.toArray(obj)).reverse()
154 _.reduce reversed, iterator, memo, context
155
156
157 # Return the first value which passes a truth test.
158 _.detect = (obj, iterator, context) ->
159 result = null
160 _.each obj, (value, index, list) ->
161 if iterator.call context, value, index, list
162 result = value
163 _.breakLoop()
164 result
165
166
167 # Return all the elements that pass a truth test. Use JavaScript 1.6's
168 # **filter**, if it exists.
169 _.filter = (obj, iterator, context) ->
170 return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
171 results = []
172 _.each obj, (value, index, list) ->
173 results.push value if iterator.call context, value, index, list
174 results
175
176
177 # Return all the elements for which a truth test fails.
178 _.reject = (obj, iterator, context) ->
179 results = []
180 _.each obj, (value, index, list) ->
181 results.push value if not iterator.call context, value, index, list
182 results
183
184
185 # Determine whether all of the elements match a truth test. Delegate to
186 # JavaScript 1.6's **every**, if it is present.
187 _.every = (obj, iterator, context) ->
188 iterator ||= _.identity
189 return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
190 result = true
191 _.each obj, (value, index, list) ->
192 _.breakLoop() unless (result = result and iterator.call(context, value, index, list))
193 result
194
195
196 # Determine if at least one element in the object matches a truth test. Use
197 # JavaScript 1.6's **some**, if it exists.
198 _.some = (obj, iterator, context) ->
199 iterator ||= _.identity
200 return obj.some iterator, context if nativeSome and obj.some is nativeSome
201 result = false
202 _.each obj, (value, index, list) ->
203 _.breakLoop() if (result = iterator.call(context, value, index, list))
204 result
205
206
207 # Determine if a given value is included in the array or object,
208 # based on `===`.
209 _.include = (obj, target) ->
210 return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
211 return true for own key, val of obj when val is target
212 false
213
214
215 # Invoke a method with arguments on every item in a collection.
216 _.invoke = (obj, method) ->
217 args = _.rest arguments, 2
218 (if method then val[method] else val).apply(val, args) for val in obj
219
220
221 # Convenience version of a common use case of **map**: fetching a property.
222 _.pluck = (obj, key) ->
223 _.map(obj, (val) -> val[key])
224
225
226 # Return the maximum item or (item-based computation).
227 _.max = (obj, iterator, context) ->
228 return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
229 result = computed: -Infinity
230 _.each obj, (value, index, list) ->
231 computed = if iterator then iterator.call(context, value, index, list) else value
232 computed >= result.computed and (result = {value: value, computed: computed})
233 result.value
234
235
236 # Return the minimum element (or element-based computation).
237 _.min = (obj, iterator, context) ->
238 return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
239 result = computed: Infinity
240 _.each obj, (value, index, list) ->
241 computed = if iterator then iterator.call(context, value, index, list) else value
242 computed < result.computed and (result = {value: value, computed: computed})
243 result.value
244
245
246 # Sort the object's values by a criterion produced by an iterator.
247 _.sortBy = (obj, iterator, context) ->
248 _.pluck(((_.map obj, (value, index, list) ->
249 {value: value, criteria: iterator.call(context, value, index, list)}
250 ).sort((left, right) ->
251 a = left.criteria; b = right.criteria
252 if a < b then -1 else if a > b then 1 else 0
253 )), 'value')
254
255
256 # Use a comparator function to figure out at what index an object should
257 # be inserted so as to maintain order. Uses binary search.
258 _.sortedIndex = (array, obj, iterator) ->
259 iterator ||= _.identity
260 low = 0
261 high = array.length
262 while low < high
263 mid = (low + high) >> 1
264 if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid
265 low
266
267
268 # Convert anything iterable into a real, live array.
269 _.toArray = (iterable) ->
270 return [] if (!iterable)
271 return iterable.toArray() if (iterable.toArray)
272 return iterable if (_.isArray(iterable))
273 return slice.call(iterable) if (_.isArguments(iterable))
274 _.values(iterable)
275
276
277 # Return the number of elements in an object.
278 _.size = (obj) -> _.toArray(obj).length
279
280
281 # Array Functions
282 # ---------------
283
284 # Get the first element of an array. Passing `n` will return the first N
285 # values in the array. Aliased as **head**. The `guard` check allows it to work
286 # with **map**.
287 _.first = (array, n, guard) ->
288 if n and not guard then slice.call(array, 0, n) else array[0]
289
290
291 # Returns everything but the first entry of the array. Aliased as **tail**.
292 # Especially useful on the arguments object. Passing an `index` will return
293 # the rest of the values in the array from that index onward. The `guard`
294 # check allows it to work with **map**.
295 _.rest = (array, index, guard) ->
296 slice.call(array, if _.isUndefined(index) or guard then 1 else index)
297
298
299 # Get the last element of an array.
300 _.last = (array) -> array[array.length - 1]
301
302
303 # Trim out all falsy values from an array.
304 _.compact = (array) -> item for item in array when item
305
306
307 # Return a completely flattened version of an array.
308 _.flatten = (array) ->
309 _.reduce array, (memo, value) ->
310 return memo.concat(_.flatten(value)) if _.isArray value
311 memo.push value
312 memo
313 , []
314
315
316 # Return a version of the array that does not contain the specified value(s).
317 _.without = (array) ->
318 values = _.rest arguments
319 val for val in _.toArray(array) when not _.include values, val
320
321
322 # Produce a duplicate-free version of the array. If the array has already
323 # been sorted, you have the option of using a faster algorithm.
324 _.uniq = (array, isSorted) ->
325 memo = []
326 for el, i in _.toArray array
327 memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
328 memo
329
330
331 # Produce an array that contains every item shared between all the
332 # passed-in arrays.
333 _.intersect = (array) ->
334 rest = _.rest arguments
335 _.select _.uniq(array), (item) ->
336 _.all rest, (other) ->
337 _.indexOf(other, item) >= 0
338
339
340 # Zip together multiple lists into a single array -- elements that share
341 # an index go together.
342 _.zip = ->
343 length = _.max _.pluck arguments, 'length'
344 results = new Array length
345 for i in [0...length]
346 results[i] = _.pluck arguments, String i
347 results
348
349
350 # If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),
351 # we need this function. Return the position of the first occurrence of an
352 # item in an array, or -1 if the item is not included in the array.
353 _.indexOf = (array, item) ->
354 return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
355 i = 0; l = array.length
356 while l - i
357 if array[i] is item then return i else i++
358 -1
359
360
361 # Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,
362 # if possible.
363 _.lastIndexOf = (array, item) ->
364 return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
365 i = array.length
366 while i
367 if array[i] is item then return i else i--
368 -1
369
370
371 # Generate an integer Array containing an arithmetic progression. A port of
372 # [the native Python **range** function](http://docs.python.org/library/functions.html#range).
373 _.range = (start, stop, step) ->
374 a = arguments
375 solo = a.length <= 1
376 i = start = if solo then 0 else a[0]
377 stop = if solo then a[0] else a[1]
378 step = a[2] or 1
379 len = Math.ceil((stop - start) / step)
380 return [] if len <= 0
381 range = new Array len
382 idx = 0
383 loop
384 return range if (if step > 0 then i - stop else stop - i) >= 0
385 range[idx] = i
386 idx++
387 i+= step
388
389
390 # Function Functions
391 # ------------------
392
393 # Create a function bound to a given object (assigning `this`, and arguments,
394 # optionally). Binding with arguments is also known as **curry**.
395 _.bind = (func, obj) ->
396 args = _.rest arguments, 2
397 -> func.apply obj or root, args.concat arguments
398
399
400 # Bind all of an object's methods to that object. Useful for ensuring that
401 # all callbacks defined on an object belong to it.
402 _.bindAll = (obj) ->
403 funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
404 _.each funcs, (f) -> obj[f] = _.bind obj[f], obj
405 obj
406
407
408 # Delays a function for the given number of milliseconds, and then calls
409 # it with the arguments supplied.
410 _.delay = (func, wait) ->
411 args = _.rest arguments, 2
412 setTimeout((-> func.apply(func, args)), wait)
413
414
415 # Memoize an expensive function by storing its results.
416 _.memoize = (func, hasher) ->
417 memo = {}
418 hasher or= _.identity
419 ->
420 key = hasher.apply this, arguments
421 return memo[key] if key of memo
422 memo[key] = func.apply this, arguments
423
424
425 # Defers a function, scheduling it to run after the current call stack has
426 # cleared.
427 _.defer = (func) ->
428 _.delay.apply _, [func, 1].concat _.rest arguments
429
430
431 # Returns the first function passed as an argument to the second,
432 # allowing you to adjust arguments, run code before and after, and
433 # conditionally execute the original function.
434 _.wrap = (func, wrapper) ->
435 -> wrapper.apply wrapper, [func].concat arguments
436
437
438 # Returns a function that is the composition of a list of functions, each
439 # consuming the return value of the function that follows.
440 _.compose = ->
441 funcs = arguments
442 ->
443 args = arguments
444 for i in [funcs.length - 1..0] by -1
445 args = [funcs[i].apply(this, args)]
446 args[0]
447
448
449 # Object Functions
450 # ----------------
451
452 # Retrieve the names of an object's properties.
453 _.keys = nativeKeys or (obj) ->
454 return _.range 0, obj.length if _.isArray(obj)
455 key for key, val of obj
456
457
458 # Retrieve the values of an object's properties.
459 _.values = (obj) ->
460 _.map obj, _.identity
461
462
463 # Return a sorted list of the function names available in Underscore.
464 _.functions = (obj) ->
465 _.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
466
467
468 # Extend a given object with all of the properties in a source object.
469 _.extend = (obj) ->
470 for source in _.rest(arguments)
471 obj[key] = val for key, val of source
472 obj
473
474
475 # Create a (shallow-cloned) duplicate of an object.
476 _.clone = (obj) ->
477 return obj.slice 0 if _.isArray obj
478 _.extend {}, obj
479
480
481 # Invokes interceptor with the obj, and then returns obj.
482 # The primary purpose of this method is to "tap into" a method chain,
483 # in order to perform operations on intermediate results within
484 the chain.
485 _.tap = (obj, interceptor) ->
486 interceptor obj
487 obj
488
489
490 # Perform a deep comparison to check if two objects are equal.
491 _.isEqual = (a, b) ->
492 # Check object identity.
493 return true if a is b
494 # Different types?
495 atype = typeof(a); btype = typeof(b)
496 return false if atype isnt btype
497 # Basic equality test (watch out for coercions).
498 return true if `a == b`
499 # One is falsy and the other truthy.
500 return false if (!a and b) or (a and !b)
501 # One of them implements an `isEqual()`?
502 return a.isEqual(b) if a.isEqual
503 # Check dates' integer values.
504 return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
505 # Both are NaN?
506 return false if _.isNaN(a) and _.isNaN(b)
507 # Compare regular expressions.
508 if _.isRegExp(a) and _.isRegExp(b)
509 return a.source is b.source and
510 a.global is b.global and
511 a.ignoreCase is b.ignoreCase and
512 a.multiline is b.multiline
513 # If a is not an object by this point, we can't handle it.
514 return false if atype isnt 'object'
515 # Check for different array lengths before comparing contents.
516 return false if a.length and (a.length isnt b.length)
517 # Nothing else worked, deep compare the contents.
518 aKeys = _.keys(a); bKeys = _.keys(b)
519 # Different object sizes?
520 return false if aKeys.length isnt bKeys.length
521 # Recursive comparison of contents.
522 return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
523 true
524
525
526 # Is a given array or object empty?
527 _.isEmpty = (obj) ->
528 return obj.length is 0 if _.isArray(obj) or _.isString(obj)
529 return false for own key of obj
530 true
531
532
533 # Is a given value a DOM element?
534 _.isElement = (obj) -> obj and obj.nodeType is 1
535
536
537 # Is a given value an array?
538 _.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)
539
540
541 # Is a given variable an arguments object?
542 _.isArguments = (obj) -> obj and obj.callee
543
544
545 # Is the given value a function?
546 _.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
547
548
549 # Is the given value a string?
550 _.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
551
552
553 # Is a given value a number?
554 _.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
555
556
557 # Is a given value a boolean?
558 _.isBoolean = (obj) -> obj is true or obj is false
559
560
561 # Is a given value a Date?
562 _.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
563
564
565 # Is the given value a regular expression?
566 _.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
567
568
569 # Is the given value NaN -- this one is interesting. `NaN != NaN`, and
570 # `isNaN(undefined) == true`, so we make sure it's a number first.
571 _.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj)
572
573
574 # Is a given value equal to null?
575 _.isNull = (obj) -> obj is null
576
577
578 # Is a given variable undefined?
579 _.isUndefined = (obj) -> typeof obj is 'undefined'
580
581
582 # Utility Functions
583 # -----------------
584
585 # Run Underscore.js in noConflict mode, returning the `_` variable to its
586 # previous owner. Returns a reference to the Underscore object.
587 _.noConflict = ->
588 root._ = previousUnderscore
589 this
590
591
592 # Keep the identity function around for default iterators.
593 _.identity = (value) -> value
594
595
596 # Run a function `n` times.
597 _.times = (n, iterator, context) ->
598 iterator.call context, i for i in [0...n]
599
600
601 # Break out of the middle of an iteration.
602 _.breakLoop = -> throw breaker
603
604
605 # Add your own custom functions to the Underscore object, ensuring that
606 # they're correctly added to the OOP wrapper as well.
607 _.mixin = (obj) ->
608 for name in _.functions(obj)
609 addToWrapper name, _[name] = obj[name]
610
611
612 # Generate a unique integer id (unique within the entire client session).
613 # Useful for temporary DOM ids.
614 idCounter = 0
615 _.uniqueId = (prefix) ->
616 (prefix or '') + idCounter++
617
618
619 # By default, Underscore uses **ERB**-style template delimiters, change the
620 # following template settings to use alternative delimiters.
621 _.templateSettings = {
622 start: '<%'
623 end: '%>'
624 interpolate: /<%=(.+?)%>/g
625 }
626
627
628 # JavaScript templating a-la **ERB**, pilfered from John Resig's
629 # *Secrets of the JavaScript Ninja*, page 83.
630 # Single-quote fix from Rick Strahl.
631 # With alterations for arbitrary delimiters, and to preserve whitespace.
632 _.template = (str, data) ->
633 c = _.templateSettings
634 endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
635 fn = new Function 'obj',
636 'var p=[],print=function(){p.push.apply(p,arguments);};' +
637 'with(obj||{}){p.push(\'' +
638 str.replace(/\r/g, '\\r')
639 .replace(/\n/g, '\\n')
640 .replace(/\t/g, '\\t')
641 .replace(endMatch,"���")
642 .split("'").join("\\'")
643 .split("���").join("'")
644 .replace(c.interpolate, "',$1,'")
645 .split(c.start).join("');")
646 .split(c.end).join("p.push('") +
647 "');}return p.join('');"
648 if data then fn(data) else fn
649
650
651 # Aliases
652 # -------
653
654 _.forEach = _.each
655 _.foldl = _.inject = _.reduce
656 _.foldr = _.reduceRight
657 _.select = _.filter
658 _.all = _.every
659 _.any = _.some
660 _.contains = _.include
661 _.head = _.first
662 _.tail = _.rest
663 _.methods = _.functions
664
665
666 # Setup the OOP Wrapper
667 # ---------------------
668
669 # If Underscore is called as a function, it returns a wrapped object that
670 # can be used OO-style. This wrapper holds altered versions of all the
671 # underscore functions. Wrapped objects may be chained.
672 wrapper = (obj) ->
673 this._wrapped = obj
674 this
675
676
677 # Helper function to continue chaining intermediate results.
678 result = (obj, chain) ->
679 if chain then _(obj).chain() else obj
680
681
682 # A method to easily add functions to the OOP wrapper.
683 addToWrapper = (name, func) ->
684 wrapper.prototype[name] = ->
685 args = _.toArray arguments
686 unshift.call args, this._wrapped
687 result func.apply(_, args), this._chain
688
689
690 # Add all ofthe Underscore functions to the wrapper object.
691 _.mixin _
692
693
694 # Add all mutator Array functions to the wrapper.
695 _.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
696 method = Array.prototype[name]
697 wrapper.prototype[name] = ->
698 method.apply(this._wrapped, arguments)
699 result(this._wrapped, this._chain)
700
701
702 # Add all accessor Array functions to the wrapper.
703 _.each ['concat', 'join', 'slice'], (name) ->
704 method = Array.prototype[name]
705 wrapper.prototype[name] = ->
706 result(method.apply(this._wrapped, arguments), this._chain)
707
708
709 # Start chaining a wrapped Underscore object.
710 wrapper::chain = ->
711 this._chain = true
712 this
713
714
715 # Extracts the result from a wrapped and chained object.
716 wrapper::value = -> this._wrapped
717 </textarea></form>
718 <script>
719 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
720 </script>
721
722 <p><strong>MIME types defined:</strong> <code>text/x-coffeescript</code>.</p>
723
724 <p>The CoffeeScript mode was written by Jeff Pickhardt (<a href="LICENSE">license</a>).</p>
725
726 </body>
727 </html>
@@ -0,0 +1,32 b''
1 CodeMirror.defineMode("diff", function() {
2
3 var TOKEN_NAMES = {
4 '+': 'tag',
5 '-': 'string',
6 '@': 'meta'
7 };
8
9 return {
10 token: function(stream) {
11 var tw_pos = stream.string.search(/[\t ]+?$/);
12
13 if (!stream.sol() || tw_pos === 0) {
14 stream.skipToEnd();
15 return ("error " + (
16 TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, '');
17 }
18
19 var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd();
20
21 if (tw_pos === -1) {
22 stream.skipToEnd();
23 } else {
24 stream.pos = tw_pos;
25 }
26
27 return token_name;
28 }
29 };
30 });
31
32 CodeMirror.defineMIME("text/x-diff", "diff");
@@ -0,0 +1,104 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Diff mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="diff.js"></script>
8 <style>
9 .CodeMirror {border-top: 1px solid #ddd; border-bottom: 1px solid #ddd;}
10 span.cm-meta {color: #a0b !important;}
11 span.cm-error { background-color: black; opacity: 0.4;}
12 span.cm-error.cm-string { background-color: red; }
13 span.cm-error.cm-tag { background-color: #2b2; }
14 </style>
15 <link rel="stylesheet" href="../../doc/docs.css">
16 </head>
17 <body>
18 <h1>CodeMirror: Diff mode</h1>
19 <form><textarea id="code" name="code">
20 diff --git a/index.html b/index.html
21 index c1d9156..7764744 100644
22 --- a/index.html
23 +++ b/index.html
24 @@ -95,7 +95,8 @@ StringStream.prototype = {
25 <script>
26 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
27 lineNumbers: true,
28 - autoMatchBrackets: true
29 + autoMatchBrackets: true,
30 + onGutterClick: function(x){console.log(x);}
31 });
32 </script>
33 </body>
34 diff --git a/lib/codemirror.js b/lib/codemirror.js
35 index 04646a9..9a39cc7 100644
36 --- a/lib/codemirror.js
37 +++ b/lib/codemirror.js
38 @@ -399,10 +399,16 @@ var CodeMirror = (function() {
39 }
40
41 function onMouseDown(e) {
42 - var start = posFromMouse(e), last = start;
43 + var start = posFromMouse(e), last = start, target = e.target();
44 if (!start) return;
45 setCursor(start.line, start.ch, false);
46 if (e.button() != 1) return;
47 + if (target.parentNode == gutter) {
48 + if (options.onGutterClick)
49 + options.onGutterClick(indexOf(gutter.childNodes, target) + showingFrom);
50 + return;
51 + }
52 +
53 if (!focused) onFocus();
54
55 e.stop();
56 @@ -808,7 +814,7 @@ var CodeMirror = (function() {
57 for (var i = showingFrom; i < showingTo; ++i) {
58 var marker = lines[i].gutterMarker;
59 if (marker) html.push('<div class="' + marker.style + '">' + htmlEscape(marker.text) + '</div>');
60 - else html.push("<div>" + (options.lineNumbers ? i + 1 : "\u00a0") + "</div>");
61 + else html.push("<div>" + (options.lineNumbers ? i + options.firstLineNumber : "\u00a0") + "</div>");
62 }
63 gutter.style.display = "none"; // TODO test whether this actually helps
64 gutter.innerHTML = html.join("");
65 @@ -1371,10 +1377,8 @@ var CodeMirror = (function() {
66 if (option == "parser") setParser(value);
67 else if (option === "lineNumbers") setLineNumbers(value);
68 else if (option === "gutter") setGutter(value);
69 - else if (option === "readOnly") options.readOnly = value;
70 - else if (option === "indentUnit") {options.indentUnit = indentUnit = value; setParser(options.parser);}
71 - else if (/^(?:enterMode|tabMode|indentWithTabs|readOnly|autoMatchBrackets|undoDepth)$/.test(option)) options[option] = value;
72 - else throw new Error("Can't set option " + option);
73 + else if (option === "indentUnit") {options.indentUnit = value; setParser(options.parser);}
74 + else options[option] = value;
75 },
76 cursorCoords: cursorCoords,
77 undo: operation(undo),
78 @@ -1402,7 +1406,8 @@ var CodeMirror = (function() {
79 replaceRange: operation(replaceRange),
80
81 operation: function(f){return operation(f)();},
82 - refresh: function(){updateDisplay([{from: 0, to: lines.length}]);}
83 + refresh: function(){updateDisplay([{from: 0, to: lines.length}]);},
84 + getInputField: function(){return input;}
85 };
86 return instance;
87 }
88 @@ -1420,6 +1425,7 @@ var CodeMirror = (function() {
89 readOnly: false,
90 onChange: null,
91 onCursorActivity: null,
92 + onGutterClick: null,
93 autoMatchBrackets: false,
94 workTime: 200,
95 workDelay: 300,
96 </textarea></form>
97 <script>
98 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
99 </script>
100
101 <p><strong>MIME types defined:</strong> <code>text/x-diff</code>.</p>
102
103 </body>
104 </html>
@@ -0,0 +1,203 b''
1 CodeMirror.defineMode("ecl", function(config) {
2
3 function words(str) {
4 var obj = {}, words = str.split(" ");
5 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
6 return obj;
7 }
8
9 function metaHook(stream, state) {
10 if (!state.startOfLine) return false;
11 stream.skipToEnd();
12 return "meta";
13 }
14
15 function tokenAtString(stream, state) {
16 var next;
17 while ((next = stream.next()) != null) {
18 if (next == '"' && !stream.eat('"')) {
19 state.tokenize = null;
20 break;
21 }
22 }
23 return "string";
24 }
25
26 var indentUnit = config.indentUnit;
27 var keyword = words("abs acos allnodes ascii asin asstring atan atan2 ave case choose choosen choosesets clustersize combine correlation cos cosh count covariance cron dataset dedup define denormalize distribute distributed distribution ebcdic enth error evaluate event eventextra eventname exists exp failcode failmessage fetch fromunicode getisvalid global graph group hash hash32 hash64 hashcrc hashmd5 having if index intformat isvalid iterate join keyunicode length library limit ln local log loop map matched matchlength matchposition matchtext matchunicode max merge mergejoin min nolocal nonempty normalize parse pipe power preload process project pull random range rank ranked realformat recordof regexfind regexreplace regroup rejected rollup round roundup row rowdiff sample set sin sinh sizeof soapcall sort sorted sqrt stepped stored sum table tan tanh thisnode topn tounicode transfer trim truncate typeof ungroup unicodeorder variance which workunit xmldecode xmlencode xmltext xmlunicode");
28 var variable = words("apply assert build buildindex evaluate fail keydiff keypatch loadxml nothor notify output parallel sequential soapcall wait");
29 var variable_2 = words("__compressed__ all and any as atmost before beginc++ best between case const counter csv descend encrypt end endc++ endmacro except exclusive expire export extend false few first flat from full function group header heading hole ifblock import in interface joined keep keyed last left limit load local locale lookup macro many maxcount maxlength min skew module named nocase noroot noscan nosort not of only opt or outer overwrite packed partition penalty physicallength pipe quote record relationship repeat return right scan self separator service shared skew skip sql store terminator thor threshold token transform trim true type unicodeorder unsorted validate virtual whole wild within xml xpath");
30 var variable_3 = words("ascii big_endian boolean data decimal ebcdic integer pattern qstring real record rule set of string token udecimal unicode unsigned varstring varunicode");
31 var builtin = words("checkpoint deprecated failcode failmessage failure global independent onwarning persist priority recovery stored success wait when");
32 var blockKeywords = words("catch class do else finally for if switch try while");
33 var atoms = words("true false null");
34 var hooks = {"#": metaHook};
35 var multiLineStrings;
36 var isOperatorChar = /[+\-*&%=<>!?|\/]/;
37
38 var curPunc;
39
40 function tokenBase(stream, state) {
41 var ch = stream.next();
42 if (hooks[ch]) {
43 var result = hooks[ch](stream, state);
44 if (result !== false) return result;
45 }
46 if (ch == '"' || ch == "'") {
47 state.tokenize = tokenString(ch);
48 return state.tokenize(stream, state);
49 }
50 if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
51 curPunc = ch;
52 return null
53 }
54 if (/\d/.test(ch)) {
55 stream.eatWhile(/[\w\.]/);
56 return "number";
57 }
58 if (ch == "/") {
59 if (stream.eat("*")) {
60 state.tokenize = tokenComment;
61 return tokenComment(stream, state);
62 }
63 if (stream.eat("/")) {
64 stream.skipToEnd();
65 return "comment";
66 }
67 }
68 if (isOperatorChar.test(ch)) {
69 stream.eatWhile(isOperatorChar);
70 return "operator";
71 }
72 stream.eatWhile(/[\w\$_]/);
73 var cur = stream.current().toLowerCase();
74 if (keyword.propertyIsEnumerable(cur)) {
75 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
76 return "keyword";
77 } else if (variable.propertyIsEnumerable(cur)) {
78 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
79 return "variable";
80 } else if (variable_2.propertyIsEnumerable(cur)) {
81 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
82 return "variable-2";
83 } else if (variable_3.propertyIsEnumerable(cur)) {
84 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
85 return "variable-3";
86 } else if (builtin.propertyIsEnumerable(cur)) {
87 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
88 return "builtin";
89 } else { //Data types are of from KEYWORD##
90 var i = cur.length - 1;
91 while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_'))
92 --i;
93
94 if (i > 0) {
95 var cur2 = cur.substr(0, i + 1);
96 if (variable_3.propertyIsEnumerable(cur2)) {
97 if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement";
98 return "variable-3";
99 }
100 }
101 }
102 if (atoms.propertyIsEnumerable(cur)) return "atom";
103 return null;
104 }
105
106 function tokenString(quote) {
107 return function(stream, state) {
108 var escaped = false, next, end = false;
109 while ((next = stream.next()) != null) {
110 if (next == quote && !escaped) {end = true; break;}
111 escaped = !escaped && next == "\\";
112 }
113 if (end || !(escaped || multiLineStrings))
114 state.tokenize = tokenBase;
115 return "string";
116 };
117 }
118
119 function tokenComment(stream, state) {
120 var maybeEnd = false, ch;
121 while (ch = stream.next()) {
122 if (ch == "/" && maybeEnd) {
123 state.tokenize = tokenBase;
124 break;
125 }
126 maybeEnd = (ch == "*");
127 }
128 return "comment";
129 }
130
131 function Context(indented, column, type, align, prev) {
132 this.indented = indented;
133 this.column = column;
134 this.type = type;
135 this.align = align;
136 this.prev = prev;
137 }
138 function pushContext(state, col, type) {
139 return state.context = new Context(state.indented, col, type, null, state.context);
140 }
141 function popContext(state) {
142 var t = state.context.type;
143 if (t == ")" || t == "]" || t == "}")
144 state.indented = state.context.indented;
145 return state.context = state.context.prev;
146 }
147
148 // Interface
149
150 return {
151 startState: function(basecolumn) {
152 return {
153 tokenize: null,
154 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
155 indented: 0,
156 startOfLine: true
157 };
158 },
159
160 token: function(stream, state) {
161 var ctx = state.context;
162 if (stream.sol()) {
163 if (ctx.align == null) ctx.align = false;
164 state.indented = stream.indentation();
165 state.startOfLine = true;
166 }
167 if (stream.eatSpace()) return null;
168 curPunc = null;
169 var style = (state.tokenize || tokenBase)(stream, state);
170 if (style == "comment" || style == "meta") return style;
171 if (ctx.align == null) ctx.align = true;
172
173 if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
174 else if (curPunc == "{") pushContext(state, stream.column(), "}");
175 else if (curPunc == "[") pushContext(state, stream.column(), "]");
176 else if (curPunc == "(") pushContext(state, stream.column(), ")");
177 else if (curPunc == "}") {
178 while (ctx.type == "statement") ctx = popContext(state);
179 if (ctx.type == "}") ctx = popContext(state);
180 while (ctx.type == "statement") ctx = popContext(state);
181 }
182 else if (curPunc == ctx.type) popContext(state);
183 else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
184 pushContext(state, stream.column(), "statement");
185 state.startOfLine = false;
186 return style;
187 },
188
189 indent: function(state, textAfter) {
190 if (state.tokenize != tokenBase && state.tokenize != null) return 0;
191 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
192 if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
193 var closing = firstChar == ctx.type;
194 if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
195 else if (ctx.align) return ctx.column + (closing ? 0 : 1);
196 else return ctx.indented + (closing ? 0 : indentUnit);
197 },
198
199 electricChars: "{}"
200 };
201 });
202
203 CodeMirror.defineMIME("text/x-ecl", "ecl");
@@ -0,0 +1,42 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: ECL mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="ecl.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style>.CodeMirror {border: 1px solid black;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: ECL mode</h1>
13 <form><textarea id="code" name="code">
14 /*
15 sample useless code to demonstrate ecl syntax highlighting
16 this is a multiline comment!
17 */
18
19 // this is a singleline comment!
20
21 import ut;
22 r :=
23 record
24 string22 s1 := '123';
25 integer4 i1 := 123;
26 end;
27 #option('tmp', true);
28 d := dataset('tmp::qb', r, thor);
29 output(d);
30 </textarea></form>
31 <script>
32 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
33 tabMode: "indent",
34 matchBrackets: true,
35 });
36 </script>
37
38 <p>Based on CodeMirror's clike mode. For more information see <a href="http://hpccsystems.com">HPCC Systems</a> web site.</p>
39 <p><strong>MIME types defined:</strong> <code>text/x-ecl</code>.</p>
40
41 </body>
42 </html>
@@ -0,0 +1,463 b''
1 // block; "begin", "case", "fun", "if", "receive", "try": closed by "end"
2 // block internal; "after", "catch", "of"
3 // guard; "when", closed by "->"
4 // "->" opens a clause, closed by ";" or "."
5 // "<<" opens a binary, closed by ">>"
6 // "," appears in arglists, lists, tuples and terminates lines of code
7 // "." resets indentation to 0
8 // obsolete; "cond", "let", "query"
9
10 CodeMirror.defineMIME("text/x-erlang", "erlang");
11
12 CodeMirror.defineMode("erlang", function(cmCfg, modeCfg) {
13
14 function rval(state,stream,type) {
15 // distinguish between "." as terminator and record field operator
16 if (type == "record") {
17 state.context = "record";
18 }else{
19 state.context = false;
20 }
21
22 // remember last significant bit on last line for indenting
23 if (type != "whitespace" && type != "comment") {
24 state.lastToken = stream.current();
25 }
26 // erlang -> CodeMirror tag
27 switch (type) {
28 case "atom": return "atom";
29 case "attribute": return "attribute";
30 case "builtin": return "builtin";
31 case "comment": return "comment";
32 case "fun": return "meta";
33 case "function": return "tag";
34 case "guard": return "property";
35 case "keyword": return "keyword";
36 case "macro": return "variable-2";
37 case "number": return "number";
38 case "operator": return "operator";
39 case "record": return "bracket";
40 case "string": return "string";
41 case "type": return "def";
42 case "variable": return "variable";
43 case "error": return "error";
44 case "separator": return null;
45 case "open_paren": return null;
46 case "close_paren": return null;
47 default: return null;
48 }
49 }
50
51 var typeWords = [
52 "-type", "-spec", "-export_type", "-opaque"];
53
54 var keywordWords = [
55 "after","begin","catch","case","cond","end","fun","if",
56 "let","of","query","receive","try","when"];
57
58 var separatorWords = [
59 "->",";",":",".",","];
60
61 var operatorWords = [
62 "and","andalso","band","bnot","bor","bsl","bsr","bxor",
63 "div","not","or","orelse","rem","xor"];
64
65 var symbolWords = [
66 "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"];
67
68 var openParenWords = [
69 "<<","(","[","{"];
70
71 var closeParenWords = [
72 "}","]",")",">>"];
73
74 var guardWords = [
75 "is_atom","is_binary","is_bitstring","is_boolean","is_float",
76 "is_function","is_integer","is_list","is_number","is_pid",
77 "is_port","is_record","is_reference","is_tuple",
78 "atom","binary","bitstring","boolean","function","integer","list",
79 "number","pid","port","record","reference","tuple"];
80
81 var bifWords = [
82 "abs","adler32","adler32_combine","alive","apply","atom_to_binary",
83 "atom_to_list","binary_to_atom","binary_to_existing_atom",
84 "binary_to_list","binary_to_term","bit_size","bitstring_to_list",
85 "byte_size","check_process_code","contact_binary","crc32",
86 "crc32_combine","date","decode_packet","delete_module",
87 "disconnect_node","element","erase","exit","float","float_to_list",
88 "garbage_collect","get","get_keys","group_leader","halt","hd",
89 "integer_to_list","internal_bif","iolist_size","iolist_to_binary",
90 "is_alive","is_atom","is_binary","is_bitstring","is_boolean",
91 "is_float","is_function","is_integer","is_list","is_number","is_pid",
92 "is_port","is_process_alive","is_record","is_reference","is_tuple",
93 "length","link","list_to_atom","list_to_binary","list_to_bitstring",
94 "list_to_existing_atom","list_to_float","list_to_integer",
95 "list_to_pid","list_to_tuple","load_module","make_ref","module_loaded",
96 "monitor_node","node","node_link","node_unlink","nodes","notalive",
97 "now","open_port","pid_to_list","port_close","port_command",
98 "port_connect","port_control","pre_loaded","process_flag",
99 "process_info","processes","purge_module","put","register",
100 "registered","round","self","setelement","size","spawn","spawn_link",
101 "spawn_monitor","spawn_opt","split_binary","statistics",
102 "term_to_binary","time","throw","tl","trunc","tuple_size",
103 "tuple_to_list","unlink","unregister","whereis"];
104
105 // ignored for indenting purposes
106 var ignoreWords = [
107 ",", ":", "catch", "after", "of", "cond", "let", "query"];
108
109
110 var smallRE = /[a-z_]/;
111 var largeRE = /[A-Z_]/;
112 var digitRE = /[0-9]/;
113 var octitRE = /[0-7]/;
114 var anumRE = /[a-z_A-Z0-9]/;
115 var symbolRE = /[\+\-\*\/<>=\|:]/;
116 var openParenRE = /[<\(\[\{]/;
117 var closeParenRE = /[>\)\]\}]/;
118 var sepRE = /[\->\.,:;]/;
119
120 function isMember(element,list) {
121 return (-1 < list.indexOf(element));
122 }
123
124 function isPrev(stream,string) {
125 var start = stream.start;
126 var len = string.length;
127 if (len <= start) {
128 var word = stream.string.slice(start-len,start);
129 return word == string;
130 }else{
131 return false;
132 }
133 }
134
135 function tokenize(stream, state) {
136 if (stream.eatSpace()) {
137 return rval(state,stream,"whitespace");
138 }
139
140 // attributes and type specs
141 if ((peekToken(state).token == "" || peekToken(state).token == ".") &&
142 stream.peek() == '-') {
143 stream.next();
144 if (stream.eat(smallRE) && stream.eatWhile(anumRE)) {
145 if (isMember(stream.current(),typeWords)) {
146 return rval(state,stream,"type");
147 }else{
148 return rval(state,stream,"attribute");
149 }
150 }
151 stream.backUp(1);
152 }
153
154 var ch = stream.next();
155
156 // comment
157 if (ch == '%') {
158 stream.skipToEnd();
159 return rval(state,stream,"comment");
160 }
161
162 // macro
163 if (ch == '?') {
164 stream.eatWhile(anumRE);
165 return rval(state,stream,"macro");
166 }
167
168 // record
169 if ( ch == "#") {
170 stream.eatWhile(anumRE);
171 return rval(state,stream,"record");
172 }
173
174 // char
175 if ( ch == "$") {
176 if (stream.next() == "\\") {
177 if (!stream.eatWhile(octitRE)) {
178 stream.next();
179 }
180 }
181 return rval(state,stream,"string");
182 }
183
184 // quoted atom
185 if (ch == '\'') {
186 if (singleQuote(stream)) {
187 return rval(state,stream,"atom");
188 }else{
189 return rval(state,stream,"error");
190 }
191 }
192
193 // string
194 if (ch == '"') {
195 if (doubleQuote(stream)) {
196 return rval(state,stream,"string");
197 }else{
198 return rval(state,stream,"error");
199 }
200 }
201
202 // variable
203 if (largeRE.test(ch)) {
204 stream.eatWhile(anumRE);
205 return rval(state,stream,"variable");
206 }
207
208 // atom/keyword/BIF/function
209 if (smallRE.test(ch)) {
210 stream.eatWhile(anumRE);
211
212 if (stream.peek() == "/") {
213 stream.next();
214 if (stream.eatWhile(digitRE)) {
215 return rval(state,stream,"fun"); // f/0 style fun
216 }else{
217 stream.backUp(1);
218 return rval(state,stream,"atom");
219 }
220 }
221
222 var w = stream.current();
223
224 if (isMember(w,keywordWords)) {
225 pushToken(state,stream);
226 return rval(state,stream,"keyword");
227 }
228 if (stream.peek() == "(") {
229 // 'put' and 'erlang:put' are bifs, 'foo:put' is not
230 if (isMember(w,bifWords) &&
231 (!isPrev(stream,":") || isPrev(stream,"erlang:"))) {
232 return rval(state,stream,"builtin");
233 }else{
234 return rval(state,stream,"function");
235 }
236 }
237 if (isMember(w,guardWords)) {
238 return rval(state,stream,"guard");
239 }
240 if (isMember(w,operatorWords)) {
241 return rval(state,stream,"operator");
242 }
243 if (stream.peek() == ":") {
244 if (w == "erlang") {
245 return rval(state,stream,"builtin");
246 } else {
247 return rval(state,stream,"function");
248 }
249 }
250 return rval(state,stream,"atom");
251 }
252
253 // number
254 if (digitRE.test(ch)) {
255 stream.eatWhile(digitRE);
256 if (stream.eat('#')) {
257 stream.eatWhile(digitRE); // 16#10 style integer
258 } else {
259 if (stream.eat('.')) { // float
260 stream.eatWhile(digitRE);
261 }
262 if (stream.eat(/[eE]/)) {
263 stream.eat(/[-+]/); // float with exponent
264 stream.eatWhile(digitRE);
265 }
266 }
267 return rval(state,stream,"number"); // normal integer
268 }
269
270 // open parens
271 if (nongreedy(stream,openParenRE,openParenWords)) {
272 pushToken(state,stream);
273 return rval(state,stream,"open_paren");
274 }
275
276 // close parens
277 if (nongreedy(stream,closeParenRE,closeParenWords)) {
278 pushToken(state,stream);
279 return rval(state,stream,"close_paren");
280 }
281
282 // separators
283 if (greedy(stream,sepRE,separatorWords)) {
284 // distinguish between "." as terminator and record field operator
285 if (state.context == false) {
286 pushToken(state,stream);
287 }
288 return rval(state,stream,"separator");
289 }
290
291 // operators
292 if (greedy(stream,symbolRE,symbolWords)) {
293 return rval(state,stream,"operator");
294 }
295
296 return rval(state,stream,null);
297 }
298
299 function nongreedy(stream,re,words) {
300 if (stream.current().length == 1 && re.test(stream.current())) {
301 stream.backUp(1);
302 while (re.test(stream.peek())) {
303 stream.next();
304 if (isMember(stream.current(),words)) {
305 return true;
306 }
307 }
308 stream.backUp(stream.current().length-1);
309 }
310 return false;
311 }
312
313 function greedy(stream,re,words) {
314 if (stream.current().length == 1 && re.test(stream.current())) {
315 while (re.test(stream.peek())) {
316 stream.next();
317 }
318 while (0 < stream.current().length) {
319 if (isMember(stream.current(),words)) {
320 return true;
321 }else{
322 stream.backUp(1);
323 }
324 }
325 stream.next();
326 }
327 return false;
328 }
329
330 function doubleQuote(stream) {
331 return quote(stream, '"', '\\');
332 }
333
334 function singleQuote(stream) {
335 return quote(stream,'\'','\\');
336 }
337
338 function quote(stream,quoteChar,escapeChar) {
339 while (!stream.eol()) {
340 var ch = stream.next();
341 if (ch == quoteChar) {
342 return true;
343 }else if (ch == escapeChar) {
344 stream.next();
345 }
346 }
347 return false;
348 }
349
350 function Token(stream) {
351 this.token = stream ? stream.current() : "";
352 this.column = stream ? stream.column() : 0;
353 this.indent = stream ? stream.indentation() : 0;
354 }
355
356 function myIndent(state,textAfter) {
357 var indent = cmCfg.indentUnit;
358 var outdentWords = ["after","catch"];
359 var token = (peekToken(state)).token;
360 var wordAfter = takewhile(textAfter,/[^a-z]/);
361
362 if (isMember(token,openParenWords)) {
363 return (peekToken(state)).column+token.length;
364 }else if (token == "." || token == ""){
365 return 0;
366 }else if (token == "->") {
367 if (wordAfter == "end") {
368 return peekToken(state,2).column;
369 }else if (peekToken(state,2).token == "fun") {
370 return peekToken(state,2).column+indent;
371 }else{
372 return (peekToken(state)).indent+indent;
373 }
374 }else if (isMember(wordAfter,outdentWords)) {
375 return (peekToken(state)).indent;
376 }else{
377 return (peekToken(state)).column+indent;
378 }
379 }
380
381 function takewhile(str,re) {
382 var m = str.match(re);
383 return m ? str.slice(0,m.index) : str;
384 }
385
386 function popToken(state) {
387 return state.tokenStack.pop();
388 }
389
390 function peekToken(state,depth) {
391 var len = state.tokenStack.length;
392 var dep = (depth ? depth : 1);
393 if (len < dep) {
394 return new Token;
395 }else{
396 return state.tokenStack[len-dep];
397 }
398 }
399
400 function pushToken(state,stream) {
401 var token = stream.current();
402 var prev_token = peekToken(state).token;
403 if (isMember(token,ignoreWords)) {
404 return false;
405 }else if (drop_both(prev_token,token)) {
406 popToken(state);
407 return false;
408 }else if (drop_first(prev_token,token)) {
409 popToken(state);
410 return pushToken(state,stream);
411 }else{
412 state.tokenStack.push(new Token(stream));
413 return true;
414 }
415 }
416
417 function drop_first(open, close) {
418 switch (open+" "+close) {
419 case "when ->": return true;
420 case "-> end": return true;
421 case "-> .": return true;
422 case ". .": return true;
423 default: return false;
424 }
425 }
426
427 function drop_both(open, close) {
428 switch (open+" "+close) {
429 case "( )": return true;
430 case "[ ]": return true;
431 case "{ }": return true;
432 case "<< >>": return true;
433 case "begin end": return true;
434 case "case end": return true;
435 case "fun end": return true;
436 case "if end": return true;
437 case "receive end": return true;
438 case "try end": return true;
439 case "-> ;": return true;
440 default: return false;
441 }
442 }
443
444 return {
445 startState:
446 function() {
447 return {tokenStack: [],
448 context: false,
449 lastToken: null};
450 },
451
452 token:
453 function(stream, state) {
454 return tokenize(stream, state);
455 },
456
457 indent:
458 function(state, textAfter) {
459 // console.log(state.tokenStack);
460 return myIndent(state,textAfter);
461 }
462 };
463 });
@@ -0,0 +1,62 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Erlang mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="erlang.js"></script>
8 <link rel="stylesheet" href="../../theme/erlang-dark.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 <link rel="stylesheet" href="../../doc/docs.css">
11 </head>
12 <body>
13 <h1>CodeMirror: Erlang mode</h1>
14
15 <form><textarea id="code" name="code">
16 %% -*- mode: erlang; erlang-indent-level: 2 -*-
17 %%% Created : 7 May 2012 by mats cronqvist <masse@klarna.com>
18
19 %% @doc
20 %% Demonstrates how to print a record.
21 %% @end
22
23 -module('ex').
24 -author('mats cronqvist').
25 -export([demo/0,
26 rec_info/1]).
27
28 -record(demo,{a="One",b="Two",c="Three",d="Four"}).
29
30 rec_info(demo) -> record_info(fields,demo).
31
32 demo() -> expand_recs(?MODULE,#demo{a="A",b="BB"}).
33
34 expand_recs(M,List) when is_list(List) ->
35 [expand_recs(M,L)||L<-List];
36 expand_recs(M,Tup) when is_tuple(Tup) ->
37 case tuple_size(Tup) of
38 L when L < 1 -> Tup;
39 L ->
40 try Fields = M:rec_info(element(1,Tup)),
41 L = length(Fields)+1,
42 lists:zip(Fields,expand_recs(M,tl(tuple_to_list(Tup))))
43 catch _:_ ->
44 list_to_tuple(expand_recs(M,tuple_to_list(Tup)))
45 end
46 end;
47 expand_recs(_,Term) ->
48 Term.
49 </textarea></form>
50
51 <script>
52 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
53 lineNumbers: true,
54 matchBrackets: true,
55 extraKeys: {"Tab": "indentAuto"},
56 theme: "erlang-dark"
57 });
58 </script>
59
60 <p><strong>MIME types defined:</strong> <code>text/x-erlang</code>.</p>
61 </body>
62 </html>
@@ -0,0 +1,144 b''
1 CodeMirror.defineMode("gfm", function(config, parserConfig) {
2 var mdMode = CodeMirror.getMode(config, "markdown");
3 var aliases = {
4 html: "htmlmixed",
5 js: "javascript",
6 json: "application/json",
7 c: "text/x-csrc",
8 "c++": "text/x-c++src",
9 java: "text/x-java",
10 csharp: "text/x-csharp",
11 "c#": "text/x-csharp"
12 };
13
14 // make this lazy so that we don't need to load GFM last
15 var getMode = (function () {
16 var i, modes = {}, mimes = {}, mime;
17
18 var list = CodeMirror.listModes();
19 for (i = 0; i < list.length; i++) {
20 modes[list[i]] = list[i];
21 }
22 var mimesList = CodeMirror.listMIMEs();
23 for (i = 0; i < mimesList.length; i++) {
24 mime = mimesList[i].mime;
25 mimes[mime] = mimesList[i].mime;
26 }
27
28 for (var a in aliases) {
29 if (aliases[a] in modes || aliases[a] in mimes)
30 modes[a] = aliases[a];
31 }
32
33 return function (lang) {
34 return modes[lang] ? CodeMirror.getMode(config, modes[lang]) : null;
35 }
36 }());
37
38 function markdown(stream, state) {
39 // intercept fenced code blocks
40 if (stream.sol() && stream.match(/^```([\w+#]*)/)) {
41 // try switching mode
42 state.localMode = getMode(RegExp.$1)
43 if (state.localMode)
44 state.localState = state.localMode.startState();
45
46 state.token = local;
47 return 'code';
48 }
49
50 return mdMode.token(stream, state.mdState);
51 }
52
53 function local(stream, state) {
54 if (stream.sol() && stream.match(/^```/)) {
55 state.localMode = state.localState = null;
56 state.token = markdown;
57 return 'code';
58 }
59 else if (state.localMode) {
60 return state.localMode.token(stream, state.localState);
61 } else {
62 stream.skipToEnd();
63 return 'code';
64 }
65 }
66
67 // custom handleText to prevent emphasis in the middle of a word
68 // and add autolinking
69 function handleText(stream, mdState) {
70 var match;
71 if (stream.match(/^\w+:\/\/\S+/)) {
72 return 'link';
73 }
74 if (stream.match(/^[^\[*\\<>` _][^\[*\\<>` ]*[^\[*\\<>` _]/)) {
75 return mdMode.getType(mdState);
76 }
77 if (match = stream.match(/^[^\[*\\<>` ]+/)) {
78 var word = match[0];
79 if (word[0] === '_' && word[word.length-1] === '_') {
80 stream.backUp(word.length);
81 return undefined;
82 }
83 return mdMode.getType(mdState);
84 }
85 if (stream.eatSpace()) {
86 return null;
87 }
88 }
89
90 return {
91 startState: function() {
92 var mdState = mdMode.startState();
93 mdState.text = handleText;
94 return {token: markdown, mode: "markdown", mdState: mdState,
95 localMode: null, localState: null};
96 },
97
98 copyState: function(state) {
99 return {token: state.token, mode: state.mode, mdState: CodeMirror.copyState(mdMode, state.mdState),
100 localMode: state.localMode,
101 localState: state.localMode ? CodeMirror.copyState(state.localMode, state.localState) : null};
102 },
103
104 token: function(stream, state) {
105 /* Parse GFM double bracket links */
106 if ((ch = stream.peek()) != undefined && ch == '[') {
107 stream.next(); // Advance the stream
108
109 /* Only handle double bracket links */
110 if ((ch = stream.peek()) == undefined || ch != '[') {
111 stream.backUp(1);
112 return state.token(stream, state);
113 }
114
115 while ((ch = stream.next()) != undefined && ch != ']') {}
116
117 if (ch == ']' && (ch = stream.next()) != undefined && ch == ']')
118 return 'link';
119
120 /* If we did not find the second ']' */
121 stream.backUp(1);
122 }
123
124 /* Match GFM latex formulas, as well as latex formulas within '$' */
125 if (stream.match(/^\$[^\$]+\$/)) {
126 return "string";
127 }
128
129 if (stream.match(/^\\\((.*?)\\\)/)) {
130 return "string";
131 }
132
133 if (stream.match(/^\$\$[^\$]+\$\$/)) {
134 return "string";
135 }
136
137 if (stream.match(/^\\\[(.*?)\\\]/)) {
138 return "string";
139 }
140
141 return state.token(stream, state);
142 }
143 }
144 }, "markdown");
@@ -0,0 +1,47 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: GFM mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="../xml/xml.js"></script>
8 <script src="../markdown/markdown.js"></script>
9 <script src="gfm.js"></script>
10 <script src="../javascript/javascript.js"></script>
11 <link rel="stylesheet" href="../markdown/markdown.css">
12 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
13 <link rel="stylesheet" href="../../doc/docs.css">
14 </head>
15 <body>
16 <h1>CodeMirror: GFM mode</h1>
17
18 <!-- source: http://daringfireball.net/projects/markdown/basics.text -->
19 <form><textarea id="code" name="code">
20 Github Flavored Markdown
21 ========================
22
23 Everything from markdown plus GFM features:
24
25 ## Fenced code blocks
26
27 ```javascript
28 for (var i = 0; i &lt; items.length; i++) {
29 console.log(items[i], i); // log them
30 }
31 ```
32
33 See http://github.github.com/github-flavored-markdown/
34
35 </textarea></form>
36
37 <script>
38 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
39 mode: 'gfm',
40 lineNumbers: true,
41 matchBrackets: true,
42 theme: "default"
43 });
44 </script>
45
46 </body>
47 </html>
@@ -0,0 +1,170 b''
1 CodeMirror.defineMode("go", function(config, parserConfig) {
2 var indentUnit = config.indentUnit;
3
4 var keywords = {
5 "break":true, "case":true, "chan":true, "const":true, "continue":true,
6 "default":true, "defer":true, "else":true, "fallthrough":true, "for":true,
7 "func":true, "go":true, "goto":true, "if":true, "import":true,
8 "interface":true, "map":true, "package":true, "range":true, "return":true,
9 "select":true, "struct":true, "switch":true, "type":true, "var":true,
10 "bool":true, "byte":true, "complex64":true, "complex128":true,
11 "float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
12 "int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
13 "uint64":true, "int":true, "uint":true, "uintptr":true
14 };
15
16 var atoms = {
17 "true":true, "false":true, "iota":true, "nil":true, "append":true,
18 "cap":true, "close":true, "complex":true, "copy":true, "imag":true,
19 "len":true, "make":true, "new":true, "panic":true, "print":true,
20 "println":true, "real":true, "recover":true
21 };
22
23 var blockKeywords = {
24 "else":true, "for":true, "func":true, "if":true, "interface":true,
25 "select":true, "struct":true, "switch":true
26 };
27
28 var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
29
30 var curPunc;
31
32 function tokenBase(stream, state) {
33 var ch = stream.next();
34 if (ch == '"' || ch == "'" || ch == "`") {
35 state.tokenize = tokenString(ch);
36 return state.tokenize(stream, state);
37 }
38 if (/[\d\.]/.test(ch)) {
39 if (ch == ".") {
40 stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
41 } else if (ch == "0") {
42 stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
43 } else {
44 stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
45 }
46 return "number";
47 }
48 if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
49 curPunc = ch;
50 return null
51 }
52 if (ch == "/") {
53 if (stream.eat("*")) {
54 state.tokenize = tokenComment;
55 return tokenComment(stream, state);
56 }
57 if (stream.eat("/")) {
58 stream.skipToEnd();
59 return "comment";
60 }
61 }
62 if (isOperatorChar.test(ch)) {
63 stream.eatWhile(isOperatorChar);
64 return "operator";
65 }
66 stream.eatWhile(/[\w\$_]/);
67 var cur = stream.current();
68 if (keywords.propertyIsEnumerable(cur)) {
69 if (cur == "case" || cur == "default") curPunc = "case";
70 return "keyword";
71 }
72 if (atoms.propertyIsEnumerable(cur)) return "atom";
73 return "variable";
74 }
75
76 function tokenString(quote) {
77 return function(stream, state) {
78 var escaped = false, next, end = false;
79 while ((next = stream.next()) != null) {
80 if (next == quote && !escaped) {end = true; break;}
81 escaped = !escaped && next == "\\";
82 }
83 if (end || !(escaped || quote == "`"))
84 state.tokenize = tokenBase;
85 return "string";
86 };
87 }
88
89 function tokenComment(stream, state) {
90 var maybeEnd = false, ch;
91 while (ch = stream.next()) {
92 if (ch == "/" && maybeEnd) {
93 state.tokenize = tokenBase;
94 break;
95 }
96 maybeEnd = (ch == "*");
97 }
98 return "comment";
99 }
100
101 function Context(indented, column, type, align, prev) {
102 this.indented = indented;
103 this.column = column;
104 this.type = type;
105 this.align = align;
106 this.prev = prev;
107 }
108 function pushContext(state, col, type) {
109 return state.context = new Context(state.indented, col, type, null, state.context);
110 }
111 function popContext(state) {
112 var t = state.context.type;
113 if (t == ")" || t == "]" || t == "}")
114 state.indented = state.context.indented;
115 return state.context = state.context.prev;
116 }
117
118 // Interface
119
120 return {
121 startState: function(basecolumn) {
122 return {
123 tokenize: null,
124 context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
125 indented: 0,
126 startOfLine: true
127 };
128 },
129
130 token: function(stream, state) {
131 var ctx = state.context;
132 if (stream.sol()) {
133 if (ctx.align == null) ctx.align = false;
134 state.indented = stream.indentation();
135 state.startOfLine = true;
136 if (ctx.type == "case") ctx.type = "}";
137 }
138 if (stream.eatSpace()) return null;
139 curPunc = null;
140 var style = (state.tokenize || tokenBase)(stream, state);
141 if (style == "comment") return style;
142 if (ctx.align == null) ctx.align = true;
143
144 if (curPunc == "{") pushContext(state, stream.column(), "}");
145 else if (curPunc == "[") pushContext(state, stream.column(), "]");
146 else if (curPunc == "(") pushContext(state, stream.column(), ")");
147 else if (curPunc == "case") ctx.type = "case"
148 else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
149 else if (curPunc == ctx.type) popContext(state);
150 state.startOfLine = false;
151 return style;
152 },
153
154 indent: function(state, textAfter) {
155 if (state.tokenize != tokenBase && state.tokenize != null) return 0;
156 var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
157 if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
158 state.context.type = "}";
159 return ctx.indented;
160 }
161 var closing = firstChar == ctx.type;
162 if (ctx.align) return ctx.column + (closing ? 0 : 1);
163 else return ctx.indented + (closing ? 0 : indentUnit);
164 },
165
166 electricChars: "{}:"
167 };
168 });
169
170 CodeMirror.defineMIME("text/x-go", "go");
@@ -0,0 +1,72 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Go mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <link rel="stylesheet" href="../../theme/elegant.css">
7 <script src="../../lib/codemirror.js"></script>
8 <script src="go.js"></script>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 <style>.CodeMirror {border:1px solid #999; background:#ffc}</style>
11 </head>
12 <body>
13 <h1>CodeMirror: Go mode</h1>
14
15 <form><textarea id="code" name="code">
16 // Prime Sieve in Go.
17 // Taken from the Go specification.
18 // Copyright © The Go Authors.
19
20 package main
21
22 import "fmt"
23
24 // Send the sequence 2, 3, 4, ... to channel 'ch'.
25 func generate(ch chan&lt;- int) {
26 for i := 2; ; i++ {
27 ch &lt;- i // Send 'i' to channel 'ch'
28 }
29 }
30
31 // Copy the values from channel 'src' to channel 'dst',
32 // removing those divisible by 'prime'.
33 func filter(src &lt;-chan int, dst chan&lt;- int, prime int) {
34 for i := range src { // Loop over values received from 'src'.
35 if i%prime != 0 {
36 dst &lt;- i // Send 'i' to channel 'dst'.
37 }
38 }
39 }
40
41 // The prime sieve: Daisy-chain filter processes together.
42 func sieve() {
43 ch := make(chan int) // Create a new channel.
44 go generate(ch) // Start generate() as a subprocess.
45 for {
46 prime := &lt;-ch
47 fmt.Print(prime, "\n")
48 ch1 := make(chan int)
49 go filter(ch, ch1, prime)
50 ch = ch1
51 }
52 }
53
54 func main() {
55 sieve()
56 }
57 </textarea></form>
58
59 <script>
60 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
61 theme: "elegant",
62 matchBrackets: true,
63 indentUnit: 8,
64 tabSize: 8,
65 indentWithTabs: true,
66 mode: "text/x-go"
67 });
68 </script>
69
70 <p><strong>MIME type:</strong> <code>text/x-go</code></p>
71 </body>
72 </html>
@@ -0,0 +1,210 b''
1 CodeMirror.defineMode("groovy", function(config, parserConfig) {
2 function words(str) {
3 var obj = {}, words = str.split(" ");
4 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
5 return obj;
6 }
7 var keywords = words(
8 "abstract as assert boolean break byte case catch char class const continue def default " +
9 "do double else enum extends final finally float for goto if implements import in " +
10 "instanceof int interface long native new package private protected public return " +
11 "short static strictfp super switch synchronized threadsafe throw throws transient " +
12 "try void volatile while");
13 var blockKeywords = words("catch class do else finally for if switch try while enum interface def");
14 var atoms = words("null true false this");
15
16 var curPunc;
17 function tokenBase(stream, state) {
18 var ch = stream.next();
19 if (ch == '"' || ch == "'") {
20 return startString(ch, stream, state);
21 }
22 if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
23 curPunc = ch;
24 return null
25 }
26 if (/\d/.test(ch)) {
27 stream.eatWhile(/[\w\.]/);
28 if (stream.eat(/eE/)) { stream.eat(/\+\-/); stream.eatWhile(/\d/); }
29 return "number";
30 }
31 if (ch == "/") {
32 if (stream.eat("*")) {
33 state.tokenize.push(tokenComment);
34 return tokenComment(stream, state);
35 }
36 if (stream.eat("/")) {
37 stream.skipToEnd();
38 return "comment";
39 }
40 if (expectExpression(state.lastToken)) {
41 return startString(ch, stream, state);
42 }
43 }
44 if (ch == "-" && stream.eat(">")) {
45 curPunc = "->";
46 return null;
47 }
48 if (/[+\-*&%=<>!?|\/~]/.test(ch)) {
49 stream.eatWhile(/[+\-*&%=<>|~]/);
50 return "operator";
51 }
52 stream.eatWhile(/[\w\$_]/);
53 if (ch == "@") { stream.eatWhile(/[\w\$_\.]/); return "meta"; }
54 if (state.lastToken == ".") return "property";
55 if (stream.eat(":")) { curPunc = "proplabel"; return "property"; }
56 var cur = stream.current();
57 if (atoms.propertyIsEnumerable(cur)) { return "atom"; }
58 if (keywords.propertyIsEnumerable(cur)) {
59 if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
60 return "keyword";
61 }
62 return "variable";
63 }
64 tokenBase.isBase = true;
65
66 function startString(quote, stream, state) {
67 var tripleQuoted = false;
68 if (quote != "/" && stream.eat(quote)) {
69 if (stream.eat(quote)) tripleQuoted = true;
70 else return "string";
71 }
72 function t(stream, state) {
73 var escaped = false, next, end = !tripleQuoted;
74 while ((next = stream.next()) != null) {
75 if (next == quote && !escaped) {
76 if (!tripleQuoted) { break; }
77 if (stream.match(quote + quote)) { end = true; break; }
78 }
79 if (quote == '"' && next == "$" && !escaped && stream.eat("{")) {
80 state.tokenize.push(tokenBaseUntilBrace());
81 return "string";
82 }
83 escaped = !escaped && next == "\\";
84 }
85 if (end) state.tokenize.pop();
86 return "string";
87 }
88 state.tokenize.push(t);
89 return t(stream, state);
90 }
91
92 function tokenBaseUntilBrace() {
93 var depth = 1;
94 function t(stream, state) {
95 if (stream.peek() == "}") {
96 depth--;
97 if (depth == 0) {
98 state.tokenize.pop();
99 return state.tokenize[state.tokenize.length-1](stream, state);
100 }
101 } else if (stream.peek() == "{") {
102 depth++;
103 }
104 return tokenBase(stream, state);
105 }
106 t.isBase = true;
107 return t;
108 }
109
110 function tokenComment(stream, state) {
111 var maybeEnd = false, ch;
112 while (ch = stream.next()) {
113 if (ch == "/" && maybeEnd) {
114 state.tokenize.pop();
115 break;
116 }
117 maybeEnd = (ch == "*");
118 }
119 return "comment";
120 }
121
122 function expectExpression(last) {
123 return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) ||
124 last == "newstatement" || last == "keyword" || last == "proplabel";
125 }
126
127 function Context(indented, column, type, align, prev) {
128 this.indented = indented;
129 this.column = column;
130 this.type = type;
131 this.align = align;
132 this.prev = prev;
133 }
134 function pushContext(state, col, type) {
135 return state.context = new Context(state.indented, col, type, null, state.context);
136 }
137 function popContext(state) {
138 var t = state.context.type;
139 if (t == ")" || t == "]" || t == "}")
140 state.indented = state.context.indented;
141 return state.context = state.context.prev;
142 }
143
144 // Interface
145
146 return {
147 startState: function(basecolumn) {
148 return {
149 tokenize: [tokenBase],
150 context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false),
151 indented: 0,
152 startOfLine: true,
153 lastToken: null
154 };
155 },
156
157 token: function(stream, state) {
158 var ctx = state.context;
159 if (stream.sol()) {
160 if (ctx.align == null) ctx.align = false;
161 state.indented = stream.indentation();
162 state.startOfLine = true;
163 // Automatic semicolon insertion
164 if (ctx.type == "statement" && !expectExpression(state.lastToken)) {
165 popContext(state); ctx = state.context;
166 }
167 }
168 if (stream.eatSpace()) return null;
169 curPunc = null;
170 var style = state.tokenize[state.tokenize.length-1](stream, state);
171 if (style == "comment") return style;
172 if (ctx.align == null) ctx.align = true;
173
174 if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
175 // Handle indentation for {x -> \n ... }
176 else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") {
177 popContext(state);
178 state.context.align = false;
179 }
180 else if (curPunc == "{") pushContext(state, stream.column(), "}");
181 else if (curPunc == "[") pushContext(state, stream.column(), "]");
182 else if (curPunc == "(") pushContext(state, stream.column(), ")");
183 else if (curPunc == "}") {
184 while (ctx.type == "statement") ctx = popContext(state);
185 if (ctx.type == "}") ctx = popContext(state);
186 while (ctx.type == "statement") ctx = popContext(state);
187 }
188 else if (curPunc == ctx.type) popContext(state);
189 else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
190 pushContext(state, stream.column(), "statement");
191 state.startOfLine = false;
192 state.lastToken = curPunc || style;
193 return style;
194 },
195
196 indent: function(state, textAfter) {
197 if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
198 var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
199 if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev;
200 var closing = firstChar == ctx.type;
201 if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit);
202 else if (ctx.align) return ctx.column + (closing ? 0 : 1);
203 else return ctx.indented + (closing ? 0 : config.indentUnit);
204 },
205
206 electricChars: "{}"
207 };
208 });
209
210 CodeMirror.defineMIME("text/x-groovy", "groovy");
@@ -0,0 +1,71 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Groovy mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="groovy.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style>.CodeMirror {border-top: 1px solid #500; border-bottom: 1px solid #500;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: Groovy mode</h1>
13
14 <form><textarea id="code" name="code">
15 //Pattern for groovy script
16 def p = ~/.*\.groovy/
17 new File( 'd:\\scripts' ).eachFileMatch(p) {f ->
18 // imports list
19 def imports = []
20 f.eachLine {
21 // condition to detect an import instruction
22 ln -> if ( ln =~ '^import .*' ) {
23 imports << "${ln - 'import '}"
24 }
25 }
26 // print thmen
27 if ( ! imports.empty ) {
28 println f
29 imports.each{ println " $it" }
30 }
31 }
32
33 /* Coin changer demo code from http://groovy.codehaus.org */
34
35 enum UsCoin {
36 quarter(25), dime(10), nickel(5), penny(1)
37 UsCoin(v) { value = v }
38 final value
39 }
40
41 enum OzzieCoin {
42 fifty(50), twenty(20), ten(10), five(5)
43 OzzieCoin(v) { value = v }
44 final value
45 }
46
47 def plural(word, count) {
48 if (count == 1) return word
49 word[-1] == 'y' ? word[0..-2] + "ies" : word + "s"
50 }
51
52 def change(currency, amount) {
53 currency.values().inject([]){ list, coin ->
54 int count = amount / coin.value
55 amount = amount % coin.value
56 list += "$count ${plural(coin.toString(), count)}"
57 }
58 }
59 </textarea></form>
60
61 <script>
62 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
63 lineNumbers: true,
64 matchBrackets: true,
65 mode: "text/x-groovy"
66 });
67 </script>
68
69 <p><strong>MIME types defined:</strong> <code>text/x-groovy</code></p>
70 </body>
71 </html>
@@ -0,0 +1,242 b''
1 CodeMirror.defineMode("haskell", function(cmCfg, modeCfg) {
2
3 function switchState(source, setState, f) {
4 setState(f);
5 return f(source, setState);
6 }
7
8 // These should all be Unicode extended, as per the Haskell 2010 report
9 var smallRE = /[a-z_]/;
10 var largeRE = /[A-Z]/;
11 var digitRE = /[0-9]/;
12 var hexitRE = /[0-9A-Fa-f]/;
13 var octitRE = /[0-7]/;
14 var idRE = /[a-z_A-Z0-9']/;
15 var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
16 var specialRE = /[(),;[\]`{}]/;
17 var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
18
19 function normal(source, setState) {
20 if (source.eatWhile(whiteCharRE)) {
21 return null;
22 }
23
24 var ch = source.next();
25 if (specialRE.test(ch)) {
26 if (ch == '{' && source.eat('-')) {
27 var t = "comment";
28 if (source.eat('#')) {
29 t = "meta";
30 }
31 return switchState(source, setState, ncomment(t, 1));
32 }
33 return null;
34 }
35
36 if (ch == '\'') {
37 if (source.eat('\\')) {
38 source.next(); // should handle other escapes here
39 }
40 else {
41 source.next();
42 }
43 if (source.eat('\'')) {
44 return "string";
45 }
46 return "error";
47 }
48
49 if (ch == '"') {
50 return switchState(source, setState, stringLiteral);
51 }
52
53 if (largeRE.test(ch)) {
54 source.eatWhile(idRE);
55 if (source.eat('.')) {
56 return "qualifier";
57 }
58 return "variable-2";
59 }
60
61 if (smallRE.test(ch)) {
62 source.eatWhile(idRE);
63 return "variable";
64 }
65
66 if (digitRE.test(ch)) {
67 if (ch == '0') {
68 if (source.eat(/[xX]/)) {
69 source.eatWhile(hexitRE); // should require at least 1
70 return "integer";
71 }
72 if (source.eat(/[oO]/)) {
73 source.eatWhile(octitRE); // should require at least 1
74 return "number";
75 }
76 }
77 source.eatWhile(digitRE);
78 var t = "number";
79 if (source.eat('.')) {
80 t = "number";
81 source.eatWhile(digitRE); // should require at least 1
82 }
83 if (source.eat(/[eE]/)) {
84 t = "number";
85 source.eat(/[-+]/);
86 source.eatWhile(digitRE); // should require at least 1
87 }
88 return t;
89 }
90
91 if (symbolRE.test(ch)) {
92 if (ch == '-' && source.eat(/-/)) {
93 source.eatWhile(/-/);
94 if (!source.eat(symbolRE)) {
95 source.skipToEnd();
96 return "comment";
97 }
98 }
99 var t = "variable";
100 if (ch == ':') {
101 t = "variable-2";
102 }
103 source.eatWhile(symbolRE);
104 return t;
105 }
106
107 return "error";
108 }
109
110 function ncomment(type, nest) {
111 if (nest == 0) {
112 return normal;
113 }
114 return function(source, setState) {
115 var currNest = nest;
116 while (!source.eol()) {
117 var ch = source.next();
118 if (ch == '{' && source.eat('-')) {
119 ++currNest;
120 }
121 else if (ch == '-' && source.eat('}')) {
122 --currNest;
123 if (currNest == 0) {
124 setState(normal);
125 return type;
126 }
127 }
128 }
129 setState(ncomment(type, currNest));
130 return type;
131 }
132 }
133
134 function stringLiteral(source, setState) {
135 while (!source.eol()) {
136 var ch = source.next();
137 if (ch == '"') {
138 setState(normal);
139 return "string";
140 }
141 if (ch == '\\') {
142 if (source.eol() || source.eat(whiteCharRE)) {
143 setState(stringGap);
144 return "string";
145 }
146 if (source.eat('&')) {
147 }
148 else {
149 source.next(); // should handle other escapes here
150 }
151 }
152 }
153 setState(normal);
154 return "error";
155 }
156
157 function stringGap(source, setState) {
158 if (source.eat('\\')) {
159 return switchState(source, setState, stringLiteral);
160 }
161 source.next();
162 setState(normal);
163 return "error";
164 }
165
166
167 var wellKnownWords = (function() {
168 var wkw = {};
169 function setType(t) {
170 return function () {
171 for (var i = 0; i < arguments.length; i++)
172 wkw[arguments[i]] = t;
173 }
174 }
175
176 setType("keyword")(
177 "case", "class", "data", "default", "deriving", "do", "else", "foreign",
178 "if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
179 "module", "newtype", "of", "then", "type", "where", "_");
180
181 setType("keyword")(
182 "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
183
184 setType("builtin")(
185 "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
186 "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
187
188 setType("builtin")(
189 "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
190 "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
191 "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
192 "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
193 "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
194 "String", "True");
195
196 setType("builtin")(
197 "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
198 "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
199 "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
200 "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
201 "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
202 "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
203 "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
204 "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
205 "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
206 "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
207 "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
208 "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
209 "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
210 "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
211 "otherwise", "pi", "pred", "print", "product", "properFraction",
212 "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
213 "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
214 "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
215 "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
216 "sequence", "sequence_", "show", "showChar", "showList", "showParen",
217 "showString", "shows", "showsPrec", "significand", "signum", "sin",
218 "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
219 "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
220 "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
221 "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
222 "zip3", "zipWith", "zipWith3");
223
224 return wkw;
225 })();
226
227
228
229 return {
230 startState: function () { return { f: normal }; },
231 copyState: function (s) { return { f: s.f }; },
232
233 token: function(stream, state) {
234 var t = state.f(stream, function(s) { state.f = s; });
235 var w = stream.current();
236 return (w in wellKnownWords) ? wellKnownWords[w] : t;
237 }
238 };
239
240 });
241
242 CodeMirror.defineMIME("text/x-haskell", "haskell");
@@ -0,0 +1,60 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Haskell mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="haskell.js"></script>
8 <link rel="stylesheet" href="../../theme/elegant.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 <link rel="stylesheet" href="../../doc/docs.css">
11 </head>
12 <body>
13 <h1>CodeMirror: Haskell mode</h1>
14
15 <form><textarea id="code" name="code">
16 module UniquePerms (
17 uniquePerms
18 )
19 where
20
21 -- | Find all unique permutations of a list where there might be duplicates.
22 uniquePerms :: (Eq a) => [a] -> [[a]]
23 uniquePerms = permBag . makeBag
24
25 -- | An unordered collection where duplicate values are allowed,
26 -- but represented with a single value and a count.
27 type Bag a = [(a, Int)]
28
29 makeBag :: (Eq a) => [a] -> Bag a
30 makeBag [] = []
31 makeBag (a:as) = mix a $ makeBag as
32 where
33 mix a [] = [(a,1)]
34 mix a (bn@(b,n):bs) | a == b = (b,n+1):bs
35 | otherwise = bn : mix a bs
36
37 permBag :: Bag a -> [[a]]
38 permBag [] = [[]]
39 permBag bs = concatMap (\(f,cs) -> map (f:) $ permBag cs) . oneOfEach $ bs
40 where
41 oneOfEach [] = []
42 oneOfEach (an@(a,n):bs) =
43 let bs' = if n == 1 then bs else (a,n-1):bs
44 in (a,bs') : mapSnd (an:) (oneOfEach bs)
45
46 apSnd f (a,b) = (a, f b)
47 mapSnd = map . apSnd
48 </textarea></form>
49
50 <script>
51 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
52 lineNumbers: true,
53 matchBrackets: true,
54 theme: "elegant"
55 });
56 </script>
57
58 <p><strong>MIME types defined:</strong> <code>text/x-haskell</code>.</p>
59 </body>
60 </html>
@@ -0,0 +1,432 b''
1 CodeMirror.defineMode("haxe", function(config, parserConfig) {
2 var indentUnit = config.indentUnit;
3
4 // Tokenizer
5
6 var keywords = function(){
7 function kw(type) {return {type: type, style: "keyword"};}
8 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
9 var operator = kw("operator"), atom = {type: "atom", style: "atom"}, attribute = {type:"attribute", style: "attribute"}
10 var type = kw("typedef");
11 return {
12 "if": A, "while": A, "else": B, "do": B, "try": B,
13 "return": C, "break": C, "continue": C, "new": C, "throw": C,
14 "var": kw("var"), "inline":attribute, "static": attribute, "using":kw("import"),
15 "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"),
16 "function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"),
17 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
18 "in": operator, "never": kw("property_access"), "trace":kw("trace"),
19 "class": type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type,
20 "true": atom, "false": atom, "null": atom
21 };
22 }();
23
24 var isOperatorChar = /[+\-*&%=<>!?|]/;
25
26 function chain(stream, state, f) {
27 state.tokenize = f;
28 return f(stream, state);
29 }
30
31 function nextUntilUnescaped(stream, end) {
32 var escaped = false, next;
33 while ((next = stream.next()) != null) {
34 if (next == end && !escaped)
35 return false;
36 escaped = !escaped && next == "\\";
37 }
38 return escaped;
39 }
40
41 // Used as scratch variables to communicate multiple values without
42 // consing up tons of objects.
43 var type, content;
44 function ret(tp, style, cont) {
45 type = tp; content = cont;
46 return style;
47 }
48
49 function haxeTokenBase(stream, state) {
50 var ch = stream.next();
51 if (ch == '"' || ch == "'")
52 return chain(stream, state, haxeTokenString(ch));
53 else if (/[\[\]{}\(\),;\:\.]/.test(ch))
54 return ret(ch);
55 else if (ch == "0" && stream.eat(/x/i)) {
56 stream.eatWhile(/[\da-f]/i);
57 return ret("number", "number");
58 }
59 else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
60 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
61 return ret("number", "number");
62 }
63 else if (state.reAllowed && (ch == "~" && stream.eat(/\//))) {
64 nextUntilUnescaped(stream, "/");
65 stream.eatWhile(/[gimsu]/);
66 return ret("regexp", "string-2");
67 }
68 else if (ch == "/") {
69 if (stream.eat("*")) {
70 return chain(stream, state, haxeTokenComment);
71 }
72 else if (stream.eat("/")) {
73 stream.skipToEnd();
74 return ret("comment", "comment");
75 }
76 else {
77 stream.eatWhile(isOperatorChar);
78 return ret("operator", null, stream.current());
79 }
80 }
81 else if (ch == "#") {
82 stream.skipToEnd();
83 return ret("conditional", "meta");
84 }
85 else if (ch == "@") {
86 stream.eat(/:/);
87 stream.eatWhile(/[\w_]/);
88 return ret ("metadata", "meta");
89 }
90 else if (isOperatorChar.test(ch)) {
91 stream.eatWhile(isOperatorChar);
92 return ret("operator", null, stream.current());
93 }
94 else {
95 var word;
96 if(/[A-Z]/.test(ch))
97 {
98 stream.eatWhile(/[\w_<>]/);
99 word = stream.current();
100 return ret("type", "variable-3", word);
101 }
102 else
103 {
104 stream.eatWhile(/[\w_]/);
105 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
106 return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
107 ret("variable", "variable", word);
108 }
109 }
110 }
111
112 function haxeTokenString(quote) {
113 return function(stream, state) {
114 if (!nextUntilUnescaped(stream, quote))
115 state.tokenize = haxeTokenBase;
116 return ret("string", "string");
117 };
118 }
119
120 function haxeTokenComment(stream, state) {
121 var maybeEnd = false, ch;
122 while (ch = stream.next()) {
123 if (ch == "/" && maybeEnd) {
124 state.tokenize = haxeTokenBase;
125 break;
126 }
127 maybeEnd = (ch == "*");
128 }
129 return ret("comment", "comment");
130 }
131
132 // Parser
133
134 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
135
136 function HaxeLexical(indented, column, type, align, prev, info) {
137 this.indented = indented;
138 this.column = column;
139 this.type = type;
140 this.prev = prev;
141 this.info = info;
142 if (align != null) this.align = align;
143 }
144
145 function inScope(state, varname) {
146 for (var v = state.localVars; v; v = v.next)
147 if (v.name == varname) return true;
148 }
149
150 function parseHaxe(state, style, type, content, stream) {
151 var cc = state.cc;
152 // Communicate our context to the combinators.
153 // (Less wasteful than consing up a hundred closures on every call.)
154 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
155
156 if (!state.lexical.hasOwnProperty("align"))
157 state.lexical.align = true;
158
159 while(true) {
160 var combinator = cc.length ? cc.pop() : statement;
161 if (combinator(type, content)) {
162 while(cc.length && cc[cc.length - 1].lex)
163 cc.pop()();
164 if (cx.marked) return cx.marked;
165 if (type == "variable" && inScope(state, content)) return "variable-2";
166 if (type == "variable" && imported(state, content)) return "variable-3";
167 return style;
168 }
169 }
170 }
171
172 function imported(state, typename)
173 {
174 if (/[a-z]/.test(typename.charAt(0)))
175 return false;
176 var len = state.importedtypes.length;
177 for (var i = 0; i<len; i++)
178 if(state.importedtypes[i]==typename) return true;
179 }
180
181
182 function registerimport(importname) {
183 var state = cx.state;
184 for (var t = state.importedtypes; t; t = t.next)
185 if(t.name == importname) return;
186 state.importedtypes = { name: importname, next: state.importedtypes };
187 }
188 // Combinator utils
189
190 var cx = {state: null, column: null, marked: null, cc: null};
191 function pass() {
192 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
193 }
194 function cont() {
195 pass.apply(null, arguments);
196 return true;
197 }
198 function register(varname) {
199 var state = cx.state;
200 if (state.context) {
201 cx.marked = "def";
202 for (var v = state.localVars; v; v = v.next)
203 if (v.name == varname) return;
204 state.localVars = {name: varname, next: state.localVars};
205 }
206 }
207
208 // Combinators
209
210 var defaultVars = {name: "this", next: null};
211 function pushcontext() {
212 if (!cx.state.context) cx.state.localVars = defaultVars;
213 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
214 }
215 function popcontext() {
216 cx.state.localVars = cx.state.context.vars;
217 cx.state.context = cx.state.context.prev;
218 }
219 function pushlex(type, info) {
220 var result = function() {
221 var state = cx.state;
222 state.lexical = new HaxeLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
223 };
224 result.lex = true;
225 return result;
226 }
227 function poplex() {
228 var state = cx.state;
229 if (state.lexical.prev) {
230 if (state.lexical.type == ")")
231 state.indented = state.lexical.indented;
232 state.lexical = state.lexical.prev;
233 }
234 }
235 poplex.lex = true;
236
237 function expect(wanted) {
238 return function expecting(type) {
239 if (type == wanted) return cont();
240 else if (wanted == ";") return pass();
241 else return cont(arguments.callee);
242 };
243 }
244
245 function statement(type) {
246 if (type == "@") return cont(metadef)
247 if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
248 if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
249 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
250 if (type == "{") return cont(pushlex("}"), pushcontext, block, poplex, popcontext);
251 if (type == ";") return cont();
252 if (type == "attribute") return cont(maybeattribute);
253 if (type == "function") return cont(functiondef);
254 if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
255 poplex, statement, poplex);
256 if (type == "variable") return cont(pushlex("stat"), maybelabel);
257 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
258 block, poplex, poplex);
259 if (type == "case") return cont(expression, expect(":"));
260 if (type == "default") return cont(expect(":"));
261 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
262 statement, poplex, popcontext);
263 if (type == "import") return cont(importdef, expect(";"));
264 if (type == "typedef") return cont(typedef);
265 return pass(pushlex("stat"), expression, expect(";"), poplex);
266 }
267 function expression(type) {
268 if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
269 if (type == "function") return cont(functiondef);
270 if (type == "keyword c") return cont(maybeexpression);
271 if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
272 if (type == "operator") return cont(expression);
273 if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
274 if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
275 return cont();
276 }
277 function maybeexpression(type) {
278 if (type.match(/[;\}\)\],]/)) return pass();
279 return pass(expression);
280 }
281
282 function maybeoperator(type, value) {
283 if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
284 if (type == "operator" || type == ":") return cont(expression);
285 if (type == ";") return;
286 if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
287 if (type == ".") return cont(property, maybeoperator);
288 if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
289 }
290
291 function maybeattribute(type, value) {
292 if (type == "attribute") return cont(maybeattribute);
293 if (type == "function") return cont(functiondef);
294 if (type == "var") return cont(vardef1);
295 }
296
297 function metadef(type, value) {
298 if(type == ":") return cont(metadef);
299 if(type == "variable") return cont(metadef);
300 if(type == "(") return cont(pushlex(")"), comasep(metaargs, ")"), poplex, statement)
301 }
302 function metaargs(type, value) {
303 if(typ == "variable") return cont();
304 }
305
306 function importdef (type, value) {
307 if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
308 else if(type == "variable" || type == "property" || type == ".") return cont(importdef);
309 }
310
311 function typedef (type, value)
312 {
313 if(type == "variable" && /[A-Z]/.test(value.charAt(0))) { registerimport(value); return cont(); }
314 }
315
316 function maybelabel(type) {
317 if (type == ":") return cont(poplex, statement);
318 return pass(maybeoperator, expect(";"), poplex);
319 }
320 function property(type) {
321 if (type == "variable") {cx.marked = "property"; return cont();}
322 }
323 function objprop(type) {
324 if (type == "variable") cx.marked = "property";
325 if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
326 }
327 function commasep(what, end) {
328 function proceed(type) {
329 if (type == ",") return cont(what, proceed);
330 if (type == end) return cont();
331 return cont(expect(end));
332 }
333 return function commaSeparated(type) {
334 if (type == end) return cont();
335 else return pass(what, proceed);
336 };
337 }
338 function block(type) {
339 if (type == "}") return cont();
340 return pass(statement, block);
341 }
342 function vardef1(type, value) {
343 if (type == "variable"){register(value); return cont(typeuse, vardef2);}
344 return cont();
345 }
346 function vardef2(type, value) {
347 if (value == "=") return cont(expression, vardef2);
348 if (type == ",") return cont(vardef1);
349 }
350 function forspec1(type, value) {
351 if (type == "variable") {
352 register(value);
353 }
354 return cont(pushlex(")"), pushcontext, forin, expression, poplex, statement, popcontext);
355 }
356 function forin(type, value) {
357 if (value == "in") return cont();
358 }
359 function functiondef(type, value) {
360 if (type == "variable") {register(value); return cont(functiondef);}
361 if (value == "new") return cont(functiondef);
362 if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, typeuse, statement, popcontext);
363 }
364 function typeuse(type, value) {
365 if(type == ":") return cont(typestring);
366 }
367 function typestring(type, value) {
368 if(type == "type") return cont();
369 if(type == "variable") return cont();
370 if(type == "{") return cont(pushlex("}"), commasep(typeprop, "}"), poplex);
371 }
372 function typeprop(type, value) {
373 if(type == "variable") return cont(typeuse);
374 }
375 function funarg(type, value) {
376 if (type == "variable") {register(value); return cont(typeuse);}
377 }
378
379 // Interface
380
381 return {
382 startState: function(basecolumn) {
383 var defaulttypes = ["Int", "Float", "String", "Void", "Std", "Bool", "Dynamic", "Array"];
384 return {
385 tokenize: haxeTokenBase,
386 reAllowed: true,
387 kwAllowed: true,
388 cc: [],
389 lexical: new HaxeLexical((basecolumn || 0) - indentUnit, 0, "block", false),
390 localVars: parserConfig.localVars,
391 importedtypes: defaulttypes,
392 context: parserConfig.localVars && {vars: parserConfig.localVars},
393 indented: 0
394 };
395 },
396
397 token: function(stream, state) {
398 if (stream.sol()) {
399 if (!state.lexical.hasOwnProperty("align"))
400 state.lexical.align = false;
401 state.indented = stream.indentation();
402 }
403 if (stream.eatSpace()) return null;
404 var style = state.tokenize(stream, state);
405 if (type == "comment") return style;
406 state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
407 state.kwAllowed = type != '.';
408 return parseHaxe(state, style, type, content, stream);
409 },
410
411 indent: function(state, textAfter) {
412 if (state.tokenize != haxeTokenBase) return 0;
413 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
414 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
415 var type = lexical.type, closing = firstChar == type;
416 if (type == "vardef") return lexical.indented + 4;
417 else if (type == "form" && firstChar == "{") return lexical.indented;
418 else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
419 else if (lexical.info == "switch" && !closing)
420 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
421 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
422 else return lexical.indented + (closing ? 0 : indentUnit);
423 },
424 compareStates: function(state1, state2) {
425 return (state1.localVars == state2.localVars) && (state1.context == state2.context);
426 },
427
428 electricChars: "{}"
429 };
430 });
431
432 CodeMirror.defineMIME("text/x-haxe", "haxe");
@@ -0,0 +1,90 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Haxe mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="haxe.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: Haxe mode</h1>
13
14 <div><textarea id="code" name="code">
15 import one.two.Three;
16
17 @attr("test")
18 class Foo&lt;T&gt; extends Three
19 {
20 public function new()
21 {
22 noFoo = 12;
23 }
24
25 public static inline function doFoo(obj:{k:Int, l:Float}):Int
26 {
27 for(i in 0...10)
28 {
29 obj.k++;
30 trace(i);
31 var var1 = new Array();
32 if(var1.length > 1)
33 throw "Error";
34 }
35 // The following line should not be colored, the variable is scoped out
36 var1;
37 /* Multi line
38 * Comment test
39 */
40 return obj.k;
41 }
42 private function bar():Void
43 {
44 #if flash
45 var t1:String = "1.21";
46 #end
47 try {
48 doFoo({k:3, l:1.2});
49 }
50 catch (e : String) {
51 trace(e);
52 }
53 var t2:Float = cast(3.2);
54 var t3:haxe.Timer = new haxe.Timer();
55 var t4 = {k:Std.int(t2), l:Std.parseFloat(t1)};
56 var t5 = ~/123+.*$/i;
57 doFoo(t4);
58 untyped t1 = 4;
59 bob = new Foo&lt;Int&gt;
60 }
61 public var okFoo(default, never):Float;
62 var noFoo(getFoo, null):Int;
63 function getFoo():Int {
64 return noFoo;
65 }
66
67 public var three:Int;
68 }
69 enum Color
70 {
71 red;
72 green;
73 blue;
74 grey( v : Int );
75 rgb (r:Int,g:Int,b:Int);
76 }
77 </textarea></div>
78
79 <script>
80 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
81 lineNumbers: true,
82 matchBrackets: true,
83 indentUnit: 4,
84 indentWithTabs: true
85 });
86 </script>
87
88 <p><strong>MIME types defined:</strong> <code>text/x-haxe</code>.</p>
89 </body>
90 </html>
@@ -0,0 +1,68 b''
1 CodeMirror.defineMode("htmlembedded", function(config, parserConfig) {
2
3 //config settings
4 var scriptStartRegex = parserConfig.scriptStartRegex || /^<%/i,
5 scriptEndRegex = parserConfig.scriptEndRegex || /^%>/i;
6
7 //inner modes
8 var scriptingMode, htmlMixedMode;
9
10 //tokenizer when in html mode
11 function htmlDispatch(stream, state) {
12 if (stream.match(scriptStartRegex, false)) {
13 state.token=scriptingDispatch;
14 return scriptingMode.token(stream, state.scriptState);
15 }
16 else
17 return htmlMixedMode.token(stream, state.htmlState);
18 }
19
20 //tokenizer when in scripting mode
21 function scriptingDispatch(stream, state) {
22 if (stream.match(scriptEndRegex, false)) {
23 state.token=htmlDispatch;
24 return htmlMixedMode.token(stream, state.htmlState);
25 }
26 else
27 return scriptingMode.token(stream, state.scriptState);
28 }
29
30
31 return {
32 startState: function() {
33 scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec);
34 htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed");
35 return {
36 token : parserConfig.startOpen ? scriptingDispatch : htmlDispatch,
37 htmlState : htmlMixedMode.startState(),
38 scriptState : scriptingMode.startState()
39 }
40 },
41
42 token: function(stream, state) {
43 return state.token(stream, state);
44 },
45
46 indent: function(state, textAfter) {
47 if (state.token == htmlDispatch)
48 return htmlMixedMode.indent(state.htmlState, textAfter);
49 else
50 return scriptingMode.indent(state.scriptState, textAfter);
51 },
52
53 copyState: function(state) {
54 return {
55 token : state.token,
56 htmlState : CodeMirror.copyState(htmlMixedMode, state.htmlState),
57 scriptState : CodeMirror.copyState(scriptingMode, state.scriptState)
58 }
59 },
60
61
62 electricChars: "/{}:"
63 }
64 }, "htmlmixed");
65
66 CodeMirror.defineMIME("application/x-ejs", { name: "htmlembedded", scriptingModeSpec:"javascript"});
67 CodeMirror.defineMIME("application/x-aspx", { name: "htmlembedded", scriptingModeSpec:"text/x-csharp"});
68 CodeMirror.defineMIME("application/x-jsp", { name: "htmlembedded", scriptingModeSpec:"text/x-java"});
@@ -0,0 +1,49 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Html Embedded Scripts mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="../xml/xml.js"></script>
8 <script src="../javascript/javascript.js"></script>
9 <script src="../css/css.js"></script>
10 <script src="../htmlmixed/htmlmixed.js"></script>
11 <script src="htmlembedded.js"></script>
12 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
13 <link rel="stylesheet" href="../../doc/docs.css">
14 </head>
15 <body>
16 <h1>CodeMirror: Html Embedded Scripts mode</h1>
17
18 <form><textarea id="code" name="code">
19 <%
20 function hello(who) {
21 return "Hello " + who;
22 }
23 %>
24 This is an example of EJS (embedded javascript)
25 <p>The program says <%= hello("world") %>.</p>
26 <script>
27 alert("And here is some normal JS code"); // also colored
28 </script>
29 </textarea></form>
30
31 <script>
32 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
33 lineNumbers: true,
34 matchBrackets: true,
35 mode: "application/x-ejs",
36 indentUnit: 4,
37 indentWithTabs: true,
38 enterMode: "keep",
39 tabMode: "shift"
40 });
41 </script>
42
43 <p>Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on
44 JavaScript, CSS and XML.<br />Other dependancies include those of the scriping language chosen.</p>
45
46 <p><strong>MIME types defined:</strong> <code>application/x-aspx</code> (ASP.NET),
47 <code>application/x-ejs</code> (Embedded Javascript), <code>application/x-jsp</code> (JavaServer Pages)</p>
48 </body>
49 </html>
@@ -0,0 +1,37 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Jinja2 mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="jinja2.js"></script>
8 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 </head>
11 <body>
12 <h1>CodeMirror: Jinja2 mode</h1>
13 <form><textarea id="code" name="code">
14 &lt;html style="color: green"&gt;
15 &lt;!-- this is a comment --&gt;
16 &lt;head&gt;
17 &lt;title&gt;Jinja2 Example&lt;/title&gt;
18 &lt;/head&gt;
19 &lt;body&gt;
20 &lt;ul&gt;
21 {# this is a comment #}
22 {%- for item in li -%}
23 &lt;li&gt;
24 {{ item.label }}
25 &lt;/li&gt;
26 {% endfor -%}
27 &lt;/ul&gt;
28 &lt;/body&gt;
29 &lt;/html&gt;
30 </textarea></form>
31 <script>
32 var editor =
33 CodeMirror.fromTextArea(document.getElementById("code"), {mode:
34 {name: "jinja2", htmlMode: true}});
35 </script>
36 </body>
37 </html>
@@ -0,0 +1,42 b''
1 CodeMirror.defineMode("jinja2", function(config, parserConf) {
2 var keywords = ["block", "endblock", "for", "endfor", "in", "true", "false",
3 "loop", "none", "self", "super", "if", "as", "not", "and",
4 "else", "import", "with", "without", "context"];
5 keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b");
6
7 function tokenBase (stream, state) {
8 var ch = stream.next();
9 if (ch == "{") {
10 if (ch = stream.eat(/\{|%|#/)) {
11 stream.eat("-");
12 state.tokenize = inTag(ch);
13 return "tag";
14 }
15 }
16 }
17 function inTag (close) {
18 if (close == "{") {
19 close = "}";
20 }
21 return function (stream, state) {
22 var ch = stream.next();
23 if ((ch == close || (ch == "-" && stream.eat(close)))
24 && stream.eat("}")) {
25 state.tokenize = tokenBase;
26 return "tag";
27 }
28 if (stream.match(keywords)) {
29 return "keyword";
30 }
31 return close == "#" ? "comment" : "string";
32 };
33 }
34 return {
35 startState: function () {
36 return {tokenize: tokenBase};
37 },
38 token: function (stream, state) {
39 return state.tokenize(stream, state);
40 }
41 };
42 });
This diff has been collapsed as it changes many lines, (618 lines changed) Show them Hide them
@@ -0,0 +1,618 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: LESS mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="less.js"></script>
8 <style>.CodeMirror {background: #f8f8f8; border: 1px solid #ddd; font-size:12px} .CodeMirror-scroll {height: 400px}</style>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 <link rel="stylesheet" href="../../theme/lesser-dark.css">
11 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
12 </head>
13 <body>
14 <h1>CodeMirror: LESS mode</h1>
15 <form><textarea id="code" name="code">/* Some LESS code */
16
17 button {
18 width: 32px;
19 height: 32px;
20 border: 0;
21 margin: 4px;
22 cursor: pointer;
23 }
24 button.icon-plus { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#plus) no-repeat; }
25 button.icon-chart { background: url(http://dahlström.net/tmp/sharp-icons/svg-icon-target.svg#chart) no-repeat; }
26
27 button:hover { background-color: #999; }
28 button:active { background-color: #666; }
29
30 @test_a: #eeeQQQ;//this is not a valid hex value and thus parsed as an element id
31 @test_b: #eeeFFF //this is a valid hex value but the declaration doesn't end with a semicolon and thus parsed as an element id
32
33 #eee aaa .box
34 {
35 #test bbb {
36 width: 500px;
37 height: 250px;
38 background-image: url(dir/output/sheep.png), url( betweengrassandsky.png );
39 background-position: center bottom, left top;
40 background-repeat: no-repeat;
41 }
42 }
43
44 @base: #f938ab;
45
46 .box-shadow(@style, @c) when (iscolor(@c)) {
47 box-shadow: @style @c;
48 -webkit-box-shadow: @style @c;
49 -moz-box-shadow: @style @c;
50 }
51 .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
52 .box-shadow(@style, rgba(0, 0, 0, @alpha));
53 }
54
55 @color: #4D926F;
56
57 #header {
58 color: @color;
59 color: #000000;
60 }
61 h2 {
62 color: @color;
63 }
64
65 .rounded-corners (@radius: 5px) {
66 border-radius: @radius;
67 -webkit-border-radius: @radius;
68 -moz-border-radius: @radius;
69 }
70
71 #header {
72 .rounded-corners;
73 }
74 #footer {
75 .rounded-corners(10px);
76 }
77
78 .box-shadow (@x: 0, @y: 0, @blur: 1px, @alpha) {
79 @val: @x @y @blur rgba(0, 0, 0, @alpha);
80
81 box-shadow: @val;
82 -webkit-box-shadow: @val;
83 -moz-box-shadow: @val;
84 }
85 .box { @base: #f938ab;
86 color: saturate(@base, 5%);
87 border-color: lighten(@base, 30%);
88 div { .box-shadow(0, 0, 5px, 0.4) }
89 }
90
91 @import url("something.css");
92
93 @light-blue: hsl(190, 50%, 65%);
94 @light-yellow: desaturate(#fefec8, 10%);
95 @dark-yellow: desaturate(darken(@light-yellow, 10%), 40%);
96 @darkest: hsl(20, 0%, 15%);
97 @dark: hsl(190, 20%, 30%);
98 @medium: hsl(10, 60%, 30%);
99 @light: hsl(90, 40%, 20%);
100 @lightest: hsl(90, 20%, 90%);
101 @highlight: hsl(80, 50%, 90%);
102 @blue: hsl(210, 60%, 20%);
103 @alpha-blue: hsla(210, 60%, 40%, 0.5);
104
105 .box-shadow (@x, @y, @blur, @alpha) {
106 @value: @x @y @blur rgba(0, 0, 0, @alpha);
107 box-shadow: @value;
108 -moz-box-shadow: @value;
109 -webkit-box-shadow: @value;
110 }
111 .border-radius (@radius) {
112 border-radius: @radius;
113 -moz-border-radius: @radius;
114 -webkit-border-radius: @radius;
115 }
116
117 .border-radius (@radius, bottom) {
118 border-top-right-radius: 0;
119 border-top-left-radius: 0;
120 -moz-border-top-right-radius: 0;
121 -moz-border-top-left-radius: 0;
122 -webkit-border-top-left-radius: 0;
123 -webkit-border-top-right-radius: 0;
124 }
125 .border-radius (@radius, right) {
126 border-bottom-left-radius: 0;
127 border-top-left-radius: 0;
128 -moz-border-bottom-left-radius: 0;
129 -moz-border-top-left-radius: 0;
130 -webkit-border-bottom-left-radius: 0;
131 -webkit-border-top-left-radius: 0;
132 }
133 .box-shadow-inset (@x, @y, @blur, @color) {
134 box-shadow: @x @y @blur @color inset;
135 -moz-box-shadow: @x @y @blur @color inset;
136 -webkit-box-shadow: @x @y @blur @color inset;
137 }
138 .code () {
139 font-family: 'Bitstream Vera Sans Mono',
140 'DejaVu Sans Mono',
141 'Monaco',
142 Courier,
143 monospace !important;
144 }
145 .wrap () {
146 text-wrap: wrap;
147 white-space: pre-wrap; /* css-3 */
148 white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
149 white-space: -pre-wrap; /* Opera 4-6 */
150 white-space: -o-pre-wrap; /* Opera 7 */
151 word-wrap: break-word; /* Internet Explorer 5.5+ */
152 }
153
154 html { margin: 0 }
155 body {
156 background-color: @darkest;
157 margin: 0 auto;
158 font-family: Arial, sans-serif;
159 font-size: 100%;
160 overflow-x: hidden;
161 }
162 nav, header, footer, section, article {
163 display: block;
164 }
165 a {
166 color: #b83000;
167 }
168 h1 a {
169 color: black;
170 text-decoration: none;
171 }
172 a:hover {
173 text-decoration: underline;
174 }
175 h1, h2, h3, h4 {
176 margin: 0;
177 font-weight: normal;
178 }
179 ul, li {
180 list-style-type: none;
181 }
182 code { .code; }
183 code {
184 .string, .regexp { color: @dark }
185 .keyword { font-weight: bold }
186 .comment { color: rgba(0, 0, 0, 0.5) }
187 .number { color: @blue }
188 .class, .special { color: rgba(0, 50, 100, 0.8) }
189 }
190 pre {
191 padding: 0 30px;
192 .wrap;
193 }
194 blockquote {
195 font-style: italic;
196 }
197 body > footer {
198 text-align: left;
199 margin-left: 10px;
200 font-style: italic;
201 font-size: 18px;
202 color: #888;
203 }
204
205 #logo {
206 margin-top: 30px;
207 margin-bottom: 30px;
208 display: block;
209 width: 199px;
210 height: 81px;
211 background: url(/images/logo.png) no-repeat;
212 }
213 nav {
214 margin-left: 15px;
215 }
216 nav a, #dropdown li {
217 display: inline-block;
218 color: white;
219 line-height: 42px;
220 margin: 0;
221 padding: 0px 15px;
222 text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.5);
223 text-decoration: none;
224 border: 2px solid transparent;
225 border-width: 0 2px;
226 &:hover {
227 .dark-red;
228 text-decoration: none;
229 }
230 }
231 .dark-red {
232 @red: @medium;
233 border: 2px solid darken(@red, 25%);
234 border-left-color: darken(@red, 15%);
235 border-right-color: darken(@red, 15%);
236 border-bottom: 0;
237 border-top: 0;
238 background-color: darken(@red, 10%);
239 }
240
241 .content {
242 margin: 0 auto;
243 width: 980px;
244 }
245
246 #menu {
247 position: absolute;
248 width: 100%;
249 z-index: 3;
250 clear: both;
251 display: block;
252 background-color: @blue;
253 height: 42px;
254 border-top: 2px solid lighten(@alpha-blue, 20%);
255 border-bottom: 2px solid darken(@alpha-blue, 25%);
256 .box-shadow(0, 1px, 8px, 0.6);
257 -moz-box-shadow: 0 0 0 #000; // Because firefox sucks.
258
259 &.docked {
260 background-color: hsla(210, 60%, 40%, 0.4);
261 }
262 &:hover {
263 background-color: @blue;
264 }
265
266 #dropdown {
267 margin: 0 0 0 117px;
268 padding: 0;
269 padding-top: 5px;
270 display: none;
271 width: 190px;
272 border-top: 2px solid @medium;
273 color: @highlight;
274 border: 2px solid darken(@medium, 25%);
275 border-left-color: darken(@medium, 15%);
276 border-right-color: darken(@medium, 15%);
277 border-top-width: 0;
278 background-color: darken(@medium, 10%);
279 ul {
280 padding: 0px;
281 }
282 li {
283 font-size: 14px;
284 display: block;
285 text-align: left;
286 padding: 0;
287 border: 0;
288 a {
289 display: block;
290 padding: 0px 15px;
291 text-decoration: none;
292 color: white;
293 &:hover {
294 background-color: darken(@medium, 15%);
295 text-decoration: none;
296 }
297 }
298 }
299 .border-radius(5px, bottom);
300 .box-shadow(0, 6px, 8px, 0.5);
301 }
302 }
303
304 #main {
305 margin: 0 auto;
306 width: 100%;
307 background-color: @light-blue;
308 border-top: 8px solid darken(@light-blue, 5%);
309
310 #intro {
311 background-color: lighten(@light-blue, 25%);
312 float: left;
313 margin-top: -8px;
314 margin-right: 5px;
315
316 height: 380px;
317 position: relative;
318 z-index: 2;
319 font-family: 'Droid Serif', 'Georgia';
320 width: 395px;
321 padding: 45px 20px 23px 30px;
322 border: 2px dashed darken(@light-blue, 10%);
323 .box-shadow(1px, 0px, 6px, 0.5);
324 border-bottom: 0;
325 border-top: 0;
326 #download { color: transparent; border: 0; float: left; display: inline-block; margin: 15px 0 15px -5px; }
327 #download img { display: inline-block}
328 #download-info {
329 code {
330 font-size: 13px;
331 }
332 color: @blue + #333; display: inline; float: left; margin: 36px 0 0 15px }
333 }
334 h2 {
335 span {
336 color: @medium;
337 }
338 color: @blue;
339 margin: 20px 0;
340 font-size: 24px;
341 line-height: 1.2em;
342 }
343 h3 {
344 color: @blue;
345 line-height: 1.4em;
346 margin: 30px 0 15px 0;
347 font-size: 1em;
348 text-shadow: 0px 0px 0px @lightest;
349 span { color: @medium }
350 }
351 #example {
352 p {
353 font-size: 18px;
354 color: @blue;
355 font-weight: bold;
356 text-shadow: 0px 1px 1px @lightest;
357 }
358 pre {
359 margin: 0;
360 text-shadow: 0 -1px 1px @darkest;
361 margin-top: 20px;
362 background-color: desaturate(@darkest, 8%);
363 border: 0;
364 width: 450px;
365 color: lighten(@lightest, 2%);
366 background-repeat: repeat;
367 padding: 15px;
368 border: 1px dashed @lightest;
369 line-height: 15px;
370 .box-shadow(0, 0px, 15px, 0.5);
371 .code;
372 .border-radius(2px);
373 code .attribute { color: hsl(40, 50%, 70%) }
374 code .variable { color: hsl(120, 10%, 50%) }
375 code .element { color: hsl(170, 20%, 50%) }
376
377 code .string, .regexp { color: hsl(75, 50%, 65%) }
378 code .class { color: hsl(40, 40%, 60%); font-weight: normal }
379 code .id { color: hsl(50, 40%, 60%); font-weight: normal }
380 code .comment { color: rgba(255, 255, 255, 0.2) }
381 code .number, .color { color: hsl(10, 40%, 50%) }
382 code .class, code .mixin, .special { color: hsl(190, 20%, 50%) }
383 #time { color: #aaa }
384 }
385 float: right;
386 font-size: 12px;
387 margin: 0;
388 margin-top: 15px;
389 padding: 0;
390 width: 500px;
391 }
392 }
393
394
395 .page {
396 .content {
397 width: 870px;
398 padding: 45px;
399 }
400 margin: 0 auto;
401 font-family: 'Georgia', serif;
402 font-size: 18px;
403 line-height: 26px;
404 padding: 0 60px;
405 code {
406 font-size: 16px;
407 }
408 pre {
409 border-width: 1px;
410 border-style: dashed;
411 padding: 15px;
412 margin: 15px 0;
413 }
414 h1 {
415 text-align: left;
416 font-size: 40px;
417 margin-top: 15px;
418 margin-bottom: 35px;
419 }
420 p + h1 { margin-top: 60px }
421 h2, h3 {
422 margin: 30px 0 15px 0;
423 }
424 p + h2, pre + h2, code + h2 {
425 border-top: 6px solid rgba(255, 255, 255, 0.1);
426 padding-top: 30px;
427 }
428 h3 {
429 margin: 15px 0;
430 }
431 }
432
433
434 #docs {
435 @bg: lighten(@light-blue, 5%);
436 border-top: 2px solid lighten(@bg, 5%);
437 color: @blue;
438 background-color: @light-blue;
439 .box-shadow(0, -2px, 5px, 0.2);
440
441 h1 {
442 font-family: 'Droid Serif', 'Georgia', serif;
443 padding-top: 30px;
444 padding-left: 45px;
445 font-size: 44px;
446 text-align: left;
447 margin: 30px 0 !important;
448 text-shadow: 0px 1px 1px @lightest;
449 font-weight: bold;
450 }
451 .content {
452 clear: both;
453 border-color: transparent;
454 background-color: lighten(@light-blue, 25%);
455 .box-shadow(0, 5px, 5px, 0.4);
456 }
457 pre {
458 @background: lighten(@bg, 30%);
459 color: lighten(@blue, 10%);
460 background-color: @background;
461 border-color: lighten(@light-blue, 25%);
462 border-width: 2px;
463 code .attribute { color: hsl(40, 50%, 30%) }
464 code .variable { color: hsl(120, 10%, 30%) }
465 code .element { color: hsl(170, 20%, 30%) }
466
467 code .string, .regexp { color: hsl(75, 50%, 35%) }
468 code .class { color: hsl(40, 40%, 30%); font-weight: normal }
469 code .id { color: hsl(50, 40%, 30%); font-weight: normal }
470 code .comment { color: rgba(0, 0, 0, 0.4) }
471 code .number, .color { color: hsl(10, 40%, 30%) }
472 code .class, code .mixin, .special { color: hsl(190, 20%, 30%) }
473 }
474 pre code { font-size: 15px }
475 p + h2, pre + h2, code + h2 { border-top-color: rgba(0, 0, 0, 0.1) }
476 }
477
478 td {
479 padding-right: 30px;
480 }
481 #synopsis {
482 .box-shadow(0, 5px, 5px, 0.2);
483 }
484 #synopsis, #about {
485 h2 {
486 font-size: 30px;
487 padding: 10px 0;
488 }
489 h1 + h2 {
490 margin-top: 15px;
491 }
492 h3 { font-size: 22px }
493
494 .code-example {
495 border-spacing: 0;
496 border-width: 1px;
497 border-style: dashed;
498 padding: 0;
499 pre { border: 0; margin: 0 }
500 td {
501 border: 0;
502 margin: 0;
503 background-color: desaturate(darken(@darkest, 5%), 20%);
504 vertical-align: top;
505 padding: 0;
506 }
507 tr { padding: 0 }
508 }
509 .css-output {
510 td {
511 border-left: 0;
512 }
513 }
514 .less-example {
515 //border-right: 1px dotted rgba(255, 255, 255, 0.5) !important;
516 }
517 .css-output, .less-example {
518 width: 390px;
519 }
520 pre {
521 padding: 20px;
522 line-height: 20px;
523 font-size: 14px;
524 }
525 }
526 #about, #synopsis, #guide {
527 a {
528 text-decoration: none;
529 color: @light-yellow;
530 border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
531 &:hover {
532 text-decoration: none;
533 border-bottom: 1px dashed @light-yellow;
534 }
535 }
536 @bg: desaturate(darken(@darkest, 5%), 20%);
537 text-shadow: 0 -1px 1px lighten(@bg, 5%);
538 color: @highlight;
539 background-color: @bg;
540 .content {
541 background-color: desaturate(@darkest, 20%);
542 clear: both;
543 .box-shadow(0, 5px, 5px, 0.4);
544 }
545 h1, h2, h3 {
546 color: @dark-yellow;
547 }
548 pre {
549 code .attribute { color: hsl(40, 50%, 70%) }
550 code .variable { color: hsl(120, 10%, 50%) }
551 code .element { color: hsl(170, 20%, 50%) }
552
553 code .string, .regexp { color: hsl(75, 50%, 65%) }
554 code .class { color: hsl(40, 40%, 60%); font-weight: normal }
555 code .id { color: hsl(50, 40%, 60%); font-weight: normal }
556 code .comment { color: rgba(255, 255, 255, 0.2) }
557 code .number, .color { color: hsl(10, 40%, 50%) }
558 code .class, code .mixin, .special { color: hsl(190, 20%, 50%) }
559 background-color: @bg;
560 border-color: darken(@light-yellow, 5%);
561 }
562 code {
563 color: darken(@dark-yellow, 5%);
564 .string, .regexp { color: desaturate(@light-blue, 15%) }
565 .keyword { color: hsl(40, 40%, 60%); font-weight: normal }
566 .comment { color: rgba(255, 255, 255, 0.2) }
567 .number { color: lighten(@blue, 10%) }
568 .class, .special { color: hsl(190, 20%, 50%) }
569 }
570 }
571 #guide {
572 background-color: @darkest;
573 .content {
574 background-color: transparent;
575 }
576
577 }
578
579 #about {
580 background-color: @darkest !important;
581 .content {
582 background-color: desaturate(lighten(@darkest, 3%), 5%);
583 }
584 }
585 #synopsis {
586 background-color: desaturate(lighten(@darkest, 3%), 5%) !important;
587 .content {
588 background-color: desaturate(lighten(@darkest, 3%), 5%);
589 }
590 pre {}
591 }
592 #synopsis, #guide {
593 .content {
594 .box-shadow(0, 0px, 0px, 0.0);
595 }
596 }
597 #about footer {
598 margin-top: 30px;
599 padding-top: 30px;
600 border-top: 6px solid rgba(0, 0, 0, 0.1);
601 text-align: center;
602 font-size: 16px;
603 color: rgba(255, 255, 255, 0.35);
604 #copy { font-size: 12px }
605 text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.02);
606 }
607 </textarea></form>
608 <script>
609 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
610 theme: "lesser-dark",
611 lineNumbers : true,
612 matchBrackets : true
613 });
614 </script>
615
616 <p><strong>MIME types defined:</strong> <code>text/x-less</code>, <code>text/css</code> (if not previously defined).</p>
617 </body>
618 </html>
@@ -0,0 +1,232 b''
1 /*
2 LESS mode - http://www.lesscss.org/
3 Ported to CodeMirror by Peter Kroon
4 */
5
6 CodeMirror.defineMode("less", function(config) {
7 var indentUnit = config.indentUnit, type;
8 function ret(style, tp) {type = tp; return style;}
9 //html5 tags
10 var tags = ["a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"];
11
12 function inTagsArray(val){
13 for(var i=0; i<tags.length; i++){
14 if(val === tags[i]){
15 return true;
16 }
17 }
18 }
19
20 function tokenBase(stream, state) {
21 var ch = stream.next();
22
23 if (ch == "@") {stream.eatWhile(/[\w\-]/); return ret("meta", stream.current());}
24 else if (ch == "/" && stream.eat("*")) {
25 state.tokenize = tokenCComment;
26 return tokenCComment(stream, state);
27 }
28 else if (ch == "<" && stream.eat("!")) {
29 state.tokenize = tokenSGMLComment;
30 return tokenSGMLComment(stream, state);
31 }
32 else if (ch == "=") ret(null, "compare");
33 else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
34 else if (ch == "\"" || ch == "'") {
35 state.tokenize = tokenString(ch);
36 return state.tokenize(stream, state);
37 }
38 else if (ch == "/") { // lesscss e.g.: .png will not be parsed as a class
39 if(stream.eat("/")){
40 state.tokenize = tokenSComment;
41 return tokenSComment(stream, state);
42 }else{
43 stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/);
44 if(/\/|\)|#/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == ")")))return ret("string", "string");//let url(/images/logo.png) without quotes return as string
45 return ret("number", "unit");
46 }
47 }
48 else if (ch == "!") {
49 stream.match(/^\s*\w*/);
50 return ret("keyword", "important");
51 }
52 else if (/\d/.test(ch)) {
53 stream.eatWhile(/[\w.%]/);
54 return ret("number", "unit");
55 }
56 else if (/[,+<>*\/]/.test(ch)) {//removed . dot character original was [,.+>*\/]
57 return ret(null, "select-op");
58 }
59 else if (/[;{}:\[\]()]/.test(ch)) { //added () char for lesscss original was [;{}:\[\]]
60 if(ch == ":"){
61 stream.eatWhile(/[active|hover|link|visited]/);
62 if( stream.current().match(/active|hover|link|visited/)){
63 return ret("tag", "tag");
64 }else{
65 return ret(null, ch);
66 }
67 }else{
68 return ret(null, ch);
69 }
70 }
71 else if (ch == ".") { // lesscss
72 stream.eatWhile(/[\a-zA-Z0-9\-_]/);
73 return ret("tag", "tag");
74 }
75 else if (ch == "#") { // lesscss
76 //we don't eat white-space, we want the hex color and or id only
77 stream.eatWhile(/[A-Za-z0-9]/);
78 //check if there is a proper hex color length e.g. #eee || #eeeEEE
79 if(stream.current().length ===4 || stream.current().length ===7){
80 if(stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false) != null){//is there a valid hex color value present in the current stream
81 //when not a valid hex value, parse as id
82 if(stream.current().substring(1) != stream.current().match(/[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/,false))return ret("atom", "tag");
83 //eat white-space
84 stream.eatSpace();
85 //when hex value declaration doesn't end with [;,] but is does with a slash/cc comment treat it as an id, just like the other hex values that don't end with[;,]
86 if( /[\/<>.(){!$%^&*_\-\\?=+\|#'~`]/.test(stream.peek()) )return ret("atom", "tag");
87 //#time { color: #aaa }
88 else if(stream.peek() == "}" )return ret("number", "unit");
89 //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa
90 else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag");
91 //when a hex value is on the end of a line, parse as id
92 else if(stream.eol())return ret("atom", "tag");
93 //default
94 else return ret("number", "unit");
95 }else{//when not a valid hexvalue in the current stream e.g. #footer
96 stream.eatWhile(/[\w\\\-]/);
97 return ret("atom", "tag");
98 }
99 }else{
100 stream.eatWhile(/[\w\\\-]/);
101 return ret("atom", "tag");
102 }
103 }
104 else if (ch == "&") {
105 stream.eatWhile(/[\w\-]/);
106 return ret(null, ch);
107 }
108 else {
109 stream.eatWhile(/[\w\\\-_%.{]/);
110 if(stream.current().match(/http|https/) != null){
111 stream.eatWhile(/[\w\\\-_%.{:\/]/);
112 return ret("string", "string");
113 }else if(stream.peek() == "<" || stream.peek() == ">"){
114 return ret("tag", "tag");
115 }else if( stream.peek().match(/\(/) != null ){// lessc
116 return ret(null, ch);
117 }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png)
118 return ret("string", "string");
119 }else if( stream.current().match(/\-\d|\-.\d/) ){ // lesscss match e.g.: -5px -0.4 etc... only colorize the minus sign
120 //stream.backUp(stream.current().length-1); //commment out these 2 comment if you want the minus sign to be parsed as null -500px
121 //return ret(null, ch);
122 return ret("number", "unit");
123 }else if( inTagsArray(stream.current()) ){ // lesscss match html tags
124 return ret("tag", "tag");
125 }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){
126 if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){
127 stream.backUp(1);
128 return ret("tag", "tag");
129 }//end if
130 if( (stream.eatSpace() && stream.peek().match(/[{<>.a-zA-Z]/) != null) || stream.eol() )return ret("tag", "tag");//e.g. button.icon-plus
131 return ret("string", "string");//let url(/images/logo.png) without quotes return as string
132 }else if( stream.eol() ){
133 if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1);
134 return ret("tag", "tag");
135 }else{
136 return ret("variable", "variable");
137 }
138 }
139
140 }
141
142 function tokenSComment(stream, state) {// SComment = Slash comment
143 stream.skipToEnd();
144 state.tokenize = tokenBase;
145 return ret("comment", "comment");
146 }
147
148 function tokenCComment(stream, state) {
149 var maybeEnd = false, ch;
150 while ((ch = stream.next()) != null) {
151 if (maybeEnd && ch == "/") {
152 state.tokenize = tokenBase;
153 break;
154 }
155 maybeEnd = (ch == "*");
156 }
157 return ret("comment", "comment");
158 }
159
160 function tokenSGMLComment(stream, state) {
161 var dashes = 0, ch;
162 while ((ch = stream.next()) != null) {
163 if (dashes >= 2 && ch == ">") {
164 state.tokenize = tokenBase;
165 break;
166 }
167 dashes = (ch == "-") ? dashes + 1 : 0;
168 }
169 return ret("comment", "comment");
170 }
171
172 function tokenString(quote) {
173 return function(stream, state) {
174 var escaped = false, ch;
175 while ((ch = stream.next()) != null) {
176 if (ch == quote && !escaped)
177 break;
178 escaped = !escaped && ch == "\\";
179 }
180 if (!escaped) state.tokenize = tokenBase;
181 return ret("string", "string");
182 };
183 }
184
185 return {
186 startState: function(base) {
187 return {tokenize: tokenBase,
188 baseIndent: base || 0,
189 stack: []};
190 },
191
192 token: function(stream, state) {
193 if (stream.eatSpace()) return null;
194 var style = state.tokenize(stream, state);
195
196 var context = state.stack[state.stack.length-1];
197 if (type == "hash" && context == "rule") style = "atom";
198 else if (style == "variable") {
199 if (context == "rule") style = null; //"tag"
200 else if (!context || context == "@media{"){
201 style = stream.current() == "when" ? "variable" :
202 stream.string.match(/#/g) != undefined ? null :
203 /[\s,|\s\)]/.test(stream.peek()) ? "tag" : null;
204 }
205 }
206
207 if (context == "rule" && /^[\{\};]$/.test(type))
208 state.stack.pop();
209 if (type == "{") {
210 if (context == "@media") state.stack[state.stack.length-1] = "@media{";
211 else state.stack.push("{");
212 }
213 else if (type == "}") state.stack.pop();
214 else if (type == "@media") state.stack.push("@media");
215 else if (context == "{" && type != "comment") state.stack.push("rule");
216 return style;
217 },
218
219 indent: function(state, textAfter) {
220 var n = state.stack.length;
221 if (/^\}/.test(textAfter))
222 n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
223 return state.baseIndent + n * indentUnit;
224 },
225
226 electricChars: "}"
227 };
228 });
229
230 CodeMirror.defineMIME("text/x-less", "less");
231 if (!CodeMirror.mimeModes.hasOwnProperty("text/css"))
232 CodeMirror.defineMIME("text/css", "less");
@@ -0,0 +1,72 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Lua mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="lua.js"></script>
8 <link rel="stylesheet" href="../../theme/neat.css">
9 <style>.CodeMirror {border: 1px solid black;}</style>
10 <link rel="stylesheet" href="../../doc/docs.css">
11 </head>
12 <body>
13 <h1>CodeMirror: Lua mode</h1>
14 <form><textarea id="code" name="code">
15 --[[
16 example useless code to show lua syntax highlighting
17 this is multiline comment
18 ]]
19
20 function blahblahblah(x)
21
22 local table = {
23 "asd" = 123,
24 "x" = 0.34,
25 }
26 if x ~= 3 then
27 print( x )
28 elseif x == "string"
29 my_custom_function( 0x34 )
30 else
31 unknown_function( "some string" )
32 end
33
34 --single line comment
35
36 end
37
38 function blablabla3()
39
40 for k,v in ipairs( table ) do
41 --abcde..
42 y=[=[
43 x=[[
44 x is a multi line string
45 ]]
46 but its definition is iside a highest level string!
47 ]=]
48 print(" \"\" ")
49
50 s = math.sin( x )
51 end
52
53 end
54 </textarea></form>
55 <script>
56 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
57 tabMode: "indent",
58 matchBrackets: true,
59 theme: "neat"
60 });
61 </script>
62
63 <p>Loosely based on Franciszek
64 Wawrzak's <a href="http://codemirror.net/1/contrib/lua">CodeMirror
65 1 mode</a>. One configuration parameter is
66 supported, <code>specials</code>, to which you can provide an
67 array of strings to have those identifiers highlighted with
68 the <code>lua-special</code> style.</p>
69 <p><strong>MIME types defined:</strong> <code>text/x-lua</code>.</p>
70
71 </body>
72 </html>
@@ -0,0 +1,140 b''
1 // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's
2 // CodeMirror 1 mode.
3 // highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting
4
5 CodeMirror.defineMode("lua", function(config, parserConfig) {
6 var indentUnit = config.indentUnit;
7
8 function prefixRE(words) {
9 return new RegExp("^(?:" + words.join("|") + ")", "i");
10 }
11 function wordRE(words) {
12 return new RegExp("^(?:" + words.join("|") + ")$", "i");
13 }
14 var specials = wordRE(parserConfig.specials || []);
15
16 // long list of standard functions from lua manual
17 var builtins = wordRE([
18 "_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load",
19 "loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require",
20 "select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall",
21
22 "coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield",
23
24 "debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable",
25 "debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable",
26 "debug.setupvalue","debug.traceback",
27
28 "close","flush","lines","read","seek","setvbuf","write",
29
30 "io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin",
31 "io.stdout","io.tmpfile","io.type","io.write",
32
33 "math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg",
34 "math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max",
35 "math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh",
36 "math.sqrt","math.tan","math.tanh",
37
38 "os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale",
39 "os.time","os.tmpname",
40
41 "package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload",
42 "package.seeall",
43
44 "string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub",
45 "string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper",
46
47 "table.concat","table.insert","table.maxn","table.remove","table.sort"
48 ]);
49 var keywords = wordRE(["and","break","elseif","false","nil","not","or","return",
50 "true","function", "end", "if", "then", "else", "do",
51 "while", "repeat", "until", "for", "in", "local" ]);
52
53 var indentTokens = wordRE(["function", "if","repeat","do", "\\(", "{"]);
54 var dedentTokens = wordRE(["end", "until", "\\)", "}"]);
55 var dedentPartial = prefixRE(["end", "until", "\\)", "}", "else", "elseif"]);
56
57 function readBracket(stream) {
58 var level = 0;
59 while (stream.eat("=")) ++level;
60 stream.eat("[");
61 return level;
62 }
63
64 function normal(stream, state) {
65 var ch = stream.next();
66 if (ch == "-" && stream.eat("-")) {
67 if (stream.eat("["))
68 return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state);
69 stream.skipToEnd();
70 return "comment";
71 }
72 if (ch == "\"" || ch == "'")
73 return (state.cur = string(ch))(stream, state);
74 if (ch == "[" && /[\[=]/.test(stream.peek()))
75 return (state.cur = bracketed(readBracket(stream), "string"))(stream, state);
76 if (/\d/.test(ch)) {
77 stream.eatWhile(/[\w.%]/);
78 return "number";
79 }
80 if (/[\w_]/.test(ch)) {
81 stream.eatWhile(/[\w\\\-_.]/);
82 return "variable";
83 }
84 return null;
85 }
86
87 function bracketed(level, style) {
88 return function(stream, state) {
89 var curlev = null, ch;
90 while ((ch = stream.next()) != null) {
91 if (curlev == null) {if (ch == "]") curlev = 0;}
92 else if (ch == "=") ++curlev;
93 else if (ch == "]" && curlev == level) { state.cur = normal; break; }
94 else curlev = null;
95 }
96 return style;
97 };
98 }
99
100 function string(quote) {
101 return function(stream, state) {
102 var escaped = false, ch;
103 while ((ch = stream.next()) != null) {
104 if (ch == quote && !escaped) break;
105 escaped = !escaped && ch == "\\";
106 }
107 if (!escaped) state.cur = normal;
108 return "string";
109 };
110 }
111
112 return {
113 startState: function(basecol) {
114 return {basecol: basecol || 0, indentDepth: 0, cur: normal};
115 },
116
117 token: function(stream, state) {
118 if (stream.eatSpace()) return null;
119 var style = state.cur(stream, state);
120 var word = stream.current();
121 if (style == "variable") {
122 if (keywords.test(word)) style = "keyword";
123 else if (builtins.test(word)) style = "builtin";
124 else if (specials.test(word)) style = "variable-2";
125 }
126 if ((style != "comment") && (style != "string")){
127 if (indentTokens.test(word)) ++state.indentDepth;
128 else if (dedentTokens.test(word)) --state.indentDepth;
129 }
130 return style;
131 },
132
133 indent: function(state, textAfter) {
134 var closing = dedentPartial.test(textAfter);
135 return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0));
136 }
137 };
138 });
139
140 CodeMirror.defineMIME("text/x-lua", "lua");
@@ -0,0 +1,41 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: MySQL mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="mysql.js"></script>
8 <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
9 <link rel="stylesheet" href="../../doc/docs.css">
10 </head>
11 <body>
12 <h1>CodeMirror: MySQL mode</h1>
13 <form><textarea id="code" name="code">
14 -- Comment for the code
15 -- MySQL Mode for CodeMirror2 by MySQLTools http://github.com/partydroid/MySQL-Tools
16 SELECT UNIQUE `var1` as `variable`,
17 MAX(`var5`) as `max`,
18 MIN(`var5`) as `min`,
19 STDEV(`var5`) as `dev`
20 FROM `table`
21
22 LEFT JOIN `table2` ON `var2` = `variable`
23
24 ORDER BY `var3` DESC
25 GROUP BY `groupvar`
26
27 LIMIT 0,30;
28
29 </textarea></form>
30 <script>
31 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
32 mode: "text/x-mysql",
33 tabMode: "indent",
34 matchBrackets: true
35 });
36 </script>
37
38 <p><strong>MIME types defined:</strong> <code>text/x-mysql</code>.</p>
39
40 </body>
41 </html>
@@ -0,0 +1,186 b''
1 /*
2 * MySQL Mode for CodeMirror 2 by MySQL-Tools
3 * @author James Thorne (partydroid)
4 * @link http://github.com/partydroid/MySQL-Tools
5 * @link http://mysqltools.org
6 * @version 02/Jan/2012
7 */
8 CodeMirror.defineMode("mysql", function(config) {
9 var indentUnit = config.indentUnit;
10 var curPunc;
11
12 function wordRegexp(words) {
13 return new RegExp("^(?:" + words.join("|") + ")$", "i");
14 }
15 var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
16 "isblank", "isliteral", "union", "a"]);
17 var keywords = wordRegexp([
18 ('ACCESSIBLE'),('ALTER'),('AS'),('BEFORE'),('BINARY'),('BY'),('CASE'),('CHARACTER'),('COLUMN'),('CONTINUE'),('CROSS'),('CURRENT_TIMESTAMP'),('DATABASE'),('DAY_MICROSECOND'),('DEC'),('DEFAULT'),
19 ('DESC'),('DISTINCT'),('DOUBLE'),('EACH'),('ENCLOSED'),('EXIT'),('FETCH'),('FLOAT8'),('FOREIGN'),('GRANT'),('HIGH_PRIORITY'),('HOUR_SECOND'),('IN'),('INNER'),('INSERT'),('INT2'),('INT8'),
20 ('INTO'),('JOIN'),('KILL'),('LEFT'),('LINEAR'),('LOCALTIME'),('LONG'),('LOOP'),('MATCH'),('MEDIUMTEXT'),('MINUTE_SECOND'),('NATURAL'),('NULL'),('OPTIMIZE'),('OR'),('OUTER'),('PRIMARY'),
21 ('RANGE'),('READ_WRITE'),('REGEXP'),('REPEAT'),('RESTRICT'),('RIGHT'),('SCHEMAS'),('SENSITIVE'),('SHOW'),('SPECIFIC'),('SQLSTATE'),('SQL_CALC_FOUND_ROWS'),('STARTING'),('TERMINATED'),
22 ('TINYINT'),('TRAILING'),('UNDO'),('UNLOCK'),('USAGE'),('UTC_DATE'),('VALUES'),('VARCHARACTER'),('WHERE'),('WRITE'),('ZEROFILL'),('ALL'),('AND'),('ASENSITIVE'),('BIGINT'),('BOTH'),('CASCADE'),
23 ('CHAR'),('COLLATE'),('CONSTRAINT'),('CREATE'),('CURRENT_TIME'),('CURSOR'),('DAY_HOUR'),('DAY_SECOND'),('DECLARE'),('DELETE'),('DETERMINISTIC'),('DIV'),('DUAL'),('ELSEIF'),('EXISTS'),('FALSE'),
24 ('FLOAT4'),('FORCE'),('FULLTEXT'),('HAVING'),('HOUR_MINUTE'),('IGNORE'),('INFILE'),('INSENSITIVE'),('INT1'),('INT4'),('INTERVAL'),('ITERATE'),('KEYS'),('LEAVE'),('LIMIT'),('LOAD'),('LOCK'),
25 ('LONGTEXT'),('MASTER_SSL_VERIFY_SERVER_CERT'),('MEDIUMINT'),('MINUTE_MICROSECOND'),('MODIFIES'),('NO_WRITE_TO_BINLOG'),('ON'),('OPTIONALLY'),('OUT'),('PRECISION'),('PURGE'),('READS'),
26 ('REFERENCES'),('RENAME'),('REQUIRE'),('REVOKE'),('SCHEMA'),('SELECT'),('SET'),('SPATIAL'),('SQLEXCEPTION'),('SQL_BIG_RESULT'),('SSL'),('TABLE'),('TINYBLOB'),('TO'),('TRUE'),('UNIQUE'),
27 ('UPDATE'),('USING'),('UTC_TIMESTAMP'),('VARCHAR'),('WHEN'),('WITH'),('YEAR_MONTH'),('ADD'),('ANALYZE'),('ASC'),('BETWEEN'),('BLOB'),('CALL'),('CHANGE'),('CHECK'),('CONDITION'),('CONVERT'),
28 ('CURRENT_DATE'),('CURRENT_USER'),('DATABASES'),('DAY_MINUTE'),('DECIMAL'),('DELAYED'),('DESCRIBE'),('DISTINCTROW'),('DROP'),('ELSE'),('ESCAPED'),('EXPLAIN'),('FLOAT'),('FOR'),('FROM'),
29 ('GROUP'),('HOUR_MICROSECOND'),('IF'),('INDEX'),('INOUT'),('INT'),('INT3'),('INTEGER'),('IS'),('KEY'),('LEADING'),('LIKE'),('LINES'),('LOCALTIMESTAMP'),('LONGBLOB'),('LOW_PRIORITY'),
30 ('MEDIUMBLOB'),('MIDDLEINT'),('MOD'),('NOT'),('NUMERIC'),('OPTION'),('ORDER'),('OUTFILE'),('PROCEDURE'),('READ'),('REAL'),('RELEASE'),('REPLACE'),('RETURN'),('RLIKE'),('SECOND_MICROSECOND'),
31 ('SEPARATOR'),('SMALLINT'),('SQL'),('SQLWARNING'),('SQL_SMALL_RESULT'),('STRAIGHT_JOIN'),('THEN'),('TINYTEXT'),('TRIGGER'),('UNION'),('UNSIGNED'),('USE'),('UTC_TIME'),('VARBINARY'),('VARYING'),
32 ('WHILE'),('XOR'),('FULL'),('COLUMNS'),('MIN'),('MAX'),('STDEV'),('COUNT')
33 ]);
34 var operatorChars = /[*+\-<>=&|]/;
35
36 function tokenBase(stream, state) {
37 var ch = stream.next();
38 curPunc = null;
39 if (ch == "$" || ch == "?") {
40 stream.match(/^[\w\d]*/);
41 return "variable-2";
42 }
43 else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
44 stream.match(/^[^\s\u00a0>]*>?/);
45 return "atom";
46 }
47 else if (ch == "\"" || ch == "'") {
48 state.tokenize = tokenLiteral(ch);
49 return state.tokenize(stream, state);
50 }
51 else if (ch == "`") {
52 state.tokenize = tokenOpLiteral(ch);
53 return state.tokenize(stream, state);
54 }
55 else if (/[{}\(\),\.;\[\]]/.test(ch)) {
56 curPunc = ch;
57 return null;
58 }
59 else if (ch == "-") {
60 var ch2 = stream.next();
61 if (ch2=="-") {
62 stream.skipToEnd();
63 return "comment";
64 }
65 }
66 else if (operatorChars.test(ch)) {
67 stream.eatWhile(operatorChars);
68 return null;
69 }
70 else if (ch == ":") {
71 stream.eatWhile(/[\w\d\._\-]/);
72 return "atom";
73 }
74 else {
75 stream.eatWhile(/[_\w\d]/);
76 if (stream.eat(":")) {
77 stream.eatWhile(/[\w\d_\-]/);
78 return "atom";
79 }
80 var word = stream.current(), type;
81 if (ops.test(word))
82 return null;
83 else if (keywords.test(word))
84 return "keyword";
85 else
86 return "variable";
87 }
88 }
89
90 function tokenLiteral(quote) {
91 return function(stream, state) {
92 var escaped = false, ch;
93 while ((ch = stream.next()) != null) {
94 if (ch == quote && !escaped) {
95 state.tokenize = tokenBase;
96 break;
97 }
98 escaped = !escaped && ch == "\\";
99 }
100 return "string";
101 };
102 }
103
104 function tokenOpLiteral(quote) {
105 return function(stream, state) {
106 var escaped = false, ch;
107 while ((ch = stream.next()) != null) {
108 if (ch == quote && !escaped) {
109 state.tokenize = tokenBase;
110 break;
111 }
112 escaped = !escaped && ch == "\\";
113 }
114 return "variable-2";
115 };
116 }
117
118
119 function pushContext(state, type, col) {
120 state.context = {prev: state.context, indent: state.indent, col: col, type: type};
121 }
122 function popContext(state) {
123 state.indent = state.context.indent;
124 state.context = state.context.prev;
125 }
126
127 return {
128 startState: function(base) {
129 return {tokenize: tokenBase,
130 context: null,
131 indent: 0,
132 col: 0};
133 },
134
135 token: function(stream, state) {
136 if (stream.sol()) {
137 if (state.context && state.context.align == null) state.context.align = false;
138 state.indent = stream.indentation();
139 }
140 if (stream.eatSpace()) return null;
141 var style = state.tokenize(stream, state);
142
143 if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") {
144 state.context.align = true;
145 }
146
147 if (curPunc == "(") pushContext(state, ")", stream.column());
148 else if (curPunc == "[") pushContext(state, "]", stream.column());
149 else if (curPunc == "{") pushContext(state, "}", stream.column());
150 else if (/[\]\}\)]/.test(curPunc)) {
151 while (state.context && state.context.type == "pattern") popContext(state);
152 if (state.context && curPunc == state.context.type) popContext(state);
153 }
154 else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state);
155 else if (/atom|string|variable/.test(style) && state.context) {
156 if (/[\}\]]/.test(state.context.type))
157 pushContext(state, "pattern", stream.column());
158 else if (state.context.type == "pattern" && !state.context.align) {
159 state.context.align = true;
160 state.context.col = stream.column();
161 }
162 }
163
164 return style;
165 },
166
167 indent: function(state, textAfter) {
168 var firstChar = textAfter && textAfter.charAt(0);
169 var context = state.context;
170 if (/[\]\}]/.test(firstChar))
171 while (context && context.type == "pattern") context = context.prev;
172
173 var closing = context && firstChar == context.type;
174 if (!context)
175 return 0;
176 else if (context.type == "pattern")
177 return context.col;
178 else if (context.align)
179 return context.col + (closing ? 0 : 1);
180 else
181 return context.indent + (closing ? 0 : indentUnit);
182 }
183 };
184 });
185
186 CodeMirror.defineMIME("text/x-mysql", "mysql");
@@ -0,0 +1,32 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: NTriples mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="ntriples.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style type="text/css">
10 .CodeMirror {
11 border: 1px solid #eee;
12 }
13 </style>
14 </head>
15 <body>
16 <h1>CodeMirror: NTriples mode</h1>
17 <form>
18 <textarea id="ntriples" name="ntriples">
19 <http://Sub1> <http://pred1> <http://obj> .
20 <http://Sub2> <http://pred2#an2> "literal 1" .
21 <http://Sub3#an3> <http://pred3> _:bnode3 .
22 _:bnode4 <http://pred4> "literal 2"@lang .
23 _:bnode5 <http://pred5> "literal 3"^^<http://type> .
24 </textarea>
25 </form>
26
27 <script>
28 var editor = CodeMirror.fromTextArea(document.getElementById("ntriples"), {});
29 </script>
30 <p><strong>MIME types defined:</strong> <code>text/n-triples</code>.</p>
31 </body>
32 </html>
@@ -0,0 +1,172 b''
1 /**********************************************************
2 * This script provides syntax highlighting support for
3 * the Ntriples format.
4 * Ntriples format specification:
5 * http://www.w3.org/TR/rdf-testcases/#ntriples
6 ***********************************************************/
7
8 /*
9 The following expression defines the defined ASF grammar transitions.
10
11 pre_subject ->
12 {
13 ( writing_subject_uri | writing_bnode_uri )
14 -> pre_predicate
15 -> writing_predicate_uri
16 -> pre_object
17 -> writing_object_uri | writing_object_bnode |
18 (
19 writing_object_literal
20 -> writing_literal_lang | writing_literal_type
21 )
22 -> post_object
23 -> BEGIN
24 } otherwise {
25 -> ERROR
26 }
27 */
28 CodeMirror.defineMode("ntriples", function() {
29
30 Location = {
31 PRE_SUBJECT : 0,
32 WRITING_SUB_URI : 1,
33 WRITING_BNODE_URI : 2,
34 PRE_PRED : 3,
35 WRITING_PRED_URI : 4,
36 PRE_OBJ : 5,
37 WRITING_OBJ_URI : 6,
38 WRITING_OBJ_BNODE : 7,
39 WRITING_OBJ_LITERAL : 8,
40 WRITING_LIT_LANG : 9,
41 WRITING_LIT_TYPE : 10,
42 POST_OBJ : 11,
43 ERROR : 12
44 };
45 function transitState(currState, c) {
46 var currLocation = currState.location;
47 var ret;
48
49 // Opening.
50 if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI;
51 else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI;
52 else if(currLocation == Location.PRE_PRED && c == '<') ret = Location.WRITING_PRED_URI;
53 else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI;
54 else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE;
55 else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL;
56
57 // Closing.
58 else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED;
59 else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED;
60 else if(currLocation == Location.WRITING_PRED_URI && c == '>') ret = Location.PRE_OBJ;
61 else if(currLocation == Location.WRITING_OBJ_URI && c == '>') ret = Location.POST_OBJ;
62 else if(currLocation == Location.WRITING_OBJ_BNODE && c == ' ') ret = Location.POST_OBJ;
63 else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ;
64 else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ;
65 else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ;
66
67 // Closing typed and language literal.
68 else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG;
69 else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE;
70
71 // Spaces.
72 else if( c == ' ' &&
73 (
74 currLocation == Location.PRE_SUBJECT ||
75 currLocation == Location.PRE_PRED ||
76 currLocation == Location.PRE_OBJ ||
77 currLocation == Location.POST_OBJ
78 )
79 ) ret = currLocation;
80
81 // Reset.
82 else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT;
83
84 // Error
85 else ret = Location.ERROR;
86
87 currState.location=ret;
88 }
89
90 untilSpace = function(c) { return c != ' '; };
91 untilEndURI = function(c) { return c != '>'; };
92 return {
93 startState: function() {
94 return {
95 location : Location.PRE_SUBJECT,
96 uris : [],
97 anchors : [],
98 bnodes : [],
99 langs : [],
100 types : []
101 };
102 },
103 token: function(stream, state) {
104 var ch = stream.next();
105 if(ch == '<') {
106 transitState(state, ch);
107 var parsedURI = '';
108 stream.eatWhile( function(c) { if( c != '#' && c != '>' ) { parsedURI += c; return true; } return false;} );
109 state.uris.push(parsedURI);
110 if( stream.match('#', false) ) return 'variable';
111 stream.next();
112 transitState(state, '>');
113 return 'variable';
114 }
115 if(ch == '#') {
116 var parsedAnchor = '';
117 stream.eatWhile(function(c) { if(c != '>' && c != ' ') { parsedAnchor+= c; return true; } return false});
118 state.anchors.push(parsedAnchor);
119 return 'variable-2';
120 }
121 if(ch == '>') {
122 transitState(state, '>');
123 return 'variable';
124 }
125 if(ch == '_') {
126 transitState(state, ch);
127 var parsedBNode = '';
128 stream.eatWhile(function(c) { if( c != ' ' ) { parsedBNode += c; return true; } return false;});
129 state.bnodes.push(parsedBNode);
130 stream.next();
131 transitState(state, ' ');
132 return 'builtin';
133 }
134 if(ch == '"') {
135 transitState(state, ch);
136 stream.eatWhile( function(c) { return c != '"'; } );
137 stream.next();
138 if( stream.peek() != '@' && stream.peek() != '^' ) {
139 transitState(state, '"');
140 }
141 return 'string';
142 }
143 if( ch == '@' ) {
144 transitState(state, '@');
145 var parsedLang = '';
146 stream.eatWhile(function(c) { if( c != ' ' ) { parsedLang += c; return true; } return false;});
147 state.langs.push(parsedLang);
148 stream.next();
149 transitState(state, ' ');
150 return 'string-2';
151 }
152 if( ch == '^' ) {
153 stream.next();
154 transitState(state, '^');
155 var parsedType = '';
156 stream.eatWhile(function(c) { if( c != '>' ) { parsedType += c; return true; } return false;} );
157 state.types.push(parsedType);
158 stream.next();
159 transitState(state, '>');
160 return 'variable';
161 }
162 if( ch == ' ' ) {
163 transitState(state, ch);
164 }
165 if( ch == '.' ) {
166 transitState(state, ch);
167 }
168 }
169 };
170 });
171
172 CodeMirror.defineMIME("text/n-triples", "ntriples");
@@ -0,0 +1,130 b''
1 <!doctype html>
2 <meta charset=utf-8>
3 <title>CodeMirror: OCaml mode</title>
4
5 <link rel=stylesheet href=../../lib/codemirror.css>
6 <link rel=stylesheet href=../../doc/docs.css>
7
8 <style type=text/css>
9 .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
10 </style>
11
12 <script src=../../lib/codemirror.js></script>
13 <script src=ocaml.js></script>
14
15 <h1>CodeMirror: OCaml mode</h1>
16
17 <textarea id=code>
18 (* Summing a list of integers *)
19 let rec sum xs =
20 match xs with
21 | [] -&gt; 0
22 | x :: xs' -&gt; x + sum xs'
23
24 (* Quicksort *)
25 let rec qsort = function
26 | [] -&gt; []
27 | pivot :: rest -&gt;
28 let is_less x = x &lt; pivot in
29 let left, right = List.partition is_less rest in
30 qsort left @ [pivot] @ qsort right
31
32 (* Fibonacci Sequence *)
33 let rec fib_aux n a b =
34 match n with
35 | 0 -&gt; a
36 | _ -&gt; fib_aux (n - 1) (a + b) a
37 let fib n = fib_aux n 0 1
38
39 (* Birthday paradox *)
40 let year_size = 365.
41
42 let rec birthday_paradox prob people =
43 let prob' = (year_size -. float people) /. year_size *. prob in
44 if prob' &lt; 0.5 then
45 Printf.printf "answer = %d\n" (people+1)
46 else
47 birthday_paradox prob' (people+1) ;;
48
49 birthday_paradox 1.0 1
50
51 (* Church numerals *)
52 let zero f x = x
53 let succ n f x = f (n f x)
54 let one = succ zero
55 let two = succ (succ zero)
56 let add n1 n2 f x = n1 f (n2 f x)
57 let to_string n = n (fun k -&gt; "S" ^ k) "0"
58 let _ = to_string (add (succ two) two)
59
60 (* Elementary functions *)
61 let square x = x * x;;
62 let rec fact x =
63 if x &lt;= 1 then 1 else x * fact (x - 1);;
64
65 (* Automatic memory management *)
66 let l = 1 :: 2 :: 3 :: [];;
67 [1; 2; 3];;
68 5 :: l;;
69
70 (* Polymorphism: sorting lists *)
71 let rec sort = function
72 | [] -&gt; []
73 | x :: l -&gt; insert x (sort l)
74
75 and insert elem = function
76 | [] -&gt; [elem]
77 | x :: l -&gt;
78 if elem &lt; x then elem :: x :: l else x :: insert elem l;;
79
80 (* Imperative features *)
81 let add_polynom p1 p2 =
82 let n1 = Array.length p1
83 and n2 = Array.length p2 in
84 let result = Array.create (max n1 n2) 0 in
85 for i = 0 to n1 - 1 do result.(i) &lt;- p1.(i) done;
86 for i = 0 to n2 - 1 do result.(i) &lt;- result.(i) + p2.(i) done;
87 result;;
88 add_polynom [| 1; 2 |] [| 1; 2; 3 |];;
89
90 (* We may redefine fact using a reference cell and a for loop *)
91 let fact n =
92 let result = ref 1 in
93 for i = 2 to n do
94 result := i * !result
95 done;
96 !result;;
97 fact 5;;
98
99 (* Triangle (graphics) *)
100 let () =
101 ignore( Glut.init Sys.argv );
102 Glut.initDisplayMode ~double_buffer:true ();
103 ignore (Glut.createWindow ~title:"OpenGL Demo");
104 let angle t = 10. *. t *. t in
105 let render () =
106 GlClear.clear [ `color ];
107 GlMat.load_identity ();
108 GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();
109 GlDraw.begins `triangles;
110 List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];
111 GlDraw.ends ();
112 Glut.swapBuffers () in
113 GlMat.mode `modelview;
114 Glut.displayFunc ~cb:render;
115 Glut.idleFunc ~cb:(Some Glut.postRedisplay);
116 Glut.mainLoop ()
117
118 (* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *)
119 (* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *)
120 </textarea>
121
122 <script>
123 var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
124 mode: 'ocaml',
125 lineNumbers: true,
126 matchBrackets: true
127 });
128 </script>
129
130 <p><strong>MIME types defined:</strong> <code>text/x-ocaml</code>.</p>
@@ -0,0 +1,114 b''
1 CodeMirror.defineMode('ocaml', function(config) {
2
3 var words = {
4 'true': 'atom',
5 'false': 'atom',
6 'let': 'keyword',
7 'rec': 'keyword',
8 'in': 'keyword',
9 'of': 'keyword',
10 'and': 'keyword',
11 'succ': 'keyword',
12 'if': 'keyword',
13 'then': 'keyword',
14 'else': 'keyword',
15 'for': 'keyword',
16 'to': 'keyword',
17 'while': 'keyword',
18 'do': 'keyword',
19 'done': 'keyword',
20 'fun': 'keyword',
21 'function': 'keyword',
22 'val': 'keyword',
23 'type': 'keyword',
24 'mutable': 'keyword',
25 'match': 'keyword',
26 'with': 'keyword',
27 'try': 'keyword',
28 'raise': 'keyword',
29 'begin': 'keyword',
30 'end': 'keyword',
31 'open': 'builtin',
32 'trace': 'builtin',
33 'ignore': 'builtin',
34 'exit': 'builtin',
35 'print_string': 'builtin',
36 'print_endline': 'builtin'
37 };
38
39 function tokenBase(stream, state) {
40 var sol = stream.sol();
41 var ch = stream.next();
42
43 if (ch === '"') {
44 state.tokenize = tokenString;
45 return state.tokenize(stream, state);
46 }
47 if (ch === '(') {
48 if (stream.eat('*')) {
49 state.commentLevel++;
50 state.tokenize = tokenComment;
51 return state.tokenize(stream, state);
52 }
53 }
54 if (ch === '~') {
55 stream.eatWhile(/\w/);
56 return 'variable-2';
57 }
58 if (ch === '`') {
59 stream.eatWhile(/\w/);
60 return 'quote';
61 }
62 if (/\d/.test(ch)) {
63 stream.eatWhile(/[\d]/);
64 if (stream.eat('.')) {
65 stream.eatWhile(/[\d]/);
66 }
67 return 'number';
68 }
69 if ( /[+\-*&%=<>!?|]/.test(ch)) {
70 return 'operator';
71 }
72 stream.eatWhile(/\w/);
73 var cur = stream.current();
74 return words[cur] || 'variable';
75 }
76
77 function tokenString(stream, state) {
78 var next, end = false, escaped = false;
79 while ((next = stream.next()) != null) {
80 if (next === '"' && !escaped) {
81 end = true;
82 break;
83 }
84 escaped = !escaped && next === '\\';
85 }
86 if (end && !escaped) {
87 state.tokenize = tokenBase;
88 }
89 return 'string';
90 };
91
92 function tokenComment(stream, state) {
93 var prev, next;
94 while(state.commentLevel > 0 && (next = stream.next()) != null) {
95 if (prev === '(' && next === '*') state.commentLevel++;
96 if (prev === '*' && next === ')') state.commentLevel--;
97 prev = next;
98 }
99 if (state.commentLevel <= 0) {
100 state.tokenize = tokenBase;
101 }
102 return 'comment';
103 }
104
105 return {
106 startState: function() {return {tokenize: tokenBase, commentLevel: 0}},
107 token: function(stream, state) {
108 if (stream.eatSpace()) return null;
109 return state.tokenize(stream, state);
110 }
111 };
112 });
113
114 CodeMirror.defineMIME('text/x-ocaml', 'ocaml');
@@ -0,0 +1,7 b''
1 Copyright (c) 2011 souceLair <support@sourcelair.com>
2
3 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:
4
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7 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.
@@ -0,0 +1,48 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Pascal mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="pascal.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: Pascal mode</h1>
13
14 <div><textarea id="code" name="code">
15 (* Example Pascal code *)
16
17 while a <> b do writeln('Waiting');
18
19 if a > b then
20 writeln('Condition met')
21 else
22 writeln('Condition not met');
23
24 for i := 1 to 10 do
25 writeln('Iteration: ', i:1);
26
27 repeat
28 a := a + 1
29 until a = 10;
30
31 case i of
32 0: write('zero');
33 1: write('one');
34 2: write('two')
35 end;
36 </textarea></div>
37
38 <script>
39 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
40 lineNumbers: true,
41 matchBrackets: true,
42 mode: "text/x-pascal"
43 });
44 </script>
45
46 <p><strong>MIME types defined:</strong> <code>text/x-pascal</code>.</p>
47 </body>
48 </html>
@@ -0,0 +1,94 b''
1 CodeMirror.defineMode("pascal", function(config) {
2 function words(str) {
3 var obj = {}, words = str.split(" ");
4 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
5 return obj;
6 }
7 var keywords = words("and array begin case const div do downto else end file for forward integer " +
8 "boolean char function goto if in label mod nil not of or packed procedure " +
9 "program record repeat set string then to type until var while with");
10 var atoms = {"null": true};
11
12 var isOperatorChar = /[+\-*&%=<>!?|\/]/;
13
14 function tokenBase(stream, state) {
15 var ch = stream.next();
16 if (ch == "#" && state.startOfLine) {
17 stream.skipToEnd();
18 return "meta";
19 }
20 if (ch == '"' || ch == "'") {
21 state.tokenize = tokenString(ch);
22 return state.tokenize(stream, state);
23 }
24 if (ch == "(" && stream.eat("*")) {
25 state.tokenize = tokenComment;
26 return tokenComment(stream, state);
27 }
28 if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
29 return null
30 }
31 if (/\d/.test(ch)) {
32 stream.eatWhile(/[\w\.]/);
33 return "number";
34 }
35 if (ch == "/") {
36 if (stream.eat("/")) {
37 stream.skipToEnd();
38 return "comment";
39 }
40 }
41 if (isOperatorChar.test(ch)) {
42 stream.eatWhile(isOperatorChar);
43 return "operator";
44 }
45 stream.eatWhile(/[\w\$_]/);
46 var cur = stream.current();
47 if (keywords.propertyIsEnumerable(cur)) return "keyword";
48 if (atoms.propertyIsEnumerable(cur)) return "atom";
49 return "variable";
50 }
51
52 function tokenString(quote) {
53 return function(stream, state) {
54 var escaped = false, next, end = false;
55 while ((next = stream.next()) != null) {
56 if (next == quote && !escaped) {end = true; break;}
57 escaped = !escaped && next == "\\";
58 }
59 if (end || !escaped) state.tokenize = null;
60 return "string";
61 };
62 }
63
64 function tokenComment(stream, state) {
65 var maybeEnd = false, ch;
66 while (ch = stream.next()) {
67 if (ch == ")" && maybeEnd) {
68 state.tokenize = null;
69 break;
70 }
71 maybeEnd = (ch == "*");
72 }
73 return "comment";
74 }
75
76 // Interface
77
78 return {
79 startState: function(basecolumn) {
80 return {tokenize: null};
81 },
82
83 token: function(stream, state) {
84 if (stream.eatSpace()) return null;
85 var style = (state.tokenize || tokenBase)(stream, state);
86 if (style == "comment" || style == "meta") return style;
87 return style;
88 },
89
90 electricChars: "{}"
91 };
92 });
93
94 CodeMirror.defineMIME("text/x-pascal", "pascal");
@@ -0,0 +1,19 b''
1 Copyright (C) 2011 by Sabaca <mail@sabaca.com> under the MIT license.
2
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
5 in the Software without restriction, including without limitation the rights
6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 copies of the Software, and to permit persons to whom the Software is
8 furnished to do so, subject to the following conditions:
9
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 THE SOFTWARE.
@@ -0,0 +1,62 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: Perl mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="perl.js"></script>
8 <link rel="stylesheet" href="../../doc/docs.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 </head>
11 <body>
12 <h1>CodeMirror: Perl mode</h1>
13
14 <div><textarea id="code" name="code">
15 #!/usr/bin/perl
16
17 use Something qw(func1 func2);
18
19 # strings
20 my $s1 = qq'single line';
21 our $s2 = q(multi-
22 line);
23
24 =item Something
25 Example.
26 =cut
27
28 my $html=<<'HTML'
29 <html>
30 <title>hi!</title>
31 </html>
32 HTML
33
34 print "first,".join(',', 'second', qq~third~);
35
36 if($s1 =~ m[(?<!\s)(l.ne)\z]o) {
37 $h->{$1}=$$.' predefined variables';
38 $s2 =~ s/\-line//ox;
39 $s1 =~ s[
40 line ]
41 [
42 block
43 ]ox;
44 }
45
46 1; # numbers and comments
47
48 __END__
49 something...
50
51 </textarea></div>
52
53 <script>
54 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
55 lineNumbers: true,
56 matchBrackets: true
57 });
58 </script>
59
60 <p><strong>MIME types defined:</strong> <code>text/x-perl</code>.</p>
61 </body>
62 </html>
This diff has been collapsed as it changes many lines, (816 lines changed) Show them Hide them
@@ -0,0 +1,816 b''
1 // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
2 // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
3 CodeMirror.defineMode("perl",function(config,parserConfig){
4 // http://perldoc.perl.org
5 var PERL={ // null - magic touch
6 // 1 - keyword
7 // 2 - def
8 // 3 - atom
9 // 4 - operator
10 // 5 - variable-2 (predefined)
11 // [x,y] - x=1,2,3; y=must be defined if x{...}
12 // PERL operators
13 '->' : 4,
14 '++' : 4,
15 '--' : 4,
16 '**' : 4,
17 // ! ~ \ and unary + and -
18 '=~' : 4,
19 '!~' : 4,
20 '*' : 4,
21 '/' : 4,
22 '%' : 4,
23 'x' : 4,
24 '+' : 4,
25 '-' : 4,
26 '.' : 4,
27 '<<' : 4,
28 '>>' : 4,
29 // named unary operators
30 '<' : 4,
31 '>' : 4,
32 '<=' : 4,
33 '>=' : 4,
34 'lt' : 4,
35 'gt' : 4,
36 'le' : 4,
37 'ge' : 4,
38 '==' : 4,
39 '!=' : 4,
40 '<=>' : 4,
41 'eq' : 4,
42 'ne' : 4,
43 'cmp' : 4,
44 '~~' : 4,
45 '&' : 4,
46 '|' : 4,
47 '^' : 4,
48 '&&' : 4,
49 '||' : 4,
50 '//' : 4,
51 '..' : 4,
52 '...' : 4,
53 '?' : 4,
54 ':' : 4,
55 '=' : 4,
56 '+=' : 4,
57 '-=' : 4,
58 '*=' : 4, // etc. ???
59 ',' : 4,
60 '=>' : 4,
61 '::' : 4,
62 // list operators (rightward)
63 'not' : 4,
64 'and' : 4,
65 'or' : 4,
66 'xor' : 4,
67 // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
68 'BEGIN' : [5,1],
69 'END' : [5,1],
70 'PRINT' : [5,1],
71 'PRINTF' : [5,1],
72 'GETC' : [5,1],
73 'READ' : [5,1],
74 'READLINE' : [5,1],
75 'DESTROY' : [5,1],
76 'TIE' : [5,1],
77 'TIEHANDLE' : [5,1],
78 'UNTIE' : [5,1],
79 'STDIN' : 5,
80 'STDIN_TOP' : 5,
81 'STDOUT' : 5,
82 'STDOUT_TOP' : 5,
83 'STDERR' : 5,
84 'STDERR_TOP' : 5,
85 '$ARG' : 5,
86 '$_' : 5,
87 '@ARG' : 5,
88 '@_' : 5,
89 '$LIST_SEPARATOR' : 5,
90 '$"' : 5,
91 '$PROCESS_ID' : 5,
92 '$PID' : 5,
93 '$$' : 5,
94 '$REAL_GROUP_ID' : 5,
95 '$GID' : 5,
96 '$(' : 5,
97 '$EFFECTIVE_GROUP_ID' : 5,
98 '$EGID' : 5,
99 '$)' : 5,
100 '$PROGRAM_NAME' : 5,
101 '$0' : 5,
102 '$SUBSCRIPT_SEPARATOR' : 5,
103 '$SUBSEP' : 5,
104 '$;' : 5,
105 '$REAL_USER_ID' : 5,
106 '$UID' : 5,
107 '$<' : 5,
108 '$EFFECTIVE_USER_ID' : 5,
109 '$EUID' : 5,
110 '$>' : 5,
111 '$a' : 5,
112 '$b' : 5,
113 '$COMPILING' : 5,
114 '$^C' : 5,
115 '$DEBUGGING' : 5,
116 '$^D' : 5,
117 '${^ENCODING}' : 5,
118 '$ENV' : 5,
119 '%ENV' : 5,
120 '$SYSTEM_FD_MAX' : 5,
121 '$^F' : 5,
122 '@F' : 5,
123 '${^GLOBAL_PHASE}' : 5,
124 '$^H' : 5,
125 '%^H' : 5,
126 '@INC' : 5,
127 '%INC' : 5,
128 '$INPLACE_EDIT' : 5,
129 '$^I' : 5,
130 '$^M' : 5,
131 '$OSNAME' : 5,
132 '$^O' : 5,
133 '${^OPEN}' : 5,
134 '$PERLDB' : 5,
135 '$^P' : 5,
136 '$SIG' : 5,
137 '%SIG' : 5,
138 '$BASETIME' : 5,
139 '$^T' : 5,
140 '${^TAINT}' : 5,
141 '${^UNICODE}' : 5,
142 '${^UTF8CACHE}' : 5,
143 '${^UTF8LOCALE}' : 5,
144 '$PERL_VERSION' : 5,
145 '$^V' : 5,
146 '${^WIN32_SLOPPY_STAT}' : 5,
147 '$EXECUTABLE_NAME' : 5,
148 '$^X' : 5,
149 '$1' : 5, // - regexp $1, $2...
150 '$MATCH' : 5,
151 '$&' : 5,
152 '${^MATCH}' : 5,
153 '$PREMATCH' : 5,
154 '$`' : 5,
155 '${^PREMATCH}' : 5,
156 '$POSTMATCH' : 5,
157 "$'" : 5,
158 '${^POSTMATCH}' : 5,
159 '$LAST_PAREN_MATCH' : 5,
160 '$+' : 5,
161 '$LAST_SUBMATCH_RESULT' : 5,
162 '$^N' : 5,
163 '@LAST_MATCH_END' : 5,
164 '@+' : 5,
165 '%LAST_PAREN_MATCH' : 5,
166 '%+' : 5,
167 '@LAST_MATCH_START' : 5,
168 '@-' : 5,
169 '%LAST_MATCH_START' : 5,
170 '%-' : 5,
171 '$LAST_REGEXP_CODE_RESULT' : 5,
172 '$^R' : 5,
173 '${^RE_DEBUG_FLAGS}' : 5,
174 '${^RE_TRIE_MAXBUF}' : 5,
175 '$ARGV' : 5,
176 '@ARGV' : 5,
177 'ARGV' : 5,
178 'ARGVOUT' : 5,
179 '$OUTPUT_FIELD_SEPARATOR' : 5,
180 '$OFS' : 5,
181 '$,' : 5,
182 '$INPUT_LINE_NUMBER' : 5,
183 '$NR' : 5,
184 '$.' : 5,
185 '$INPUT_RECORD_SEPARATOR' : 5,
186 '$RS' : 5,
187 '$/' : 5,
188 '$OUTPUT_RECORD_SEPARATOR' : 5,
189 '$ORS' : 5,
190 '$\\' : 5,
191 '$OUTPUT_AUTOFLUSH' : 5,
192 '$|' : 5,
193 '$ACCUMULATOR' : 5,
194 '$^A' : 5,
195 '$FORMAT_FORMFEED' : 5,
196 '$^L' : 5,
197 '$FORMAT_PAGE_NUMBER' : 5,
198 '$%' : 5,
199 '$FORMAT_LINES_LEFT' : 5,
200 '$-' : 5,
201 '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
202 '$:' : 5,
203 '$FORMAT_LINES_PER_PAGE' : 5,
204 '$=' : 5,
205 '$FORMAT_TOP_NAME' : 5,
206 '$^' : 5,
207 '$FORMAT_NAME' : 5,
208 '$~' : 5,
209 '${^CHILD_ERROR_NATIVE}' : 5,
210 '$EXTENDED_OS_ERROR' : 5,
211 '$^E' : 5,
212 '$EXCEPTIONS_BEING_CAUGHT' : 5,
213 '$^S' : 5,
214 '$WARNING' : 5,
215 '$^W' : 5,
216 '${^WARNING_BITS}' : 5,
217 '$OS_ERROR' : 5,
218 '$ERRNO' : 5,
219 '$!' : 5,
220 '%OS_ERROR' : 5,
221 '%ERRNO' : 5,
222 '%!' : 5,
223 '$CHILD_ERROR' : 5,
224 '$?' : 5,
225 '$EVAL_ERROR' : 5,
226 '$@' : 5,
227 '$OFMT' : 5,
228 '$#' : 5,
229 '$*' : 5,
230 '$ARRAY_BASE' : 5,
231 '$[' : 5,
232 '$OLD_PERL_VERSION' : 5,
233 '$]' : 5,
234 // PERL blocks
235 'if' :[1,1],
236 elsif :[1,1],
237 'else' :[1,1],
238 'while' :[1,1],
239 unless :[1,1],
240 'for' :[1,1],
241 foreach :[1,1],
242 // PERL functions
243 'abs' :1, // - absolute value function
244 accept :1, // - accept an incoming socket connect
245 alarm :1, // - schedule a SIGALRM
246 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
247 bind :1, // - binds an address to a socket
248 binmode :1, // - prepare binary files for I/O
249 bless :1, // - create an object
250 bootstrap :1, //
251 'break' :1, // - break out of a "given" block
252 caller :1, // - get context of the current subroutine call
253 chdir :1, // - change your current working directory
254 chmod :1, // - changes the permissions on a list of files
255 chomp :1, // - remove a trailing record separator from a string
256 chop :1, // - remove the last character from a string
257 chown :1, // - change the owership on a list of files
258 chr :1, // - get character this number represents
259 chroot :1, // - make directory new root for path lookups
260 close :1, // - close file (or pipe or socket) handle
261 closedir :1, // - close directory handle
262 connect :1, // - connect to a remote socket
263 'continue' :[1,1], // - optional trailing block in a while or foreach
264 'cos' :1, // - cosine function
265 crypt :1, // - one-way passwd-style encryption
266 dbmclose :1, // - breaks binding on a tied dbm file
267 dbmopen :1, // - create binding on a tied dbm file
268 'default' :1, //
269 defined :1, // - test whether a value, variable, or function is defined
270 'delete' :1, // - deletes a value from a hash
271 die :1, // - raise an exception or bail out
272 'do' :1, // - turn a BLOCK into a TERM
273 dump :1, // - create an immediate core dump
274 each :1, // - retrieve the next key/value pair from a hash
275 endgrent :1, // - be done using group file
276 endhostent :1, // - be done using hosts file
277 endnetent :1, // - be done using networks file
278 endprotoent :1, // - be done using protocols file
279 endpwent :1, // - be done using passwd file
280 endservent :1, // - be done using services file
281 eof :1, // - test a filehandle for its end
282 'eval' :1, // - catch exceptions or compile and run code
283 'exec' :1, // - abandon this program to run another
284 exists :1, // - test whether a hash key is present
285 exit :1, // - terminate this program
286 'exp' :1, // - raise I to a power
287 fcntl :1, // - file control system call
288 fileno :1, // - return file descriptor from filehandle
289 flock :1, // - lock an entire file with an advisory lock
290 fork :1, // - create a new process just like this one
291 format :1, // - declare a picture format with use by the write() function
292 formline :1, // - internal function used for formats
293 getc :1, // - get the next character from the filehandle
294 getgrent :1, // - get next group record
295 getgrgid :1, // - get group record given group user ID
296 getgrnam :1, // - get group record given group name
297 gethostbyaddr :1, // - get host record given its address
298 gethostbyname :1, // - get host record given name
299 gethostent :1, // - get next hosts record
300 getlogin :1, // - return who logged in at this tty
301 getnetbyaddr :1, // - get network record given its address
302 getnetbyname :1, // - get networks record given name
303 getnetent :1, // - get next networks record
304 getpeername :1, // - find the other end of a socket connection
305 getpgrp :1, // - get process group
306 getppid :1, // - get parent process ID
307 getpriority :1, // - get current nice value
308 getprotobyname :1, // - get protocol record given name
309 getprotobynumber :1, // - get protocol record numeric protocol
310 getprotoent :1, // - get next protocols record
311 getpwent :1, // - get next passwd record
312 getpwnam :1, // - get passwd record given user login name
313 getpwuid :1, // - get passwd record given user ID
314 getservbyname :1, // - get services record given its name
315 getservbyport :1, // - get services record given numeric port
316 getservent :1, // - get next services record
317 getsockname :1, // - retrieve the sockaddr for a given socket
318 getsockopt :1, // - get socket options on a given socket
319 given :1, //
320 glob :1, // - expand filenames using wildcards
321 gmtime :1, // - convert UNIX time into record or string using Greenwich time
322 'goto' :1, // - create spaghetti code
323 grep :1, // - locate elements in a list test true against a given criterion
324 hex :1, // - convert a string to a hexadecimal number
325 'import' :1, // - patch a module's namespace into your own
326 index :1, // - find a substring within a string
327 'int' :1, // - get the integer portion of a number
328 ioctl :1, // - system-dependent device control system call
329 'join' :1, // - join a list into a string using a separator
330 keys :1, // - retrieve list of indices from a hash
331 kill :1, // - send a signal to a process or process group
332 last :1, // - exit a block prematurely
333 lc :1, // - return lower-case version of a string
334 lcfirst :1, // - return a string with just the next letter in lower case
335 length :1, // - return the number of bytes in a string
336 'link' :1, // - create a hard link in the filesytem
337 listen :1, // - register your socket as a server
338 local : 2, // - create a temporary value for a global variable (dynamic scoping)
339 localtime :1, // - convert UNIX time into record or string using local time
340 lock :1, // - get a thread lock on a variable, subroutine, or method
341 'log' :1, // - retrieve the natural logarithm for a number
342 lstat :1, // - stat a symbolic link
343 m :null, // - match a string with a regular expression pattern
344 map :1, // - apply a change to a list to get back a new list with the changes
345 mkdir :1, // - create a directory
346 msgctl :1, // - SysV IPC message control operations
347 msgget :1, // - get SysV IPC message queue
348 msgrcv :1, // - receive a SysV IPC message from a message queue
349 msgsnd :1, // - send a SysV IPC message to a message queue
350 my : 2, // - declare and assign a local variable (lexical scoping)
351 'new' :1, //
352 next :1, // - iterate a block prematurely
353 no :1, // - unimport some module symbols or semantics at compile time
354 oct :1, // - convert a string to an octal number
355 open :1, // - open a file, pipe, or descriptor
356 opendir :1, // - open a directory
357 ord :1, // - find a character's numeric representation
358 our : 2, // - declare and assign a package variable (lexical scoping)
359 pack :1, // - convert a list into a binary representation
360 'package' :1, // - declare a separate global namespace
361 pipe :1, // - open a pair of connected filehandles
362 pop :1, // - remove the last element from an array and return it
363 pos :1, // - find or set the offset for the last/next m//g search
364 print :1, // - output a list to a filehandle
365 printf :1, // - output a formatted list to a filehandle
366 prototype :1, // - get the prototype (if any) of a subroutine
367 push :1, // - append one or more elements to an array
368 q :null, // - singly quote a string
369 qq :null, // - doubly quote a string
370 qr :null, // - Compile pattern
371 quotemeta :null, // - quote regular expression magic characters
372 qw :null, // - quote a list of words
373 qx :null, // - backquote quote a string
374 rand :1, // - retrieve the next pseudorandom number
375 read :1, // - fixed-length buffered input from a filehandle
376 readdir :1, // - get a directory from a directory handle
377 readline :1, // - fetch a record from a file
378 readlink :1, // - determine where a symbolic link is pointing
379 readpipe :1, // - execute a system command and collect standard output
380 recv :1, // - receive a message over a Socket
381 redo :1, // - start this loop iteration over again
382 ref :1, // - find out the type of thing being referenced
383 rename :1, // - change a filename
384 require :1, // - load in external functions from a library at runtime
385 reset :1, // - clear all variables of a given name
386 'return' :1, // - get out of a function early
387 reverse :1, // - flip a string or a list
388 rewinddir :1, // - reset directory handle
389 rindex :1, // - right-to-left substring search
390 rmdir :1, // - remove a directory
391 s :null, // - replace a pattern with a string
392 say :1, // - print with newline
393 scalar :1, // - force a scalar context
394 seek :1, // - reposition file pointer for random-access I/O
395 seekdir :1, // - reposition directory pointer
396 select :1, // - reset default output or do I/O multiplexing
397 semctl :1, // - SysV semaphore control operations
398 semget :1, // - get set of SysV semaphores
399 semop :1, // - SysV semaphore operations
400 send :1, // - send a message over a socket
401 setgrent :1, // - prepare group file for use
402 sethostent :1, // - prepare hosts file for use
403 setnetent :1, // - prepare networks file for use
404 setpgrp :1, // - set the process group of a process
405 setpriority :1, // - set a process's nice value
406 setprotoent :1, // - prepare protocols file for use
407 setpwent :1, // - prepare passwd file for use
408 setservent :1, // - prepare services file for use
409 setsockopt :1, // - set some socket options
410 shift :1, // - remove the first element of an array, and return it
411 shmctl :1, // - SysV shared memory operations
412 shmget :1, // - get SysV shared memory segment identifier
413 shmread :1, // - read SysV shared memory
414 shmwrite :1, // - write SysV shared memory
415 shutdown :1, // - close down just half of a socket connection
416 'sin' :1, // - return the sine of a number
417 sleep :1, // - block for some number of seconds
418 socket :1, // - create a socket
419 socketpair :1, // - create a pair of sockets
420 'sort' :1, // - sort a list of values
421 splice :1, // - add or remove elements anywhere in an array
422 'split' :1, // - split up a string using a regexp delimiter
423 sprintf :1, // - formatted print into a string
424 'sqrt' :1, // - square root function
425 srand :1, // - seed the random number generator
426 stat :1, // - get a file's status information
427 state :1, // - declare and assign a state variable (persistent lexical scoping)
428 study :1, // - optimize input data for repeated searches
429 'sub' :1, // - declare a subroutine, possibly anonymously
430 'substr' :1, // - get or alter a portion of a stirng
431 symlink :1, // - create a symbolic link to a file
432 syscall :1, // - execute an arbitrary system call
433 sysopen :1, // - open a file, pipe, or descriptor
434 sysread :1, // - fixed-length unbuffered input from a filehandle
435 sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
436 system :1, // - run a separate program
437 syswrite :1, // - fixed-length unbuffered output to a filehandle
438 tell :1, // - get current seekpointer on a filehandle
439 telldir :1, // - get current seekpointer on a directory handle
440 tie :1, // - bind a variable to an object class
441 tied :1, // - get a reference to the object underlying a tied variable
442 time :1, // - return number of seconds since 1970
443 times :1, // - return elapsed time for self and child processes
444 tr :null, // - transliterate a string
445 truncate :1, // - shorten a file
446 uc :1, // - return upper-case version of a string
447 ucfirst :1, // - return a string with just the next letter in upper case
448 umask :1, // - set file creation mode mask
449 undef :1, // - remove a variable or function definition
450 unlink :1, // - remove one link to a file
451 unpack :1, // - convert binary structure into normal perl variables
452 unshift :1, // - prepend more elements to the beginning of a list
453 untie :1, // - break a tie binding to a variable
454 use :1, // - load in a module at compile time
455 utime :1, // - set a file's last access and modify times
456 values :1, // - return a list of the values in a hash
457 vec :1, // - test or set particular bits in a string
458 wait :1, // - wait for any child process to die
459 waitpid :1, // - wait for a particular child process to die
460 wantarray :1, // - get void vs scalar vs list context of current subroutine call
461 warn :1, // - print debugging info
462 when :1, //
463 write :1, // - print a picture record
464 y :null}; // - transliterate a string
465
466 var RXstyle="string-2";
467 var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
468
469 function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
470 state.chain=null; // 12 3tail
471 state.style=null;
472 state.tail=null;
473 state.tokenize=function(stream,state){
474 var e=false,c,i=0;
475 while(c=stream.next()){
476 if(c===chain[i]&&!e){
477 if(chain[++i]!==undefined){
478 state.chain=chain[i];
479 state.style=style;
480 state.tail=tail}
481 else if(tail)
482 stream.eatWhile(tail);
483 state.tokenize=tokenPerl;
484 return style}
485 e=!e&&c=="\\"}
486 return style};
487 return state.tokenize(stream,state)}
488
489 function tokenSOMETHING(stream,state,string){
490 state.tokenize=function(stream,state){
491 if(stream.string==string)
492 state.tokenize=tokenPerl;
493 stream.skipToEnd();
494 return "string"};
495 return state.tokenize(stream,state)}
496
497 function tokenPerl(stream,state){
498 if(stream.eatSpace())
499 return null;
500 if(state.chain)
501 return tokenChain(stream,state,state.chain,state.style,state.tail);
502 if(stream.match(/^\-?[\d\.]/,false))
503 if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
504 return 'number';
505 if(stream.match(/^<<(?=\w)/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n
506 stream.eatWhile(/\w/);
507 return tokenSOMETHING(stream,state,stream.current().substr(2))}
508 if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n
509 return tokenSOMETHING(stream,state,'=cut')}
510 var ch=stream.next();
511 if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
512 if(stream.prefix(3)=="<<"+ch){
513 var p=stream.pos;
514 stream.eatWhile(/\w/);
515 var n=stream.current().substr(1);
516 if(n&&stream.eat(ch))
517 return tokenSOMETHING(stream,state,n);
518 stream.pos=p}
519 return tokenChain(stream,state,[ch],"string")}
520 if(ch=="q"){
521 var c=stream.look(-2);
522 if(!(c&&/\w/.test(c))){
523 c=stream.look(0);
524 if(c=="x"){
525 c=stream.look(1);
526 if(c=="("){
527 stream.eatSuffix(2);
528 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
529 if(c=="["){
530 stream.eatSuffix(2);
531 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
532 if(c=="{"){
533 stream.eatSuffix(2);
534 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
535 if(c=="<"){
536 stream.eatSuffix(2);
537 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}
538 if(/[\^'"!~\/]/.test(c)){
539 stream.eatSuffix(1);
540 return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers)}}
541 else if(c=="q"){
542 c=stream.look(1);
543 if(c=="("){
544 stream.eatSuffix(2);
545 return tokenChain(stream,state,[")"],"string")}
546 if(c=="["){
547 stream.eatSuffix(2);
548 return tokenChain(stream,state,["]"],"string")}
549 if(c=="{"){
550 stream.eatSuffix(2);
551 return tokenChain(stream,state,["}"],"string")}
552 if(c=="<"){
553 stream.eatSuffix(2);
554 return tokenChain(stream,state,[">"],"string")}
555 if(/[\^'"!~\/]/.test(c)){
556 stream.eatSuffix(1);
557 return tokenChain(stream,state,[stream.eat(c)],"string")}}
558 else if(c=="w"){
559 c=stream.look(1);
560 if(c=="("){
561 stream.eatSuffix(2);
562 return tokenChain(stream,state,[")"],"bracket")}
563 if(c=="["){
564 stream.eatSuffix(2);
565 return tokenChain(stream,state,["]"],"bracket")}
566 if(c=="{"){
567 stream.eatSuffix(2);
568 return tokenChain(stream,state,["}"],"bracket")}
569 if(c=="<"){
570 stream.eatSuffix(2);
571 return tokenChain(stream,state,[">"],"bracket")}
572 if(/[\^'"!~\/]/.test(c)){
573 stream.eatSuffix(1);
574 return tokenChain(stream,state,[stream.eat(c)],"bracket")}}
575 else if(c=="r"){
576 c=stream.look(1);
577 if(c=="("){
578 stream.eatSuffix(2);
579 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
580 if(c=="["){
581 stream.eatSuffix(2);
582 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
583 if(c=="{"){
584 stream.eatSuffix(2);
585 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
586 if(c=="<"){
587 stream.eatSuffix(2);
588 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}
589 if(/[\^'"!~\/]/.test(c)){
590 stream.eatSuffix(1);
591 return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers)}}
592 else if(/[\^'"!~\/(\[{<]/.test(c)){
593 if(c=="("){
594 stream.eatSuffix(1);
595 return tokenChain(stream,state,[")"],"string")}
596 if(c=="["){
597 stream.eatSuffix(1);
598 return tokenChain(stream,state,["]"],"string")}
599 if(c=="{"){
600 stream.eatSuffix(1);
601 return tokenChain(stream,state,["}"],"string")}
602 if(c=="<"){
603 stream.eatSuffix(1);
604 return tokenChain(stream,state,[">"],"string")}
605 if(/[\^'"!~\/]/.test(c)){
606 return tokenChain(stream,state,[stream.eat(c)],"string")}}}}
607 if(ch=="m"){
608 var c=stream.look(-2);
609 if(!(c&&/\w/.test(c))){
610 c=stream.eat(/[(\[{<\^'"!~\/]/);
611 if(c){
612 if(/[\^'"!~\/]/.test(c)){
613 return tokenChain(stream,state,[c],RXstyle,RXmodifiers)}
614 if(c=="("){
615 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers)}
616 if(c=="["){
617 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers)}
618 if(c=="{"){
619 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers)}
620 if(c=="<"){
621 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers)}}}}
622 if(ch=="s"){
623 var c=/[\/>\]})\w]/.test(stream.look(-2));
624 if(!c){
625 c=stream.eat(/[(\[{<\^'"!~\/]/);
626 if(c){
627 if(c=="[")
628 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
629 if(c=="{")
630 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
631 if(c=="<")
632 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
633 if(c=="(")
634 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
635 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}
636 if(ch=="y"){
637 var c=/[\/>\]})\w]/.test(stream.look(-2));
638 if(!c){
639 c=stream.eat(/[(\[{<\^'"!~\/]/);
640 if(c){
641 if(c=="[")
642 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
643 if(c=="{")
644 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
645 if(c=="<")
646 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
647 if(c=="(")
648 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
649 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}
650 if(ch=="t"){
651 var c=/[\/>\]})\w]/.test(stream.look(-2));
652 if(!c){
653 c=stream.eat("r");if(c){
654 c=stream.eat(/[(\[{<\^'"!~\/]/);
655 if(c){
656 if(c=="[")
657 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
658 if(c=="{")
659 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
660 if(c=="<")
661 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
662 if(c=="(")
663 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
664 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers)}}}}
665 if(ch=="`"){
666 return tokenChain(stream,state,[ch],"variable-2")}
667 if(ch=="/"){
668 if(!/~\s*$/.test(stream.prefix()))
669 return "operator";
670 else
671 return tokenChain(stream,state,[ch],RXstyle,RXmodifiers)}
672 if(ch=="$"){
673 var p=stream.pos;
674 if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
675 return "variable-2";
676 else
677 stream.pos=p}
678 if(/[$@%]/.test(ch)){
679 var p=stream.pos;
680 if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
681 var c=stream.current();
682 if(PERL[c])
683 return "variable-2"}
684 stream.pos=p}
685 if(/[$@%&]/.test(ch)){
686 if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
687 var c=stream.current();
688 if(PERL[c])
689 return "variable-2";
690 else
691 return "variable"}}
692 if(ch=="#"){
693 if(stream.look(-2)!="$"){
694 stream.skipToEnd();
695 return "comment"}}
696 if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
697 var p=stream.pos;
698 stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
699 if(PERL[stream.current()])
700 return "operator";
701 else
702 stream.pos=p}
703 if(ch=="_"){
704 if(stream.pos==1){
705 if(stream.suffix(6)=="_END__"){
706 return tokenChain(stream,state,['\0'],"comment")}
707 else if(stream.suffix(7)=="_DATA__"){
708 return tokenChain(stream,state,['\0'],"variable-2")}
709 else if(stream.suffix(7)=="_C__"){
710 return tokenChain(stream,state,['\0'],"string")}}}
711 if(/\w/.test(ch)){
712 var p=stream.pos;
713 if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
714 return "string";
715 else
716 stream.pos=p}
717 if(/[A-Z]/.test(ch)){
718 var l=stream.look(-2);
719 var p=stream.pos;
720 stream.eatWhile(/[A-Z_]/);
721 if(/[\da-z]/.test(stream.look(0))){
722 stream.pos=p}
723 else{
724 var c=PERL[stream.current()];
725 if(!c)
726 return "meta";
727 if(c[1])
728 c=c[0];
729 if(l!=":"){
730 if(c==1)
731 return "keyword";
732 else if(c==2)
733 return "def";
734 else if(c==3)
735 return "atom";
736 else if(c==4)
737 return "operator";
738 else if(c==5)
739 return "variable-2";
740 else
741 return "meta"}
742 else
743 return "meta"}}
744 if(/[a-zA-Z_]/.test(ch)){
745 var l=stream.look(-2);
746 stream.eatWhile(/\w/);
747 var c=PERL[stream.current()];
748 if(!c)
749 return "meta";
750 if(c[1])
751 c=c[0];
752 if(l!=":"){
753 if(c==1)
754 return "keyword";
755 else if(c==2)
756 return "def";
757 else if(c==3)
758 return "atom";
759 else if(c==4)
760 return "operator";
761 else if(c==5)
762 return "variable-2";
763 else
764 return "meta"}
765 else
766 return "meta"}
767 return null}
768
769 return{
770 startState:function(){
771 return{
772 tokenize:tokenPerl,
773 chain:null,
774 style:null,
775 tail:null}},
776 token:function(stream,state){
777 return (state.tokenize||tokenPerl)(stream,state)},
778 electricChars:"{}"}});
779
780 CodeMirror.defineMIME("text/x-perl", "perl");
781
782 // it's like "peek", but need for look-ahead or look-behind if index < 0
783 CodeMirror.StringStream.prototype.look=function(c){
784 return this.string.charAt(this.pos+(c||0))};
785
786 // return a part of prefix of current stream from current position
787 CodeMirror.StringStream.prototype.prefix=function(c){
788 if(c){
789 var x=this.pos-c;
790 return this.string.substr((x>=0?x:0),c)}
791 else{
792 return this.string.substr(0,this.pos-1)}};
793
794 // return a part of suffix of current stream from current position
795 CodeMirror.StringStream.prototype.suffix=function(c){
796 var y=this.string.length;
797 var x=y-this.pos+1;
798 return this.string.substr(this.pos,(c&&c<y?c:x))};
799
800 // return a part of suffix of current stream from current position and change current position
801 CodeMirror.StringStream.prototype.nsuffix=function(c){
802 var p=this.pos;
803 var l=c||(this.string.length-this.pos+1);
804 this.pos+=l;
805 return this.string.substr(p,l)};
806
807 // eating and vomiting a part of stream from current position
808 CodeMirror.StringStream.prototype.eatSuffix=function(c){
809 var x=this.pos+c;
810 var y;
811 if(x<=0)
812 this.pos=0;
813 else if(x>=(y=this.string.length-1))
814 this.pos=y;
815 else
816 this.pos=x};
@@ -0,0 +1,48 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror: PHP mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="../xml/xml.js"></script>
8 <script src="../javascript/javascript.js"></script>
9 <script src="../css/css.js"></script>
10 <script src="../clike/clike.js"></script>
11 <script src="php.js"></script>
12 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
13 <link rel="stylesheet" href="../../doc/docs.css">
14 </head>
15 <body>
16 <h1>CodeMirror: PHP mode</h1>
17
18 <form><textarea id="code" name="code">
19 <?php
20 function hello($who) {
21 return "Hello " . $who;
22 }
23 ?>
24 <p>The program says <?= hello("World") ?>.</p>
25 <script>
26 alert("And here is some JS code"); // also colored
27 </script>
28 </textarea></form>
29
30 <script>
31 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
32 lineNumbers: true,
33 matchBrackets: true,
34 mode: "application/x-httpd-php",
35 indentUnit: 4,
36 indentWithTabs: true,
37 enterMode: "keep",
38 tabMode: "shift"
39 });
40 </script>
41
42 <p>Simple HTML/PHP mode based on
43 the <a href="../clike/">C-like</a> mode. Depends on XML,
44 JavaScript, CSS, and C-like modes.</p>
45
46 <p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>
47 </body>
48 </html>
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,4 +1,4 b''
1 Copyright (C) 2011 by Marijn Haverbeke <marijnh@gmail.com>
1 Copyright (C) 2012 by Marijn Haverbeke <marijnh@gmail.com>
2
2
3 Permission is hereby granted, free of charge, to any person obtaining a copy
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
4 of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,8 b''
1 # CodeMirror 2
1 # CodeMirror 2
2
2
3 CodeMirror 2 is a rewrite of [CodeMirror
3 CodeMirror is a JavaScript component that provides a code editor in
4 1](http://github.com/marijnh/CodeMirror). The docs live
4 the browser. When a mode is available for the language you are coding
5 [here](http://codemirror.net/doc/manual.html), and the project page is
5 in, it will color your code, and optionally help with indentation.
6 [http://codemirror.net/](http://codemirror.net/).
6
7 The project page is http://codemirror.net
8 The manual is at http://codemirror.net/doc/manual.html
@@ -1,14 +1,52 b''
1 .CodeMirror {
1 .CodeMirror {
2 line-height: 1em;
2 line-height: 1em;
3 font-family: monospace;
3 font-family: monospace;
4
5 /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
6 position: relative;
7 /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
8 overflow: hidden;
4 }
9 }
5
10
6 .CodeMirror-scroll {
11 .CodeMirror-scroll {
7 overflow: auto;
12 overflow-x: auto;
13 overflow-y: hidden;
8 height: 300px;
14 height: 300px;
9 /* This is needed to prevent an IE[67] bug where the scrolled content
15 /* This is needed to prevent an IE[67] bug where the scrolled content
10 is visible outside of the scrolling box. */
16 is visible outside of the scrolling box. */
11 position: relative;
17 position: relative;
18 outline: none;
19 }
20
21 /* Vertical scrollbar */
22 .CodeMirror-scrollbar {
23 float: right;
24 overflow-x: hidden;
25 overflow-y: scroll;
26
27 /* This corrects for the 1px gap introduced to the left of the scrollbar
28 by the rule for .CodeMirror-scrollbar-inner. */
29 margin-left: -1px;
30 }
31 .CodeMirror-scrollbar-inner {
32 /* This needs to have a nonzero width in order for the scrollbar to appear
33 in Firefox and IE9. */
34 width: 1px;
35 }
36 .CodeMirror-scrollbar.cm-sb-overlap {
37 /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
38 rather than sitting to the right of it. */
39 position: absolute;
40 z-index: 1;
41 float: none;
42 right: 0;
43 min-width: 12px;
44 }
45 .CodeMirror-scrollbar.cm-sb-nonoverlap {
46 min-width: 12px;
47 }
48 .CodeMirror-scrollbar.cm-sb-ie7 {
49 min-width: 18px;
12 }
50 }
13
51
14 .CodeMirror-gutter {
52 .CodeMirror-gutter {
@@ -24,9 +62,16 b''
24 text-align: right;
62 text-align: right;
25 padding: .4em .2em .4em .4em;
63 padding: .4em .2em .4em .4em;
26 white-space: pre !important;
64 white-space: pre !important;
65 cursor: default;
27 }
66 }
28 .CodeMirror-lines {
67 .CodeMirror-lines {
29 padding: .4em;
68 padding: .4em;
69 white-space: pre;
70 cursor: text;
71 }
72 .CodeMirror-lines * {
73 /* Necessary for throw-scrolling to decelerate properly on Safari. */
74 pointer-events: none;
30 }
75 }
31
76
32 .CodeMirror pre {
77 .CodeMirror pre {
@@ -40,11 +85,14 b''
40 padding: 0; margin: 0;
85 padding: 0; margin: 0;
41 white-space: pre;
86 white-space: pre;
42 word-wrap: normal;
87 word-wrap: normal;
88 line-height: inherit;
89 color: inherit;
43 }
90 }
44
91
45 .CodeMirror-wrap pre {
92 .CodeMirror-wrap pre {
46 word-wrap: break-word;
93 word-wrap: break-word;
47 white-space: pre-wrap;
94 white-space: pre-wrap;
95 word-break: normal;
48 }
96 }
49 .CodeMirror-wrap .CodeMirror-scroll {
97 .CodeMirror-wrap .CodeMirror-scroll {
50 overflow-x: hidden;
98 overflow-x: hidden;
@@ -59,7 +107,21 b''
59 position: absolute;
107 position: absolute;
60 visibility: hidden;
108 visibility: hidden;
61 border-left: 1px solid black;
109 border-left: 1px solid black;
110 border-right: none;
111 width: 0;
112 }
113 .cm-keymap-fat-cursor pre.CodeMirror-cursor {
114 width: auto;
115 border: 0;
116 background: transparent;
117 background: rgba(0, 200, 0, .4);
118 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
119 }
120 /* Kludge to turn off filter in ie9+, which also accepts rgba */
121 .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
122 filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
62 }
123 }
124 .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
63 .CodeMirror-focused pre.CodeMirror-cursor {
125 .CodeMirror-focused pre.CodeMirror-cursor {
64 visibility: visible;
126 visibility: visible;
65 }
127 }
@@ -93,7 +155,7 b' div.CodeMirror-selected { background: #d9d9d9; }'
93 .cm-s-default span.cm-bracket {color: #cc7;}
155 .cm-s-default span.cm-bracket {color: #cc7;}
94 .cm-s-default span.cm-tag {color: #170;}
156 .cm-s-default span.cm-tag {color: #170;}
95 .cm-s-default span.cm-attribute {color: #00c;}
157 .cm-s-default span.cm-attribute {color: #00c;}
96 .cm-s-default span.cm-header {color: #a0a;}
158 .cm-s-default span.cm-header {color: blue;}
97 .cm-s-default span.cm-quote {color: #090;}
159 .cm-s-default span.cm-quote {color: #090;}
98 .cm-s-default span.cm-hr {color: #999;}
160 .cm-s-default span.cm-hr {color: #999;}
99 .cm-s-default span.cm-link {color: #00c;}
161 .cm-s-default span.cm-link {color: #00c;}
This diff has been collapsed as it changes many lines, (1180 lines changed) Show them Hide them
@@ -4,7 +4,7 b''
4
4
5 // CodeMirror is the only global var we claim
5 // CodeMirror is the only global var we claim
6 var CodeMirror = (function() {
6 var CodeMirror = (function() {
7 // This is the function that produces an editor instance. It's
7 // This is the function that produces an editor instance. Its
8 // closure is used to store the editor state.
8 // closure is used to store the editor state.
9 function CodeMirror(place, givenOptions) {
9 function CodeMirror(place, givenOptions) {
10 // Determine effective options based on given values and defaults.
10 // Determine effective options based on given values and defaults.
@@ -13,23 +13,27 b' var CodeMirror = (function() {'
13 if (defaults.hasOwnProperty(opt))
13 if (defaults.hasOwnProperty(opt))
14 options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
14 options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15
15
16 var targetDocument = options["document"];
17 // The element in which the editor lives.
16 // The element in which the editor lives.
18 var wrapper = targetDocument.createElement("div");
17 var wrapper = document.createElement("div");
19 wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
18 wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
20 // This mess creates the base DOM structure for the editor.
19 // This mess creates the base DOM structure for the editor.
21 wrapper.innerHTML =
20 wrapper.innerHTML =
22 '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
21 '<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
23 '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
22 '<textarea style="position: absolute; padding: 0; width: 1px; height: 1em" wrap="off" ' +
24 'autocorrect="off" autocapitalize="off"></textarea></div>' +
23 'autocorrect="off" autocapitalize="off"></textarea></div>' +
24 '<div class="CodeMirror-scrollbar">' + // The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
25 '<div class="CodeMirror-scrollbar-inner">' + // The empty scrollbar content, used solely for managing the scrollbar thumb.
26 '</div></div>' + // This must be before the scroll area because it's float-right.
25 '<div class="CodeMirror-scroll" tabindex="-1">' +
27 '<div class="CodeMirror-scroll" tabindex="-1">' +
26 '<div style="position: relative">' + // Set to the height of the text, causes scrolling
28 '<div style="position: relative">' + // Set to the height of the text, causes scrolling
27 '<div style="position: relative">' + // Moved around its parent to cover visible view
29 '<div style="position: relative">' + // Moved around its parent to cover visible view
28 '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
30 '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29 // Provides positioning relative to (visible) text origin
31 // Provides positioning relative to (visible) text origin
30 '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
32 '<div class="CodeMirror-lines"><div style="position: relative; z-index: 0">' +
31 '<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden; outline: 5px auto none"></div>' +
33 // Used to measure text size
34 '<div style="position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;"></div>' +
32 '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
35 '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
36 '<pre class="CodeMirror-cursor" style="visibility: hidden">&#160;</pre>' + // Used to force a width
33 '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
37 '<div style="position: relative; z-index: -1"></div><div></div>' + // DIVs containing the selection and the actual code
34 '</div></div></div></div></div>';
38 '</div></div></div></div></div>';
35 if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
39 if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
@@ -38,15 +42,30 b' var CodeMirror = (function() {'
38 scroller = wrapper.lastChild, code = scroller.firstChild,
42 scroller = wrapper.lastChild, code = scroller.firstChild,
39 mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
43 mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
40 lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
44 lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
41 cursor = measure.nextSibling, selectionDiv = cursor.nextSibling,
45 cursor = measure.nextSibling, widthForcer = cursor.nextSibling,
42 lineDiv = selectionDiv.nextSibling;
46 selectionDiv = widthForcer.nextSibling, lineDiv = selectionDiv.nextSibling,
43 themeChanged();
47 scrollbar = inputDiv.nextSibling, scrollbarInner = scrollbar.firstChild;
48 themeChanged(); keyMapChanged();
44 // Needed to hide big blue blinking cursor on Mobile Safari
49 // Needed to hide big blue blinking cursor on Mobile Safari
45 if (ios) input.style.width = "0px";
50 if (ios) input.style.width = "0px";
46 if (!webkit) lineSpace.draggable = true;
51 if (!webkit) scroller.draggable = true;
47 lineSpace.style.outline = "none";
52 lineSpace.style.outline = "none";
48 if (options.tabindex != null) input.tabIndex = options.tabindex;
53 if (options.tabindex != null) input.tabIndex = options.tabindex;
54 if (options.autofocus) focusInput();
49 if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
55 if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
56 // Needed to handle Tab key in KHTML
57 if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
58
59 // Check for OS X >= 10.7. If so, we need to force a width on the scrollbar, and
60 // make it overlap the content. (But we only do this if the scrollbar doesn't already
61 // have a natural width. If the mouse is plugged in or the user sets the system pref
62 // to always show scrollbars, the scrollbar shouldn't overlap.)
63 if (mac_geLion) {
64 scrollbar.className += (overlapScrollbars() ? " cm-sb-overlap" : " cm-sb-nonoverlap");
65 } else if (ie_lt8) {
66 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
67 scrollbar.className += " cm-sb-ie7";
68 }
50
69
51 // Check for problem with IE innerHTML not working when we have a
70 // Check for problem with IE innerHTML not working when we have a
52 // P (or similar) parent node.
71 // P (or similar) parent node.
@@ -71,7 +90,7 b' var CodeMirror = (function() {'
71 var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
90 var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
72 // Selection-related flags. shiftSelecting obviously tracks
91 // Selection-related flags. shiftSelecting obviously tracks
73 // whether the user is holding shift.
92 // whether the user is holding shift.
74 var shiftSelecting, lastClick, lastDoubleClick, lastScrollPos = 0, draggingText,
93 var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, lastScrollLeft = 0, draggingText,
75 overwrite = false, suppressEdits = false;
94 overwrite = false, suppressEdits = false;
76 // Variables used by startOperation/endOperation to track what
95 // Variables used by startOperation/endOperation to track what
77 // happened during the operation.
96 // happened during the operation.
@@ -79,12 +98,13 b' var CodeMirror = (function() {'
79 gutterDirty, callbacks;
98 gutterDirty, callbacks;
80 // Current visible range (may be bigger than the view window).
99 // Current visible range (may be bigger than the view window).
81 var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
100 var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
82 // bracketHighlighted is used to remember that a backet has been
101 // bracketHighlighted is used to remember that a bracket has been
83 // marked.
102 // marked.
84 var bracketHighlighted;
103 var bracketHighlighted;
85 // Tracks the maximum line length so that the horizontal scrollbar
104 // Tracks the maximum line length so that the horizontal scrollbar
86 // can be kept static when scrolling.
105 // can be kept static when scrolling.
87 var maxLine = "", maxWidth, tabText = computeTabText();
106 var maxLine = "", updateMaxLine = false, maxLineChanged = true;
107 var tabCache = {};
88
108
89 // Initialize the content.
109 // Initialize the content.
90 operation(function(){setValue(options.value || ""); updateInput = false;})();
110 operation(function(){setValue(options.value || ""); updateInput = false;})();
@@ -93,18 +113,16 b' var CodeMirror = (function() {'
93 // Register our event handlers.
113 // Register our event handlers.
94 connect(scroller, "mousedown", operation(onMouseDown));
114 connect(scroller, "mousedown", operation(onMouseDown));
95 connect(scroller, "dblclick", operation(onDoubleClick));
115 connect(scroller, "dblclick", operation(onDoubleClick));
96 connect(lineSpace, "dragstart", onDragStart);
97 connect(lineSpace, "selectstart", e_preventDefault);
116 connect(lineSpace, "selectstart", e_preventDefault);
98 // Gecko browsers fire contextmenu *after* opening the menu, at
117 // Gecko browsers fire contextmenu *after* opening the menu, at
99 // which point we can't mess with it anymore. Context menu is
118 // which point we can't mess with it anymore. Context menu is
100 // handled in onMouseDown for Gecko.
119 // handled in onMouseDown for Gecko.
101 if (!gecko) connect(scroller, "contextmenu", onContextMenu);
120 if (!gecko) connect(scroller, "contextmenu", onContextMenu);
102 connect(scroller, "scroll", function() {
121 connect(scroller, "scroll", onScroll);
103 lastScrollPos = scroller.scrollTop;
122 connect(scrollbar, "scroll", onScroll);
104 updateDisplay([]);
123 connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);});
105 if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
124 connect(scroller, "mousewheel", onMouseWheel);
106 if (options.onScroll) options.onScroll(instance);
125 connect(scroller, "DOMMouseScroll", onMouseWheel);
107 });
108 connect(window, "resize", function() {updateDisplay(true);});
126 connect(window, "resize", function() {updateDisplay(true);});
109 connect(input, "keyup", operation(onKeyUp));
127 connect(input, "keyup", operation(onKeyUp));
110 connect(input, "input", fastPoll);
128 connect(input, "input", fastPoll);
@@ -113,19 +131,32 b' var CodeMirror = (function() {'
113 connect(input, "focus", onFocus);
131 connect(input, "focus", onFocus);
114 connect(input, "blur", onBlur);
132 connect(input, "blur", onBlur);
115
133
116 connect(scroller, "dragenter", e_stop);
134 if (options.dragDrop) {
117 connect(scroller, "dragover", e_stop);
135 connect(scroller, "dragstart", onDragStart);
118 connect(scroller, "drop", operation(onDrop));
136 function drag_(e) {
137 if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
138 e_stop(e);
139 }
140 connect(scroller, "dragenter", drag_);
141 connect(scroller, "dragover", drag_);
142 connect(scroller, "drop", operation(onDrop));
143 }
119 connect(scroller, "paste", function(){focusInput(); fastPoll();});
144 connect(scroller, "paste", function(){focusInput(); fastPoll();});
120 connect(input, "paste", fastPoll);
145 connect(input, "paste", fastPoll);
121 connect(input, "cut", operation(function(){
146 connect(input, "cut", operation(function(){
122 if (!options.readOnly) replaceSelection("");
147 if (!options.readOnly) replaceSelection("");
123 }));
148 }));
124
149
150 // Needed to handle Tab key in KHTML
151 if (khtml) connect(code, "mouseup", function() {
152 if (document.activeElement == input) input.blur();
153 focusInput();
154 });
155
125 // IE throws unspecified error in certain cases, when
156 // IE throws unspecified error in certain cases, when
126 // trying to access activeElement before onload
157 // trying to access activeElement before onload
127 var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
158 var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
128 if (hasFocus) setTimeout(onFocus, 20);
159 if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
129 else onBlur();
160 else onBlur();
130
161
131 function isLine(l) {return l >= 0 && l < doc.size;}
162 function isLine(l) {return l >= 0 && l < doc.size;}
@@ -139,7 +170,7 b' var CodeMirror = (function() {'
139 setValue: operation(setValue),
170 setValue: operation(setValue),
140 getSelection: getSelection,
171 getSelection: getSelection,
141 replaceSelection: operation(replaceSelection),
172 replaceSelection: operation(replaceSelection),
142 focus: function(){focusInput(); onFocus(); fastPoll();},
173 focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
143 setOption: function(option, value) {
174 setOption: function(option, value) {
144 var oldVal = options[option];
175 var oldVal = options[option];
145 options[option] = value;
176 options[option] = value;
@@ -148,7 +179,8 b' var CodeMirror = (function() {'
148 else if (option == "readOnly" && !value) {resetInput(true);}
179 else if (option == "readOnly" && !value) {resetInput(true);}
149 else if (option == "theme") themeChanged();
180 else if (option == "theme") themeChanged();
150 else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
181 else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
151 else if (option == "tabSize") operation(tabsChanged)();
182 else if (option == "tabSize") updateDisplay(true);
183 else if (option == "keyMap") keyMapChanged();
152 if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
184 if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") {
153 gutterChanged();
185 gutterChanged();
154 updateDisplay(true);
186 updateDisplay(true);
@@ -167,6 +199,15 b' var CodeMirror = (function() {'
167 indentSelection: operation(indentSelected),
199 indentSelection: operation(indentSelected),
168 historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
200 historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
169 clearHistory: function() {history = new History();},
201 clearHistory: function() {history = new History();},
202 setHistory: function(histData) {
203 history = new History();
204 history.done = histData.done;
205 history.undone = histData.undone;
206 },
207 getHistory: function() {
208 history.time = 0;
209 return {done: history.done.concat([]), undone: history.undone.concat([])};
210 },
170 matchBrackets: operation(function(){matchBrackets(true);}),
211 matchBrackets: operation(function(){matchBrackets(true);}),
171 getTokenAt: operation(function(pos) {
212 getTokenAt: operation(function(pos) {
172 pos = clipPos(pos);
213 pos = clipPos(pos);
@@ -176,17 +217,23 b' var CodeMirror = (function() {'
176 line = clipLine(line == null ? doc.size - 1: line);
217 line = clipLine(line == null ? doc.size - 1: line);
177 return getStateBefore(line + 1);
218 return getStateBefore(line + 1);
178 },
219 },
179 cursorCoords: function(start){
220 cursorCoords: function(start, mode) {
180 if (start == null) start = sel.inverted;
221 if (start == null) start = sel.inverted;
181 return pageCoords(start ? sel.from : sel.to);
222 return this.charCoords(start ? sel.from : sel.to, mode);
223 },
224 charCoords: function(pos, mode) {
225 pos = clipPos(pos);
226 if (mode == "local") return localCoords(pos, false);
227 if (mode == "div") return localCoords(pos, true);
228 return pageCoords(pos);
182 },
229 },
183 charCoords: function(pos){return pageCoords(clipPos(pos));},
184 coordsChar: function(coords) {
230 coordsChar: function(coords) {
185 var off = eltOffset(lineSpace);
231 var off = eltOffset(lineSpace);
186 return coordsChar(coords.x - off.left, coords.y - off.top);
232 return coordsChar(coords.x - off.left, coords.y - off.top);
187 },
233 },
188 markText: operation(markText),
234 markText: operation(markText),
189 setBookmark: setBookmark,
235 setBookmark: setBookmark,
236 findMarksAt: findMarksAt,
190 setMarker: operation(addGutterMarker),
237 setMarker: operation(addGutterMarker),
191 clearMarker: operation(removeGutterMarker),
238 clearMarker: operation(removeGutterMarker),
192 setLineClass: operation(setLineClass),
239 setLineClass: operation(setLineClass),
@@ -252,14 +299,23 b' var CodeMirror = (function() {'
252 if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
299 if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
253 }),
300 }),
254 replaceRange: operation(replaceRange),
301 replaceRange: operation(replaceRange),
255 getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
302 getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);},
256
303
304 triggerOnKeyDown: operation(onKeyDown),
257 execCommand: function(cmd) {return commands[cmd](instance);},
305 execCommand: function(cmd) {return commands[cmd](instance);},
258 // Stuff used by commands, probably not much use to outside code.
306 // Stuff used by commands, probably not much use to outside code.
259 moveH: operation(moveH),
307 moveH: operation(moveH),
260 deleteH: operation(deleteH),
308 deleteH: operation(deleteH),
261 moveV: operation(moveV),
309 moveV: operation(moveV),
262 toggleOverwrite: function() {overwrite = !overwrite;},
310 toggleOverwrite: function() {
311 if(overwrite){
312 overwrite = false;
313 cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
314 } else {
315 overwrite = true;
316 cursor.className += " CodeMirror-overwrite";
317 }
318 },
263
319
264 posFromIndex: function(off) {
320 posFromIndex: function(off) {
265 var lineNo = 0, ch;
321 var lineNo = 0, ch;
@@ -281,15 +337,28 b' var CodeMirror = (function() {'
281 },
337 },
282 scrollTo: function(x, y) {
338 scrollTo: function(x, y) {
283 if (x != null) scroller.scrollLeft = x;
339 if (x != null) scroller.scrollLeft = x;
284 if (y != null) scroller.scrollTop = y;
340 if (y != null) scrollbar.scrollTop = y;
285 updateDisplay([]);
341 updateDisplay([]);
286 },
342 },
343 getScrollInfo: function() {
344 return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
345 height: scrollbar.scrollHeight, width: scroller.scrollWidth};
346 },
347 setSize: function(width, height) {
348 function interpret(val) {
349 val = String(val);
350 return /^\d+$/.test(val) ? val + "px" : val;
351 }
352 if (width != null) wrapper.style.width = interpret(width);
353 if (height != null) scroller.style.height = interpret(height);
354 },
287
355
288 operation: function(f){return operation(f)();},
356 operation: function(f){return operation(f)();},
357 compoundChange: function(f){return compoundChange(f);},
289 refresh: function(){
358 refresh: function(){
290 updateDisplay(true);
359 updateDisplay(true, null, lastScrollTop);
291 if (scroller.scrollHeight > lastScrollPos)
360 if (scrollbar.scrollHeight > lastScrollTop)
292 scroller.scrollTop = lastScrollPos;
361 scrollbar.scrollTop = lastScrollTop;
293 },
362 },
294 getInputField: function(){return input;},
363 getInputField: function(){return input;},
295 getWrapperElement: function(){return wrapper;},
364 getWrapperElement: function(){return wrapper;},
@@ -310,10 +379,24 b' var CodeMirror = (function() {'
310 splitLines(code), top, top);
379 splitLines(code), top, top);
311 updateInput = true;
380 updateInput = true;
312 }
381 }
313 function getValue(code) {
382 function getValue(lineSep) {
314 var text = [];
383 var text = [];
315 doc.iter(0, doc.size, function(line) { text.push(line.text); });
384 doc.iter(0, doc.size, function(line) { text.push(line.text); });
316 return text.join("\n");
385 return text.join(lineSep || "\n");
386 }
387
388 function onScroll(e) {
389 if (scroller.scrollTop) {
390 scrollbar.scrollTop += scroller.scrollTop;
391 scroller.scrollTop = 0;
392 }
393 if (lastScrollTop != scrollbar.scrollTop || lastScrollLeft != scroller.scrollLeft) {
394 lastScrollTop = scrollbar.scrollTop;
395 lastScrollLeft = scroller.scrollLeft;
396 updateDisplay([]);
397 if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
398 if (options.onScroll) options.onScroll(instance);
399 }
317 }
400 }
318
401
319 function onMouseDown(e) {
402 function onMouseDown(e) {
@@ -334,10 +417,12 b' var CodeMirror = (function() {'
334
417
335 switch (e_button(e)) {
418 switch (e_button(e)) {
336 case 3:
419 case 3:
337 if (gecko && !mac) onContextMenu(e);
420 if (gecko) onContextMenu(e);
338 return;
421 return;
339 case 2:
422 case 2:
340 if (start) setCursor(start.line, start.ch, true);
423 if (start) setCursor(start.line, start.ch, true);
424 setTimeout(focusInput, 20);
425 e_preventDefault(e);
341 return;
426 return;
342 }
427 }
343 // For button 1, if it was clicked inside the editor
428 // For button 1, if it was clicked inside the editor
@@ -347,44 +432,66 b' var CodeMirror = (function() {'
347
432
348 if (!focused) onFocus();
433 if (!focused) onFocus();
349
434
350 var now = +new Date;
435 var now = +new Date, type = "single";
351 if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
436 if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
437 type = "triple";
352 e_preventDefault(e);
438 e_preventDefault(e);
353 setTimeout(focusInput, 20);
439 setTimeout(focusInput, 20);
354 return selectLine(start.line);
440 selectLine(start.line);
355 } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
441 } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
442 type = "double";
356 lastDoubleClick = {time: now, pos: start};
443 lastDoubleClick = {time: now, pos: start};
357 e_preventDefault(e);
444 e_preventDefault(e);
358 return selectWordAt(start);
445 var word = findWordAt(start);
446 setSelectionUser(word.from, word.to);
359 } else { lastClick = {time: now, pos: start}; }
447 } else { lastClick = {time: now, pos: start}; }
360
448
361 var last = start, going;
449 var last = start, going;
362 if (dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
450 if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
363 !posLess(start, sel.from) && !posLess(sel.to, start)) {
451 !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
364 // Let the drag handler handle this.
452 // Let the drag handler handle this.
365 if (webkit) lineSpace.draggable = true;
453 if (webkit) scroller.draggable = true;
366 var up = connect(targetDocument, "mouseup", operation(function(e2) {
454 function dragEnd(e2) {
367 if (webkit) lineSpace.draggable = false;
455 if (webkit) scroller.draggable = false;
368 draggingText = false;
456 draggingText = false;
369 up();
457 up(); drop();
370 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
458 if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
371 e_preventDefault(e2);
459 e_preventDefault(e2);
372 setCursor(start.line, start.ch, true);
460 setCursor(start.line, start.ch, true);
373 focusInput();
461 focusInput();
374 }
462 }
375 }), true);
463 }
464 var up = connect(document, "mouseup", operation(dragEnd), true);
465 var drop = connect(scroller, "drop", operation(dragEnd), true);
376 draggingText = true;
466 draggingText = true;
467 // IE's approach to draggable
468 if (scroller.dragDrop) scroller.dragDrop();
377 return;
469 return;
378 }
470 }
379 e_preventDefault(e);
471 e_preventDefault(e);
380 setCursor(start.line, start.ch, true);
472 if (type == "single") setCursor(start.line, start.ch, true);
473
474 var startstart = sel.from, startend = sel.to;
475
476 function doSelect(cur) {
477 if (type == "single") {
478 setSelectionUser(start, cur);
479 } else if (type == "double") {
480 var word = findWordAt(cur);
481 if (posLess(cur, startstart)) setSelectionUser(word.from, startend);
482 else setSelectionUser(startstart, word.to);
483 } else if (type == "triple") {
484 if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0}));
485 else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0}));
486 }
487 }
381
488
382 function extend(e) {
489 function extend(e) {
383 var cur = posFromMouse(e, true);
490 var cur = posFromMouse(e, true);
384 if (cur && !posEq(cur, last)) {
491 if (cur && !posEq(cur, last)) {
385 if (!focused) onFocus();
492 if (!focused) onFocus();
386 last = cur;
493 last = cur;
387 setSelectionUser(start, cur);
494 doSelect(cur);
388 updateInput = false;
495 updateInput = false;
389 var visible = visibleLines();
496 var visible = visibleLines();
390 if (cur.line >= visible.to || cur.line < visible.from)
497 if (cur.line >= visible.to || cur.line < visible.from)
@@ -392,31 +499,30 b' var CodeMirror = (function() {'
392 }
499 }
393 }
500 }
394
501
395 var move = connect(targetDocument, "mousemove", operation(function(e) {
502 function done(e) {
396 clearTimeout(going);
397 e_preventDefault(e);
398 extend(e);
399 }), true);
400 var up = connect(targetDocument, "mouseup", operation(function(e) {
401 clearTimeout(going);
503 clearTimeout(going);
402 var cur = posFromMouse(e);
504 var cur = posFromMouse(e);
403 if (cur) setSelectionUser(start, cur);
505 if (cur) doSelect(cur);
404 e_preventDefault(e);
506 e_preventDefault(e);
405 focusInput();
507 focusInput();
406 updateInput = true;
508 updateInput = true;
407 move(); up();
509 move(); up();
510 }
511 var move = connect(document, "mousemove", operation(function(e) {
512 clearTimeout(going);
513 e_preventDefault(e);
514 if (!ie && !e_button(e)) done(e);
515 else extend(e);
408 }), true);
516 }), true);
517 var up = connect(document, "mouseup", operation(done), true);
409 }
518 }
410 function onDoubleClick(e) {
519 function onDoubleClick(e) {
411 for (var n = e_target(e); n != wrapper; n = n.parentNode)
520 for (var n = e_target(e); n != wrapper; n = n.parentNode)
412 if (n.parentNode == gutterText) return e_preventDefault(e);
521 if (n.parentNode == gutterText) return e_preventDefault(e);
413 var start = posFromMouse(e);
414 if (!start) return;
415 lastDoubleClick = {time: +new Date, pos: start};
416 e_preventDefault(e);
522 e_preventDefault(e);
417 selectWordAt(start);
418 }
523 }
419 function onDrop(e) {
524 function onDrop(e) {
525 if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
420 e.preventDefault();
526 e.preventDefault();
421 var pos = posFromMouse(e, true), files = e.dataTransfer.files;
527 var pos = posFromMouse(e, true), files = e.dataTransfer.files;
422 if (!pos || options.readOnly) return;
528 if (!pos || options.readOnly) return;
@@ -426,86 +532,124 b' var CodeMirror = (function() {'
426 reader.onload = function() {
532 reader.onload = function() {
427 text[i] = reader.result;
533 text[i] = reader.result;
428 if (++read == n) {
534 if (++read == n) {
429 pos = clipPos(pos);
535 pos = clipPos(pos);
430 operation(function() {
536 operation(function() {
431 var end = replaceRange(text.join(""), pos, pos);
537 var end = replaceRange(text.join(""), pos, pos);
432 setSelectionUser(pos, end);
538 setSelectionUser(pos, end);
433 })();
539 })();
434 }
540 }
435 };
541 };
436 reader.readAsText(file);
542 reader.readAsText(file);
437 }
543 }
438 var n = files.length, text = Array(n), read = 0;
544 var n = files.length, text = Array(n), read = 0;
439 for (var i = 0; i < n; ++i) loadFile(files[i], i);
545 for (var i = 0; i < n; ++i) loadFile(files[i], i);
440 }
546 } else {
441 else {
547 // Don't do a replace if the drop happened inside of the selected text.
548 if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
442 try {
549 try {
443 var text = e.dataTransfer.getData("Text");
550 var text = e.dataTransfer.getData("Text");
444 if (text) {
551 if (text) {
445 var curFrom = sel.from, curTo = sel.to;
552 compoundChange(function() {
446 setSelectionUser(pos, pos);
553 var curFrom = sel.from, curTo = sel.to;
447 if (draggingText) replaceRange("", curFrom, curTo);
554 setSelectionUser(pos, pos);
448 replaceSelection(text);
555 if (draggingText) replaceRange("", curFrom, curTo);
449 focusInput();
556 replaceSelection(text);
450 }
557 focusInput();
558 });
559 }
451 }
560 }
452 catch(e){}
561 catch(e){}
453 }
562 }
454 }
563 }
455 function onDragStart(e) {
564 function onDragStart(e) {
456 var txt = getSelection();
565 var txt = getSelection();
457 // This will reset escapeElement
458 htmlEscape(txt);
459 e.dataTransfer.setDragImage(escapeElement, 0, 0);
460 e.dataTransfer.setData("Text", txt);
566 e.dataTransfer.setData("Text", txt);
461 }
567
462 function handleKeyBinding(e) {
568 // Use dummy image instead of default browsers image.
463 var name = keyNames[e_prop(e, "keyCode")], next = keyMap[options.keyMap].auto, bound, dropShift;
569 if (gecko || chrome || opera) {
464 function handleNext() {
570 var img = document.createElement('img');
465 return next.call ? next.call(null, instance) : next;
571 img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
466 }
572 e.dataTransfer.setDragImage(img, 0, 0);
467 if (name == null || e.altGraphKey) {
468 if (next) options.keyMap = handleNext();
469 return null;
470 }
471 if (e_prop(e, "altKey")) name = "Alt-" + name;
472 if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
473 if (e_prop(e, "metaKey")) name = "Cmd-" + name;
474 if (e_prop(e, "shiftKey") &&
475 (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) {
476 dropShift = true;
477 } else {
478 bound = lookupKey(name, options.extraKeys, options.keyMap);
479 }
573 }
574 }
575
576 function doHandleBinding(bound, dropShift) {
480 if (typeof bound == "string") {
577 if (typeof bound == "string") {
481 if (commands.propertyIsEnumerable(bound)) bound = commands[bound];
578 bound = commands[bound];
482 else bound = null;
579 if (!bound) return false;
483 }
580 }
484 if (next && (bound || !isModifierKey(e))) options.keyMap = handleNext();
485 if (!bound) return false;
486 var prevShift = shiftSelecting;
581 var prevShift = shiftSelecting;
487 try {
582 try {
488 if (options.readOnly) suppressEdits = true;
583 if (options.readOnly) suppressEdits = true;
489 if (dropShift) shiftSelecting = null;
584 if (dropShift) shiftSelecting = null;
490 bound(instance);
585 bound(instance);
586 } catch(e) {
587 if (e != Pass) throw e;
588 return false;
491 } finally {
589 } finally {
492 shiftSelecting = prevShift;
590 shiftSelecting = prevShift;
493 suppressEdits = false;
591 suppressEdits = false;
494 }
592 }
495 e_preventDefault(e);
496 return true;
593 return true;
497 }
594 }
498 var lastStoppedKey = null;
595 function handleKeyBinding(e) {
596 // Handle auto keymap transitions
597 var startMap = getKeyMap(options.keyMap), next = startMap.auto;
598 clearTimeout(maybeTransition);
599 if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
600 if (getKeyMap(options.keyMap) == startMap) {
601 options.keyMap = (next.call ? next.call(null, instance) : next);
602 }
603 }, 50);
604
605 var name = keyNames[e_prop(e, "keyCode")], handled = false;
606 if (name == null || e.altGraphKey) return false;
607 if (e_prop(e, "altKey")) name = "Alt-" + name;
608 if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
609 if (e_prop(e, "metaKey")) name = "Cmd-" + name;
610
611 var stopped = false;
612 function stop() { stopped = true; }
613
614 if (e_prop(e, "shiftKey")) {
615 handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
616 function(b) {return doHandleBinding(b, true);}, stop)
617 || lookupKey(name, options.extraKeys, options.keyMap, function(b) {
618 if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
619 }, stop);
620 } else {
621 handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
622 }
623 if (stopped) handled = false;
624 if (handled) {
625 e_preventDefault(e);
626 restartBlink();
627 if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
628 }
629 return handled;
630 }
631 function handleCharBinding(e, ch) {
632 var handled = lookupKey("'" + ch + "'", options.extraKeys,
633 options.keyMap, function(b) { return doHandleBinding(b, true); });
634 if (handled) {
635 e_preventDefault(e);
636 restartBlink();
637 }
638 return handled;
639 }
640
641 var lastStoppedKey = null, maybeTransition;
499 function onKeyDown(e) {
642 function onKeyDown(e) {
500 if (!focused) onFocus();
643 if (!focused) onFocus();
501 if (ie && e.keyCode == 27) { e.returnValue = false; }
644 if (ie && e.keyCode == 27) { e.returnValue = false; }
645 if (pollingFast) { if (readInput()) pollingFast = false; }
502 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
646 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
503 var code = e_prop(e, "keyCode");
647 var code = e_prop(e, "keyCode");
504 // IE does strange things with escape.
648 // IE does strange things with escape.
505 setShift(code == 16 || e_prop(e, "shiftKey"));
649 setShift(code == 16 || e_prop(e, "shiftKey"));
506 // First give onKeyEvent option a chance to handle this.
650 // First give onKeyEvent option a chance to handle this.
507 var handled = handleKeyBinding(e);
651 var handled = handleKeyBinding(e);
508 if (window.opera) {
652 if (opera) {
509 lastStoppedKey = handled ? code : null;
653 lastStoppedKey = handled ? code : null;
510 // Opera has no cut event... we try to at least catch the key combo
654 // Opera has no cut event... we try to at least catch the key combo
511 if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
655 if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
@@ -513,15 +657,17 b' var CodeMirror = (function() {'
513 }
657 }
514 }
658 }
515 function onKeyPress(e) {
659 function onKeyPress(e) {
660 if (pollingFast) readInput();
516 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
661 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
517 var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
662 var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
518 if (window.opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
663 if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
519 if (window.opera && !e.which && handleKeyBinding(e)) return;
664 if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
665 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
520 if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
666 if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
521 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
522 if (mode.electricChars.indexOf(ch) > -1)
667 if (mode.electricChars.indexOf(ch) > -1)
523 setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
668 setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
524 }
669 }
670 if (handleCharBinding(e, ch)) return;
525 fastPoll();
671 fastPoll();
526 }
672 }
527 function onKeyUp(e) {
673 function onKeyUp(e) {
@@ -534,8 +680,8 b' var CodeMirror = (function() {'
534 if (!focused) {
680 if (!focused) {
535 if (options.onFocus) options.onFocus(instance);
681 if (options.onFocus) options.onFocus(instance);
536 focused = true;
682 focused = true;
537 if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
683 if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
538 wrapper.className += " CodeMirror-focused";
684 scroller.className += " CodeMirror-focused";
539 if (!leaveInputAlone) resetInput(true);
685 if (!leaveInputAlone) resetInput(true);
540 }
686 }
541 slowPoll();
687 slowPoll();
@@ -549,12 +695,48 b' var CodeMirror = (function() {'
549 operation(function(){
695 operation(function(){
550 if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
696 if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
551 })();
697 })();
552 wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
698 scroller.className = scroller.className.replace(" CodeMirror-focused", "");
553 }
699 }
554 clearInterval(blinker);
700 clearInterval(blinker);
555 setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
701 setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
556 }
702 }
557
703
704 function chopDelta(delta) {
705 // Make sure we always scroll a little bit for any nonzero delta.
706 if (delta > 0.0 && delta < 1.0) return 1;
707 else if (delta > -1.0 && delta < 0.0) return -1;
708 else return Math.round(delta);
709 }
710
711 function onMouseWheel(e) {
712 var deltaX = 0, deltaY = 0;
713 if (e.type == "DOMMouseScroll") { // Firefox
714 var delta = -e.detail * 8.0;
715 if (e.axis == e.HORIZONTAL_AXIS) deltaX = delta;
716 else if (e.axis == e.VERTICAL_AXIS) deltaY = delta;
717 } else if (e.wheelDeltaX !== undefined && e.wheelDeltaY !== undefined) { // WebKit
718 deltaX = e.wheelDeltaX / 3.0;
719 deltaY = e.wheelDeltaY / 3.0;
720 } else if (e.wheelDelta !== undefined) { // IE or Opera
721 deltaY = e.wheelDelta / 3.0;
722 }
723
724 var scrolled = false;
725 deltaX = chopDelta(deltaX);
726 deltaY = chopDelta(deltaY);
727 if ((deltaX > 0 && scroller.scrollLeft > 0) ||
728 (deltaX < 0 && scroller.scrollLeft + scroller.clientWidth < scroller.scrollWidth)) {
729 scroller.scrollLeft -= deltaX;
730 scrolled = true;
731 }
732 if ((deltaY > 0 && scrollbar.scrollTop > 0) ||
733 (deltaY < 0 && scrollbar.scrollTop + scrollbar.clientHeight < scrollbar.scrollHeight)) {
734 scrollbar.scrollTop -= deltaY;
735 scrolled = true;
736 }
737 if (scrolled) e_stop(e);
738 }
739
558 // Replace the range from from to to by the strings in newText.
740 // Replace the range from from to to by the strings in newText.
559 // Afterwards, set the selection to selFrom, selTo.
741 // Afterwards, set the selection to selFrom, selTo.
560 function updateLines(from, to, newText, selFrom, selTo) {
742 function updateLines(from, to, newText, selFrom, selTo) {
@@ -567,29 +749,30 b' var CodeMirror = (function() {'
567 }
749 }
568 updateLinesNoUndo(from, to, newText, selFrom, selTo);
750 updateLinesNoUndo(from, to, newText, selFrom, selTo);
569 }
751 }
570 function unredoHelper(from, to, dir) {
752 function unredoHelper(from, to) {
571 var set = from.pop(), len = set ? set.length : 0, out = [];
753 if (!from.length) return;
572 for (var i = dir > 0 ? 0 : len - 1, e = dir > 0 ? len : -1; i != e; i += dir) {
754 var set = from.pop(), out = [];
755 for (var i = set.length - 1; i >= 0; i -= 1) {
573 var change = set[i];
756 var change = set[i];
574 var replaced = [], end = change.start + change.added;
757 var replaced = [], end = change.start + change.added;
575 doc.iter(change.start, end, function(line) { replaced.push(line.text); });
758 doc.iter(change.start, end, function(line) { replaced.push(line.text); });
576 out.push({start: change.start, added: change.old.length, old: replaced});
759 out.push({start: change.start, added: change.old.length, old: replaced});
577 var pos = clipPos({line: change.start + change.old.length - 1,
760 var pos = {line: change.start + change.old.length - 1,
578 ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
761 ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
579 updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
762 updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
580 }
763 }
581 updateInput = true;
764 updateInput = true;
582 to.push(out);
765 to.push(out);
583 }
766 }
584 function undo() {unredoHelper(history.done, history.undone, -1);}
767 function undo() {unredoHelper(history.done, history.undone);}
585 function redo() {unredoHelper(history.undone, history.done, 1);}
768 function redo() {unredoHelper(history.undone, history.done);}
586
769
587 function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
770 function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
588 if (suppressEdits) return;
771 if (suppressEdits) return;
589 var recomputeMaxLength = false, maxLineLength = maxLine.length;
772 var recomputeMaxLength = false, maxLineLength = maxLine.length;
590 if (!options.lineWrapping)
773 if (!options.lineWrapping)
591 doc.iter(from.line, to.line, function(line) {
774 doc.iter(from.line, to.line + 1, function(line) {
592 if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
775 if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
593 });
776 });
594 if (from.line != to.line || newText.length > 1) gutterDirty = true;
777 if (from.line != to.line || newText.length > 1) gutterDirty = true;
595
778
@@ -636,29 +819,21 b' var CodeMirror = (function() {'
636 doc.insert(from.line + 1, added);
819 doc.insert(from.line + 1, added);
637 }
820 }
638 if (options.lineWrapping) {
821 if (options.lineWrapping) {
639 var perLine = scroller.clientWidth / charWidth() - 3;
822 var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
640 doc.iter(from.line, from.line + newText.length, function(line) {
823 doc.iter(from.line, from.line + newText.length, function(line) {
641 if (line.hidden) return;
824 if (line.hidden) return;
642 var guess = Math.ceil(line.text.length / perLine) || 1;
825 var guess = Math.ceil(line.text.length / perLine) || 1;
643 if (guess != line.height) updateLineHeight(line, guess);
826 if (guess != line.height) updateLineHeight(line, guess);
644 });
827 });
645 } else {
828 } else {
646 doc.iter(from.line, i + newText.length, function(line) {
829 doc.iter(from.line, from.line + newText.length, function(line) {
647 var l = line.text;
830 var l = line.text;
648 if (l.length > maxLineLength) {
831 if (!line.hidden && l.length > maxLineLength) {
649 maxLine = l; maxLineLength = l.length; maxWidth = null;
832 maxLine = l; maxLineLength = l.length; maxLineChanged = true;
650 recomputeMaxLength = false;
833 recomputeMaxLength = false;
651 }
834 }
652 });
835 });
653 if (recomputeMaxLength) {
836 if (recomputeMaxLength) updateMaxLine = true;
654 maxLineLength = 0; maxLine = ""; maxWidth = null;
655 doc.iter(0, doc.size, function(line) {
656 var l = line.text;
657 if (l.length > maxLineLength) {
658 maxLineLength = l.length; maxLine = l;
659 }
660 });
661 }
662 }
837 }
663
838
664 // Add these lines to the work array, so that they will be
839 // Add these lines to the work array, so that they will be
@@ -684,11 +859,55 b' var CodeMirror = (function() {'
684
859
685 // Update the selection
860 // Update the selection
686 function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
861 function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
687 setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
862 setSelection(clipPos(selFrom), clipPos(selTo),
863 updateLine(sel.from.line), updateLine(sel.to.line));
864 }
865
866 function needsScrollbar() {
867 var realHeight = doc.height * textHeight() + 2 * paddingTop();
868 return realHeight - 1 > scroller.offsetHeight ? realHeight : false;
869 }
870
871 function updateVerticalScroll(scrollTop) {
872 var scrollHeight = needsScrollbar();
873 scrollbar.style.display = scrollHeight ? "block" : "none";
874 if (scrollHeight) {
875 scrollbarInner.style.height = scrollHeight + "px";
876 scrollbar.style.height = scroller.offsetHeight + "px";
877 if (scrollTop != null) scrollbar.scrollTop = scrollTop;
878 }
879 // Position the mover div to align with the current virtual scroll position
880 mover.style.top = (displayOffset * textHeight() - scrollbar.scrollTop) + "px";
881 }
882
883 // On Mac OS X Lion and up, detect whether the mouse is plugged in by measuring
884 // the width of a div with a scrollbar in it. If the width is <= 1, then
885 // the mouse isn't plugged in and scrollbars should overlap the content.
886 function overlapScrollbars() {
887 var tmpSb = document.createElement('div'),
888 tmpSbInner = document.createElement('div');
889 tmpSb.className = "CodeMirror-scrollbar";
890 tmpSb.style.cssText = "position: absolute; left: -9999px; height: 100px;";
891 tmpSbInner.className = "CodeMirror-scrollbar-inner";
892 tmpSbInner.style.height = "200px";
893 tmpSb.appendChild(tmpSbInner);
894
895 document.body.appendChild(tmpSb);
896 var result = (tmpSb.offsetWidth <= 1);
897 document.body.removeChild(tmpSb);
898 return result;
899 }
688
900
689 // Make sure the scroll-size div has the correct height.
901 function computeMaxLength() {
690 if (scroller.clientHeight)
902 var maxLineLength = 0;
691 code.style.height = (doc.height * textHeight() + 2 * paddingTop()) + "px";
903 maxLine = ""; maxLineChanged = true;
904 doc.iter(0, doc.size, function(line) {
905 var l = line.text;
906 if (!line.hidden && l.length > maxLineLength) {
907 maxLineLength = l.length; maxLine = l;
908 }
909 });
910 updateMaxLine = false;
692 }
911 }
693
912
694 function replaceRange(code, from, to) {
913 function replaceRange(code, from, to) {
@@ -724,16 +943,16 b' var CodeMirror = (function() {'
724 updateLines(from, to, code, newSel.from, newSel.to);
943 updateLines(from, to, code, newSel.from, newSel.to);
725 }
944 }
726
945
727 function getRange(from, to) {
946 function getRange(from, to, lineSep) {
728 var l1 = from.line, l2 = to.line;
947 var l1 = from.line, l2 = to.line;
729 if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
948 if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
730 var code = [getLine(l1).text.slice(from.ch)];
949 var code = [getLine(l1).text.slice(from.ch)];
731 doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
950 doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
732 code.push(getLine(l2).text.slice(0, to.ch));
951 code.push(getLine(l2).text.slice(0, to.ch));
733 return code.join("\n");
952 return code.join(lineSep || "\n");
734 }
953 }
735 function getSelection() {
954 function getSelection(lineSep) {
736 return getRange(sel.from, sel.to);
955 return getRange(sel.from, sel.to, lineSep);
737 }
956 }
738
957
739 var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
958 var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
@@ -777,7 +996,8 b' var CodeMirror = (function() {'
777 else if (overwrite && posEq(sel.from, sel.to))
996 else if (overwrite && posEq(sel.from, sel.to))
778 sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
997 sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
779 replaceSelection(text.slice(same), "end");
998 replaceSelection(text.slice(same), "end");
780 prevInput = text;
999 if (text.length > 1000) { input.value = prevInput = ""; }
1000 else prevInput = text;
781 return true;
1001 return true;
782 }
1002 }
783 function resetInput(user) {
1003 function resetInput(user) {
@@ -793,60 +1013,72 b' var CodeMirror = (function() {'
793 }
1013 }
794
1014
795 function scrollEditorIntoView() {
1015 function scrollEditorIntoView() {
796 if (!cursor.getBoundingClientRect) return;
797 var rect = cursor.getBoundingClientRect();
1016 var rect = cursor.getBoundingClientRect();
798 // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
1017 // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
799 if (ie && rect.top == rect.bottom) return;
1018 if (ie && rect.top == rect.bottom) return;
800 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
1019 var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
801 if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
1020 if (rect.top < 0 || rect.bottom > winH) scrollCursorIntoView();
802 }
1021 }
803 function scrollCursorIntoView() {
1022 function scrollCursorIntoView() {
1023 var coords = calculateCursorCoords();
1024 return scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
1025 }
1026 function calculateCursorCoords() {
804 var cursor = localCoords(sel.inverted ? sel.from : sel.to);
1027 var cursor = localCoords(sel.inverted ? sel.from : sel.to);
805 var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
1028 var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
806 return scrollIntoView(x, cursor.y, x, cursor.yBot);
1029 return {x: x, y: cursor.y, yBot: cursor.yBot};
807 }
1030 }
808 function scrollIntoView(x1, y1, x2, y2) {
1031 function scrollIntoView(x1, y1, x2, y2) {
809 var pl = paddingLeft(), pt = paddingTop(), lh = textHeight();
1032 var scrollPos = calculateScrollPos(x1, y1, x2, y2), scrolled = false;
1033 if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft; scrolled = true;}
1034 if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scrollPos.scrollTop; scrolled = true;}
1035 if (scrolled && options.onScroll) options.onScroll(instance);
1036 }
1037 function calculateScrollPos(x1, y1, x2, y2) {
1038 var pl = paddingLeft(), pt = paddingTop();
810 y1 += pt; y2 += pt; x1 += pl; x2 += pl;
1039 y1 += pt; y2 += pt; x1 += pl; x2 += pl;
811 var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
1040 var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
812 if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
1041 var docBottom = scroller.scrollHeight;
813 else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
1042 var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;;
1043 if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
1044 else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
814
1045
815 var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
1046 var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
816 var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
1047 var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
817 if (x1 < screenleft + gutterw) {
1048 var atLeft = x1 < gutterw + pl + 10;
818 if (x1 < 50) x1 = 0;
1049 if (x1 < screenleft + gutterw || atLeft) {
819 scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
1050 if (atLeft) x1 = 0;
820 scrolled = true;
1051 result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
821 }
1052 } else if (x2 > screenw + screenleft - 3) {
822 else if (x2 > screenw + screenleft - 3) {
1053 result.scrollLeft = x2 + 10 - screenw;
823 scroller.scrollLeft = x2 + 10 - screenw;
824 scrolled = true;
825 if (x2 > code.clientWidth) result = false;
826 }
1054 }
827 if (scrolled && options.onScroll) options.onScroll(instance);
828 return result;
1055 return result;
829 }
1056 }
830
1057
831 function visibleLines() {
1058 function visibleLines(scrollTop) {
832 var lh = textHeight(), top = scroller.scrollTop - paddingTop();
1059 var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
833 var from_height = Math.max(0, Math.floor(top / lh));
1060 var fromHeight = Math.max(0, Math.floor(top / lh));
834 var to_height = Math.ceil((top + scroller.clientHeight) / lh);
1061 var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
835 return {from: lineAtHeight(doc, from_height),
1062 return {from: lineAtHeight(doc, fromHeight),
836 to: lineAtHeight(doc, to_height)};
1063 to: lineAtHeight(doc, toHeight)};
837 }
1064 }
838 // Uses a set of changes plus the current scroll position to
1065 // Uses a set of changes plus the current scroll position to
839 // determine which DOM updates have to be made, and makes the
1066 // determine which DOM updates have to be made, and makes the
840 // updates.
1067 // updates.
841 function updateDisplay(changes, suppressCallback) {
1068 function updateDisplay(changes, suppressCallback, scrollTop) {
842 if (!scroller.clientWidth) {
1069 if (!scroller.clientWidth) {
843 showingFrom = showingTo = displayOffset = 0;
1070 showingFrom = showingTo = displayOffset = 0;
844 return;
1071 return;
845 }
1072 }
846 // Compute the new visible window
1073 // Compute the new visible window
847 var visible = visibleLines();
1074 // If scrollTop is specified, use that to determine which lines
1075 // to render instead of the current scrollbar position.
1076 var visible = visibleLines(scrollTop);
848 // Bail out if the visible area is already rendered and nothing changed.
1077 // Bail out if the visible area is already rendered and nothing changed.
849 if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) return;
1078 if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
1079 updateVerticalScroll(scrollTop);
1080 return;
1081 }
850 var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
1082 var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
851 if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
1083 if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
852 if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
1084 if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
@@ -864,7 +1096,10 b' var CodeMirror = (function() {'
864 if (range.from >= range.to) intact.splice(i--, 1);
1096 if (range.from >= range.to) intact.splice(i--, 1);
865 else intactLines += range.to - range.from;
1097 else intactLines += range.to - range.from;
866 }
1098 }
867 if (intactLines == to - from) return;
1099 if (intactLines == to - from && from == showingFrom && to == showingTo) {
1100 updateVerticalScroll(scrollTop);
1101 return;
1102 }
868 intact.sort(function(a, b) {return a.domStart - b.domStart;});
1103 intact.sort(function(a, b) {return a.domStart - b.domStart;});
869
1104
870 var th = textHeight(), gutterDisplay = gutter.style.display;
1105 var th = textHeight(), gutterDisplay = gutter.style.display;
@@ -872,17 +1107,12 b' var CodeMirror = (function() {'
872 patchDisplay(from, to, intact);
1107 patchDisplay(from, to, intact);
873 lineDiv.style.display = gutter.style.display = "";
1108 lineDiv.style.display = gutter.style.display = "";
874
1109
875 // Position the mover div to align with the lines it's supposed
876 // to be showing (which will cover the visible display)
877 var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
1110 var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
878 // This is just a bogus formula that detects when the editor is
1111 // This is just a bogus formula that detects when the editor is
879 // resized or the font size changes.
1112 // resized or the font size changes.
880 if (different) lastSizeC = scroller.clientHeight + th;
1113 if (different) lastSizeC = scroller.clientHeight + th;
881 showingFrom = from; showingTo = to;
1114 showingFrom = from; showingTo = to;
882 displayOffset = heightAtLine(doc, from);
1115 displayOffset = heightAtLine(doc, from);
883 mover.style.top = (displayOffset * th) + "px";
884 if (scroller.clientHeight)
885 code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
886
1116
887 // Since this is all rather error prone, it is honoured with the
1117 // Since this is all rather error prone, it is honoured with the
888 // only assertion in the whole file.
1118 // only assertion in the whole file.
@@ -890,8 +1120,7 b' var CodeMirror = (function() {'
890 throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
1120 throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
891 " nodes=" + lineDiv.childNodes.length);
1121 " nodes=" + lineDiv.childNodes.length);
892
1122
893 if (options.lineWrapping) {
1123 function checkHeights() {
894 maxWidth = scroller.clientWidth;
895 var curNode = lineDiv.firstChild, heightChanged = false;
1124 var curNode = lineDiv.firstChild, heightChanged = false;
896 doc.iter(showingFrom, showingTo, function(line) {
1125 doc.iter(showingFrom, showingTo, function(line) {
897 if (!line.hidden) {
1126 if (!line.hidden) {
@@ -903,21 +1132,26 b' var CodeMirror = (function() {'
903 }
1132 }
904 curNode = curNode.nextSibling;
1133 curNode = curNode.nextSibling;
905 });
1134 });
906 if (heightChanged)
1135 return heightChanged;
907 code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
1136 }
908 } else {
1137
909 if (maxWidth == null) maxWidth = stringWidth(maxLine);
1138 if (options.lineWrapping) {
910 if (maxWidth > scroller.clientWidth) {
1139 checkHeights();
911 lineSpace.style.width = maxWidth + "px";
1140 var scrollHeight = needsScrollbar();
912 // Needed to prevent odd wrapping/hiding of widgets placed in here.
1141 var shouldHaveScrollbar = scrollHeight ? "block" : "none";
913 code.style.width = "";
1142 if (scrollbar.style.display != shouldHaveScrollbar) {
914 code.style.width = scroller.scrollWidth + "px";
1143 scrollbar.style.display = shouldHaveScrollbar;
915 } else {
1144 if (scrollHeight) scrollbarInner.style.height = scrollHeight + "px";
916 lineSpace.style.width = code.style.width = "";
1145 checkHeights();
917 }
1146 }
918 }
1147 }
1148
919 gutter.style.display = gutterDisplay;
1149 gutter.style.display = gutterDisplay;
920 if (different || gutterDirty) updateGutter();
1150 if (different || gutterDirty) {
1151 // If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
1152 updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
1153 }
1154 updateVerticalScroll(scrollTop);
921 updateSelection();
1155 updateSelection();
922 if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
1156 if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
923 return true;
1157 return true;
@@ -965,16 +1199,17 b' var CodeMirror = (function() {'
965 }
1199 }
966 // This pass fills in the lines that actually changed.
1200 // This pass fills in the lines that actually changed.
967 var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
1201 var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
968 var scratch = targetDocument.createElement("div"), newElt;
1202 var scratch = document.createElement("div");
969 doc.iter(from, to, function(line) {
1203 doc.iter(from, to, function(line) {
970 if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
1204 if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
971 if (!nextIntact || nextIntact.from > j) {
1205 if (!nextIntact || nextIntact.from > j) {
972 if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
1206 if (line.hidden) var html = scratch.innerHTML = "<pre></pre>";
973 else {
1207 else {
974 var html = '<pre>' + line.getHTML(tabText) + '</pre>';
1208 var html = '<pre' + (line.className ? ' class="' + line.className + '"' : '') + '>'
1209 + line.getHTML(makeTab) + '</pre>';
975 // Kludge to make sure the styled element lies behind the selection (by z-index)
1210 // Kludge to make sure the styled element lies behind the selection (by z-index)
976 if (line.className)
1211 if (line.bgClassName)
977 html = '<div style="position: relative"><pre class="' + line.className +
1212 html = '<div style="position: relative"><pre class="' + line.bgClassName +
978 '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
1213 '" style="position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2">&#160;</pre>' + html + "</div>";
979 }
1214 }
980 scratch.innerHTML = html;
1215 scratch.innerHTML = html;
@@ -990,13 +1225,13 b' var CodeMirror = (function() {'
990 if (!options.gutter && !options.lineNumbers) return;
1225 if (!options.gutter && !options.lineNumbers) return;
991 var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
1226 var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
992 gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
1227 gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
993 var html = [], i = showingFrom;
1228 var html = [], i = showingFrom, normalNode;
994 doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
1229 doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
995 if (line.hidden) {
1230 if (line.hidden) {
996 html.push("<pre></pre>");
1231 html.push("<pre></pre>");
997 } else {
1232 } else {
998 var marker = line.gutterMarker;
1233 var marker = line.gutterMarker;
999 var text = options.lineNumbers ? i + options.firstLineNumber : null;
1234 var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
1000 if (marker && marker.text)
1235 if (marker && marker.text)
1001 text = marker.text.replace("%N%", text != null ? text : "");
1236 text = marker.text.replace("%N%", text != null ? text : "");
1002 else if (text == null)
1237 else if (text == null)
@@ -1004,17 +1239,24 b' var CodeMirror = (function() {'
1004 html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
1239 html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text);
1005 for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
1240 for (var j = 1; j < line.height; ++j) html.push("<br/>&#160;");
1006 html.push("</pre>");
1241 html.push("</pre>");
1242 if (!marker) normalNode = i;
1007 }
1243 }
1008 ++i;
1244 ++i;
1009 });
1245 });
1010 gutter.style.display = "none";
1246 gutter.style.display = "none";
1011 gutterText.innerHTML = html.join("");
1247 gutterText.innerHTML = html.join("");
1012 var minwidth = String(doc.size).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
1248 // Make sure scrolling doesn't cause number gutter size to pop
1013 while (val.length + pad.length < minwidth) pad += "\u00a0";
1249 if (normalNode != null && options.lineNumbers) {
1014 if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
1250 var node = gutterText.childNodes[normalNode - showingFrom];
1251 var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
1252 while (val.length + pad.length < minwidth) pad += "\u00a0";
1253 if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
1254 }
1015 gutter.style.display = "";
1255 gutter.style.display = "";
1256 var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
1016 lineSpace.style.marginLeft = gutter.offsetWidth + "px";
1257 lineSpace.style.marginLeft = gutter.offsetWidth + "px";
1017 gutterDirty = false;
1258 gutterDirty = false;
1259 return resized;
1018 }
1260 }
1019 function updateSelection() {
1261 function updateSelection() {
1020 var collapsed = posEq(sel.from, sel.to);
1262 var collapsed = posEq(sel.from, sel.to);
@@ -1031,20 +1273,24 b' var CodeMirror = (function() {'
1031 selectionDiv.style.display = "none";
1273 selectionDiv.style.display = "none";
1032 } else {
1274 } else {
1033 var sameLine = fromPos.y == toPos.y, html = "";
1275 var sameLine = fromPos.y == toPos.y, html = "";
1276 var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
1277 var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
1034 function add(left, top, right, height) {
1278 function add(left, top, right, height) {
1279 var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
1280 : "right: " + right + "px";
1035 html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
1281 html += '<div class="CodeMirror-selected" style="position: absolute; left: ' + left +
1036 'px; top: ' + top + 'px; right: ' + right + 'px; height: ' + height + 'px"></div>';
1282 'px; top: ' + top + 'px; ' + rstyle + '; height: ' + height + 'px"></div>';
1037 }
1283 }
1038 if (sel.from.ch && fromPos.y >= 0) {
1284 if (sel.from.ch && fromPos.y >= 0) {
1039 var right = sameLine ? lineSpace.clientWidth - toPos.x : 0;
1285 var right = sameLine ? clientWidth - toPos.x : 0;
1040 add(fromPos.x, fromPos.y, right, th);
1286 add(fromPos.x, fromPos.y, right, th);
1041 }
1287 }
1042 var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
1288 var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
1043 var middleHeight = Math.min(toPos.y, lineSpace.clientHeight) - middleStart;
1289 var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
1044 if (middleHeight > 0.2 * th)
1290 if (middleHeight > 0.2 * th)
1045 add(0, middleStart, 0, middleHeight);
1291 add(0, middleStart, 0, middleHeight);
1046 if ((!sameLine || !sel.from.ch) && toPos.y < lineSpace.clientHeight - .5 * th)
1292 if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
1047 add(0, toPos.y, lineSpace.clientWidth - toPos.x, th);
1293 add(0, toPos.y, clientWidth - toPos.x, th);
1048 selectionDiv.innerHTML = html;
1294 selectionDiv.innerHTML = html;
1049 cursor.style.display = "none";
1295 cursor.style.display = "none";
1050 selectionDiv.style.display = "";
1296 selectionDiv.style.display = "";
@@ -1074,13 +1320,32 b' var CodeMirror = (function() {'
1074 if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
1320 if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
1075
1321
1076 // Skip over hidden lines.
1322 // Skip over hidden lines.
1077 if (from.line != oldFrom) from = skipHidden(from, oldFrom, sel.from.ch);
1323 if (from.line != oldFrom) {
1324 var from1 = skipHidden(from, oldFrom, sel.from.ch);
1325 // If there is no non-hidden line left, force visibility on current line
1326 if (!from1) setLineHidden(from.line, false);
1327 else from = from1;
1328 }
1078 if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
1329 if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
1079
1330
1080 if (posEq(from, to)) sel.inverted = false;
1331 if (posEq(from, to)) sel.inverted = false;
1081 else if (posEq(from, sel.to)) sel.inverted = false;
1332 else if (posEq(from, sel.to)) sel.inverted = false;
1082 else if (posEq(to, sel.from)) sel.inverted = true;
1333 else if (posEq(to, sel.from)) sel.inverted = true;
1083
1334
1335 if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
1336 var head = sel.inverted ? from : to;
1337 if (head.line != sel.from.line && sel.from.line < doc.size) {
1338 var oldLine = getLine(sel.from.line);
1339 if (/^\s+$/.test(oldLine.text))
1340 setTimeout(operation(function() {
1341 if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
1342 var no = lineNo(oldLine);
1343 replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
1344 }
1345 }, 10));
1346 }
1347 }
1348
1084 sel.from = from; sel.to = to;
1349 sel.from = from; sel.to = to;
1085 selectionChanged = true;
1350 selectionChanged = true;
1086 }
1351 }
@@ -1091,13 +1356,14 b' var CodeMirror = (function() {'
1091 var line = getLine(lNo);
1356 var line = getLine(lNo);
1092 if (!line.hidden) {
1357 if (!line.hidden) {
1093 var ch = pos.ch;
1358 var ch = pos.ch;
1094 if (ch > oldCh || ch > line.text.length) ch = line.text.length;
1359 if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
1095 return {line: lNo, ch: ch};
1360 return {line: lNo, ch: ch};
1096 }
1361 }
1097 lNo += dir;
1362 lNo += dir;
1098 }
1363 }
1099 }
1364 }
1100 var line = getLine(pos.line);
1365 var line = getLine(pos.line);
1366 var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
1101 if (!line.hidden) return pos;
1367 if (!line.hidden) return pos;
1102 if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
1368 if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
1103 else return getNonHidden(-1) || getNonHidden(1);
1369 else return getNonHidden(-1) || getNonHidden(1);
@@ -1164,19 +1430,22 b' var CodeMirror = (function() {'
1164 if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
1430 if (unit == "page") dist = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
1165 else if (unit == "line") dist = textHeight();
1431 else if (unit == "line") dist = textHeight();
1166 var target = coordsChar(pos.x, pos.y + dist * dir + 2);
1432 var target = coordsChar(pos.x, pos.y + dist * dir + 2);
1433 if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
1167 setCursor(target.line, target.ch, true);
1434 setCursor(target.line, target.ch, true);
1168 goalColumn = pos.x;
1435 goalColumn = pos.x;
1169 }
1436 }
1170
1437
1171 function selectWordAt(pos) {
1438 function findWordAt(pos) {
1172 var line = getLine(pos.line).text;
1439 var line = getLine(pos.line).text;
1173 var start = pos.ch, end = pos.ch;
1440 var start = pos.ch, end = pos.ch;
1174 while (start > 0 && isWordChar(line.charAt(start - 1))) --start;
1441 var check = isWordChar(line.charAt(start < line.length ? start : start - 1)) ?
1175 while (end < line.length && isWordChar(line.charAt(end))) ++end;
1442 isWordChar : function(ch) {return !isWordChar(ch);};
1176 setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
1443 while (start > 0 && check(line.charAt(start - 1))) --start;
1444 while (end < line.length && check(line.charAt(end))) ++end;
1445 return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
1177 }
1446 }
1178 function selectLine(line) {
1447 function selectLine(line) {
1179 setSelectionUser({line: line, ch: 0}, {line: line, ch: getLine(line).text.length});
1448 setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
1180 }
1449 }
1181 function indentSelected(mode) {
1450 function indentSelected(mode) {
1182 if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
1451 if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
@@ -1193,26 +1462,23 b' var CodeMirror = (function() {'
1193
1462
1194 var line = getLine(n), curSpace = line.indentation(options.tabSize),
1463 var line = getLine(n), curSpace = line.indentation(options.tabSize),
1195 curSpaceString = line.text.match(/^\s*/)[0], indentation;
1464 curSpaceString = line.text.match(/^\s*/)[0], indentation;
1465 if (how == "smart") {
1466 indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
1467 if (indentation == Pass) how = "prev";
1468 }
1196 if (how == "prev") {
1469 if (how == "prev") {
1197 if (n) indentation = getLine(n-1).indentation(options.tabSize);
1470 if (n) indentation = getLine(n-1).indentation(options.tabSize);
1198 else indentation = 0;
1471 else indentation = 0;
1199 }
1472 }
1200 else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
1201 else if (how == "add") indentation = curSpace + options.indentUnit;
1473 else if (how == "add") indentation = curSpace + options.indentUnit;
1202 else if (how == "subtract") indentation = curSpace - options.indentUnit;
1474 else if (how == "subtract") indentation = curSpace - options.indentUnit;
1203 indentation = Math.max(0, indentation);
1475 indentation = Math.max(0, indentation);
1204 var diff = indentation - curSpace;
1476 var diff = indentation - curSpace;
1205
1477
1206 if (!diff) {
1478 var indentString = "", pos = 0;
1207 if (sel.from.line != n && sel.to.line != n) return;
1479 if (options.indentWithTabs)
1208 var indentString = curSpaceString;
1480 for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
1209 }
1481 while (pos < indentation) {++pos; indentString += " ";}
1210 else {
1211 var indentString = "", pos = 0;
1212 if (options.indentWithTabs)
1213 for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
1214 while (pos < indentation) {++pos; indentString += " ";}
1215 }
1216
1482
1217 replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1483 replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1218 }
1484 }
@@ -1239,9 +1505,10 b' var CodeMirror = (function() {'
1239 if (guess != 1) updateLineHeight(line, guess);
1505 if (guess != 1) updateLineHeight(line, guess);
1240 });
1506 });
1241 lineSpace.style.width = code.style.width = "";
1507 lineSpace.style.width = code.style.width = "";
1508 widthForcer.style.left = "";
1242 } else {
1509 } else {
1243 wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
1510 wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
1244 maxWidth = null; maxLine = "";
1511 maxLine = ""; maxLineChanged = true;
1245 doc.iter(0, doc.size, function(line) {
1512 doc.iter(0, doc.size, function(line) {
1246 if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
1513 if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
1247 if (line.text.length > maxLine.length) maxLine = line.text;
1514 if (line.text.length > maxLine.length) maxLine = line.text;
@@ -1249,18 +1516,21 b' var CodeMirror = (function() {'
1249 }
1516 }
1250 changes.push({from: 0, to: doc.size});
1517 changes.push({from: 0, to: doc.size});
1251 }
1518 }
1252 function computeTabText() {
1519 function makeTab(col) {
1253 for (var str = '<span class="cm-tab">', i = 0; i < options.tabSize; ++i) str += " ";
1520 var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
1254 return str + "</span>";
1521 if (cached) return cached;
1255 }
1522 for (var str = '<span class="cm-tab">', i = 0; i < w; ++i) str += " ";
1256 function tabsChanged() {
1523 return (tabCache[w] = {html: str + "</span>", width: w});
1257 tabText = computeTabText();
1258 updateDisplay(true);
1259 }
1524 }
1260 function themeChanged() {
1525 function themeChanged() {
1261 scroller.className = scroller.className.replace(/\s*cm-s-\w+/g, "") +
1526 scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
1262 options.theme.replace(/(^|\s)\s*/g, " cm-s-");
1527 options.theme.replace(/(^|\s)\s*/g, " cm-s-");
1263 }
1528 }
1529 function keyMapChanged() {
1530 var style = keyMap[options.keyMap].style;
1531 wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
1532 (style ? " cm-keymap-" + style : "");
1533 }
1264
1534
1265 function TextMarker() { this.set = []; }
1535 function TextMarker() { this.set = []; }
1266 TextMarker.prototype.clear = operation(function() {
1536 TextMarker.prototype.clear = operation(function() {
@@ -1271,7 +1541,7 b' var CodeMirror = (function() {'
1271 var lineN = lineNo(line);
1541 var lineN = lineNo(line);
1272 min = Math.min(min, lineN); max = Math.max(max, lineN);
1542 min = Math.min(min, lineN); max = Math.max(max, lineN);
1273 for (var j = 0; j < mk.length; ++j)
1543 for (var j = 0; j < mk.length; ++j)
1274 if (mk[j].set == this.set) mk.splice(j--, 1);
1544 if (mk[j].marker == this) mk.splice(j--, 1);
1275 }
1545 }
1276 if (min != Infinity)
1546 if (min != Infinity)
1277 changes.push({from: min, to: max + 1});
1547 changes.push({from: min, to: max + 1});
@@ -1282,7 +1552,7 b' var CodeMirror = (function() {'
1282 var line = this.set[i], mk = line.marked;
1552 var line = this.set[i], mk = line.marked;
1283 for (var j = 0; j < mk.length; ++j) {
1553 for (var j = 0; j < mk.length; ++j) {
1284 var mark = mk[j];
1554 var mark = mk[j];
1285 if (mark.set == this.set) {
1555 if (mark.marker == this) {
1286 if (mark.from != null || mark.to != null) {
1556 if (mark.from != null || mark.to != null) {
1287 var found = lineNo(line);
1557 var found = lineNo(line);
1288 if (found != null) {
1558 if (found != null) {
@@ -1299,8 +1569,9 b' var CodeMirror = (function() {'
1299 function markText(from, to, className) {
1569 function markText(from, to, className) {
1300 from = clipPos(from); to = clipPos(to);
1570 from = clipPos(from); to = clipPos(to);
1301 var tm = new TextMarker();
1571 var tm = new TextMarker();
1572 if (!posLess(from, to)) return tm;
1302 function add(line, from, to, className) {
1573 function add(line, from, to, className) {
1303 getLine(line).addMark(new MarkedText(from, to, className, tm.set));
1574 getLine(line).addMark(new MarkedText(from, to, className, tm));
1304 }
1575 }
1305 if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1576 if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1306 else {
1577 else {
@@ -1320,6 +1591,19 b' var CodeMirror = (function() {'
1320 return bm;
1591 return bm;
1321 }
1592 }
1322
1593
1594 function findMarksAt(pos) {
1595 pos = clipPos(pos);
1596 var markers = [], marked = getLine(pos.line).marked;
1597 if (!marked) return markers;
1598 for (var i = 0, e = marked.length; i < e; ++i) {
1599 var m = marked[i];
1600 if ((m.from == null || m.from <= pos.ch) &&
1601 (m.to == null || m.to >= pos.ch))
1602 markers.push(m.marker || m);
1603 }
1604 return markers;
1605 }
1606
1323 function addGutterMarker(line, text, className) {
1607 function addGutterMarker(line, text, className) {
1324 if (typeof line == "number") line = getLine(clipLine(line));
1608 if (typeof line == "number") line = getLine(clipLine(line));
1325 line.gutterMarker = {text: text, style: className};
1609 line.gutterMarker = {text: text, style: className};
@@ -1341,10 +1625,11 b' var CodeMirror = (function() {'
1341 else return null;
1625 else return null;
1342 return line;
1626 return line;
1343 }
1627 }
1344 function setLineClass(handle, className) {
1628 function setLineClass(handle, className, bgClassName) {
1345 return changeLine(handle, function(line) {
1629 return changeLine(handle, function(line) {
1346 if (line.className != className) {
1630 if (line.className != className || line.bgClassName != bgClassName) {
1347 line.className = className;
1631 line.className = className;
1632 line.bgClassName = bgClassName;
1348 return true;
1633 return true;
1349 }
1634 }
1350 });
1635 });
@@ -1353,11 +1638,21 b' var CodeMirror = (function() {'
1353 return changeLine(handle, function(line, no) {
1638 return changeLine(handle, function(line, no) {
1354 if (line.hidden != hidden) {
1639 if (line.hidden != hidden) {
1355 line.hidden = hidden;
1640 line.hidden = hidden;
1641 if (!options.lineWrapping) {
1642 var l = line.text;
1643 if (hidden && l.length == maxLine.length) {
1644 updateMaxLine = true;
1645 } else if (!hidden && l.length > maxLine.length) {
1646 maxLine = l; updateMaxLine = false;
1647 }
1648 }
1356 updateLineHeight(line, hidden ? 0 : 1);
1649 updateLineHeight(line, hidden ? 0 : 1);
1357 var fline = sel.from.line, tline = sel.to.line;
1650 var fline = sel.from.line, tline = sel.to.line;
1358 if (hidden && (fline == no || tline == no)) {
1651 if (hidden && (fline == no || tline == no)) {
1359 var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
1652 var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
1360 var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
1653 var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
1654 // Can't hide the last visible line, we'd have no place to put the cursor
1655 if (!to) return;
1361 setSelection(from, to);
1656 setSelection(from, to);
1362 }
1657 }
1363 return (gutterDirty = true);
1658 return (gutterDirty = true);
@@ -1371,14 +1666,13 b' var CodeMirror = (function() {'
1371 var n = line;
1666 var n = line;
1372 line = getLine(line);
1667 line = getLine(line);
1373 if (!line) return null;
1668 if (!line) return null;
1374 }
1669 } else {
1375 else {
1376 var n = lineNo(line);
1670 var n = lineNo(line);
1377 if (n == null) return null;
1671 if (n == null) return null;
1378 }
1672 }
1379 var marker = line.gutterMarker;
1673 var marker = line.gutterMarker;
1380 return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
1674 return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
1381 markerClass: marker && marker.style, lineClass: line.className};
1675 markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
1382 }
1676 }
1383
1677
1384 function stringWidth(str) {
1678 function stringWidth(str) {
@@ -1392,8 +1686,7 b' var CodeMirror = (function() {'
1392 if (x <= 0) return 0;
1686 if (x <= 0) return 0;
1393 var lineObj = getLine(line), text = lineObj.text;
1687 var lineObj = getLine(line), text = lineObj.text;
1394 function getX(len) {
1688 function getX(len) {
1395 measure.innerHTML = "<pre><span>" + lineObj.getHTML(tabText, len) + "</span></pre>";
1689 return measureLine(lineObj, len).left;
1396 return measure.firstChild.firstChild.offsetWidth;
1397 }
1690 }
1398 var from = 0, fromX = 0, to = text.length, toX;
1691 var from = 0, fromX = 0, to = text.length, toX;
1399 // Guess a suitable upper bound for our search.
1692 // Guess a suitable upper bound for our search.
@@ -1416,19 +1709,13 b' var CodeMirror = (function() {'
1416 }
1709 }
1417 }
1710 }
1418
1711
1419 var tempId = Math.floor(Math.random() * 0xffffff).toString(16);
1712 var tempId = "CodeMirror-temp-" + Math.floor(Math.random() * 0xffffff).toString(16);
1420 function measureLine(line, ch) {
1713 function measureLine(line, ch) {
1421 if (ch == 0) return {top: 0, left: 0};
1714 if (ch == 0) return {top: 0, left: 0};
1422 var extra = "";
1715 var wbr = options.lineWrapping && ch < line.text.length &&
1423 // Include extra text at the end to make sure the measured line is wrapped in the right way.
1716 spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1424 if (options.lineWrapping) {
1717 measure.innerHTML = "<pre>" + line.getHTML(makeTab, ch, tempId, wbr) + "</pre>";
1425 var end = line.text.indexOf(" ", ch + 2);
1718 var elt = document.getElementById(tempId);
1426 extra = htmlEscape(line.text.slice(ch + 1, end < 0 ? line.text.length : end + (ie ? 5 : 0)));
1427 }
1428 measure.innerHTML = "<pre>" + line.getHTML(tabText, ch) +
1429 '<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
1430 extra + "</pre>";
1431 var elt = document.getElementById("CodeMirror-temp-" + tempId);
1432 var top = elt.offsetTop, left = elt.offsetLeft;
1719 var top = elt.offsetTop, left = elt.offsetLeft;
1433 // Older IEs report zero offsets for spans directly after a wrap
1720 // Older IEs report zero offsets for spans directly after a wrap
1434 if (ie && top == 0 && left == 0) {
1721 if (ie && top == 0 && left == 0) {
@@ -1528,8 +1815,8 b' var CodeMirror = (function() {'
1528 return coordsChar(x - offL.left, y - offL.top);
1815 return coordsChar(x - offL.left, y - offL.top);
1529 }
1816 }
1530 function onContextMenu(e) {
1817 function onContextMenu(e) {
1531 var pos = posFromMouse(e);
1818 var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
1532 if (!pos || window.opera) return; // Opera is difficult.
1819 if (!pos || opera) return; // Opera is difficult.
1533 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1820 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1534 operation(setCursor)(pos.line, pos.ch);
1821 operation(setCursor)(pos.line, pos.ch);
1535
1822
@@ -1544,9 +1831,10 b' var CodeMirror = (function() {'
1544 selectInput(input);
1831 selectInput(input);
1545 function rehide() {
1832 function rehide() {
1546 var newVal = splitLines(input.value).join("\n");
1833 var newVal = splitLines(input.value).join("\n");
1547 if (newVal != val) operation(replaceSelection)(newVal, "end");
1834 if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
1548 inputDiv.style.position = "relative";
1835 inputDiv.style.position = "relative";
1549 input.style.cssText = oldCSS;
1836 input.style.cssText = oldCSS;
1837 if (ie_lt9) scrollbar.scrollTop = scrollPos;
1550 leaveInputAlone = false;
1838 leaveInputAlone = false;
1551 resetInput(true);
1839 resetInput(true);
1552 slowPoll();
1840 slowPoll();
@@ -1558,8 +1846,7 b' var CodeMirror = (function() {'
1558 mouseup();
1846 mouseup();
1559 setTimeout(rehide, 20);
1847 setTimeout(rehide, 20);
1560 }, true);
1848 }, true);
1561 }
1849 } else {
1562 else {
1563 setTimeout(rehide, 50);
1850 setTimeout(rehide, 50);
1564 }
1851 }
1565 }
1852 }
@@ -1589,7 +1876,7 b' var CodeMirror = (function() {'
1589 var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1876 var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1590 for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1877 for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1591 var text = st[i];
1878 var text = st[i];
1592 if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1879 if (st[i+1] != style) {pos += d * text.length; continue;}
1593 for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1880 for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1594 if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1881 if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1595 var match = matching[cur];
1882 var match = matching[cur];
@@ -1676,13 +1963,17 b' var CodeMirror = (function() {'
1676 var changed = line.highlight(mode, state, options.tabSize);
1963 var changed = line.highlight(mode, state, options.tabSize);
1677 if (changed) realChange = true;
1964 if (changed) realChange = true;
1678 line.stateAfter = copyState(mode, state);
1965 line.stateAfter = copyState(mode, state);
1966 var done = null;
1679 if (compare) {
1967 if (compare) {
1680 if (hadState && compare(hadState, state)) return true;
1968 var same = hadState && compare(hadState, state);
1681 } else {
1969 if (same != Pass) done = !!same;
1970 }
1971 if (done == null) {
1682 if (changed !== false || !hadState) unchanged = 0;
1972 if (changed !== false || !hadState) unchanged = 0;
1683 else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1973 else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1684 return true;
1974 done = true;
1685 }
1975 }
1976 if (done) return true;
1686 ++i;
1977 ++i;
1687 });
1978 });
1688 if (bail) return;
1979 if (bail) return;
@@ -1705,14 +1996,24 b' var CodeMirror = (function() {'
1705 changes = []; selectionChanged = false; callbacks = [];
1996 changes = []; selectionChanged = false; callbacks = [];
1706 }
1997 }
1707 function endOperation() {
1998 function endOperation() {
1708 var reScroll = false, updated;
1999 if (updateMaxLine) computeMaxLength();
1709 if (selectionChanged) reScroll = !scrollCursorIntoView();
2000 if (maxLineChanged && !options.lineWrapping) {
1710 if (changes.length) updated = updateDisplay(changes, true);
2001 var cursorWidth = widthForcer.offsetWidth, left = stringWidth(maxLine);
2002 widthForcer.style.left = left + "px";
2003 lineSpace.style.minWidth = (left + cursorWidth) + "px";
2004 maxLineChanged = false;
2005 }
2006 var newScrollPos, updated;
2007 if (selectionChanged) {
2008 var coords = calculateCursorCoords();
2009 newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
2010 }
2011 if (changes.length) updated = updateDisplay(changes, true, (newScrollPos ? newScrollPos.scrollTop : null));
1711 else {
2012 else {
1712 if (selectionChanged) updateSelection();
2013 if (selectionChanged) updateSelection();
1713 if (gutterDirty) updateGutter();
2014 if (gutterDirty) updateGutter();
1714 }
2015 }
1715 if (reScroll) scrollCursorIntoView();
2016 if (newScrollPos) scrollCursorIntoView();
1716 if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
2017 if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1717
2018
1718 if (focused && !leaveInputAlone &&
2019 if (focused && !leaveInputAlone &&
@@ -1724,11 +2025,11 b' var CodeMirror = (function() {'
1724 if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
2025 if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1725 if (posEq(sel.from, sel.to)) matchBrackets(false);
2026 if (posEq(sel.from, sel.to)) matchBrackets(false);
1726 }), 20);
2027 }), 20);
1727 var tc = textChanged, cbs = callbacks; // these can be reset by callbacks
2028 var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
1728 if (selectionChanged && options.onCursorActivity)
2029 if (textChanged && options.onChange && instance)
2030 options.onChange(instance, textChanged);
2031 if (sc && options.onCursorActivity)
1729 options.onCursorActivity(instance);
2032 options.onCursorActivity(instance);
1730 if (tc && options.onChange && instance)
1731 options.onChange(instance, tc);
1732 for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
2033 for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
1733 if (updated && options.onUpdate) options.onUpdate(instance);
2034 if (updated && options.onUpdate) options.onUpdate(instance);
1734 }
2035 }
@@ -1742,6 +2043,11 b' var CodeMirror = (function() {'
1742 };
2043 };
1743 }
2044 }
1744
2045
2046 function compoundChange(f) {
2047 history.startCompound();
2048 try { return f(); } finally { history.endCompound(); }
2049 }
2050
1745 for (var ext in extensions)
2051 for (var ext in extensions)
1746 if (extensions.propertyIsEnumerable(ext) &&
2052 if (extensions.propertyIsEnumerable(ext) &&
1747 !instance.propertyIsEnumerable(ext))
2053 !instance.propertyIsEnumerable(ext))
@@ -1761,13 +2067,16 b' var CodeMirror = (function() {'
1761 keyMap: "default",
2067 keyMap: "default",
1762 extraKeys: null,
2068 extraKeys: null,
1763 electricChars: true,
2069 electricChars: true,
2070 autoClearEmptyLines: false,
1764 onKeyEvent: null,
2071 onKeyEvent: null,
2072 onDragEvent: null,
1765 lineWrapping: false,
2073 lineWrapping: false,
1766 lineNumbers: false,
2074 lineNumbers: false,
1767 gutter: false,
2075 gutter: false,
1768 fixedGutter: false,
2076 fixedGutter: false,
1769 firstLineNumber: 1,
2077 firstLineNumber: 1,
1770 readOnly: false,
2078 readOnly: false,
2079 dragDrop: true,
1771 onChange: null,
2080 onChange: null,
1772 onCursorActivity: null,
2081 onCursorActivity: null,
1773 onGutterClick: null,
2082 onGutterClick: null,
@@ -1780,7 +2089,8 b' var CodeMirror = (function() {'
1780 pollInterval: 100,
2089 pollInterval: 100,
1781 undoDepth: 40,
2090 undoDepth: 40,
1782 tabindex: null,
2091 tabindex: null,
1783 document: window.document
2092 autofocus: null,
2093 lineNumberFormatter: function(integer) { return integer; }
1784 };
2094 };
1785
2095
1786 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
2096 var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
@@ -1788,27 +2098,31 b' var CodeMirror = (function() {'
1788 var win = /Win/.test(navigator.platform);
2098 var win = /Win/.test(navigator.platform);
1789
2099
1790 // Known modes, by name and by MIME
2100 // Known modes, by name and by MIME
1791 var modes = {}, mimeModes = {};
2101 var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
1792 CodeMirror.defineMode = function(name, mode) {
2102 CodeMirror.defineMode = function(name, mode) {
1793 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
2103 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
2104 if (arguments.length > 2) {
2105 mode.dependencies = [];
2106 for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
2107 }
1794 modes[name] = mode;
2108 modes[name] = mode;
1795 };
2109 };
1796 CodeMirror.defineMIME = function(mime, spec) {
2110 CodeMirror.defineMIME = function(mime, spec) {
1797 mimeModes[mime] = spec;
2111 mimeModes[mime] = spec;
1798 };
2112 };
1799 CodeMirror.getMode = function(options, spec) {
2113 CodeMirror.resolveMode = function(spec) {
1800 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
2114 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1801 spec = mimeModes[spec];
2115 spec = mimeModes[spec];
1802 if (typeof spec == "string")
2116 else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
1803 var mname = spec, config = {};
2117 return CodeMirror.resolveMode("application/xml");
1804 else if (spec != null)
2118 if (typeof spec == "string") return {name: spec};
1805 var mname = spec.name, config = spec;
2119 else return spec || {name: "null"};
1806 var mfactory = modes[mname];
2120 };
1807 if (!mfactory) {
2121 CodeMirror.getMode = function(options, spec) {
1808 if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
2122 var spec = CodeMirror.resolveMode(spec);
1809 return CodeMirror.getMode(options, "text/plain");
2123 var mfactory = modes[spec.name];
1810 }
2124 if (!mfactory) return CodeMirror.getMode(options, "text/plain");
1811 return mfactory(options, config || {});
2125 return mfactory(options, spec);
1812 };
2126 };
1813 CodeMirror.listModes = function() {
2127 CodeMirror.listModes = function() {
1814 var list = [];
2128 var list = [];
@@ -1865,6 +2179,10 b' var CodeMirror = (function() {'
1865 indentMore: function(cm) {cm.indentSelection("add");},
2179 indentMore: function(cm) {cm.indentSelection("add");},
1866 indentLess: function(cm) {cm.indentSelection("subtract");},
2180 indentLess: function(cm) {cm.indentSelection("subtract");},
1867 insertTab: function(cm) {cm.replaceSelection("\t", "end");},
2181 insertTab: function(cm) {cm.replaceSelection("\t", "end");},
2182 defaultTab: function(cm) {
2183 if (cm.somethingSelected()) cm.indentSelection("add");
2184 else cm.replaceSelection("\t", "end");
2185 },
1868 transposeChars: function(cm) {
2186 transposeChars: function(cm) {
1869 var cur = cm.getCursor(), line = cm.getLine(cur.line);
2187 var cur = cm.getCursor(), line = cm.getLine(cur.line);
1870 if (cur.ch > 0 && cur.ch < line.length - 1)
2188 if (cur.ch > 0 && cur.ch < line.length - 1)
@@ -1882,7 +2200,7 b' var CodeMirror = (function() {'
1882 keyMap.basic = {
2200 keyMap.basic = {
1883 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
2201 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
1884 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
2202 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
1885 "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "indentMore", "Shift-Tab": "indentLess",
2203 "Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
1886 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
2204 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
1887 };
2205 };
1888 // Note that the save and find-related commands aren't defined by
2206 // Note that the save and find-related commands aren't defined by
@@ -1893,6 +2211,7 b' var CodeMirror = (function() {'
1893 "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
2211 "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
1894 "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
2212 "Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
1895 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
2213 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
2214 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
1896 fallthrough: "basic"
2215 fallthrough: "basic"
1897 };
2216 };
1898 keyMap.macDefault = {
2217 keyMap.macDefault = {
@@ -1901,6 +2220,7 b' var CodeMirror = (function() {'
1901 "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
2220 "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
1902 "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
2221 "Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
1903 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
2222 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
2223 "Cmd-[": "indentLess", "Cmd-]": "indentMore",
1904 fallthrough: ["basic", "emacsy"]
2224 fallthrough: ["basic", "emacsy"]
1905 };
2225 };
1906 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
2226 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
@@ -1911,20 +2231,30 b' var CodeMirror = (function() {'
1911 "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
2231 "Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
1912 };
2232 };
1913
2233
1914 function lookupKey(name, extraMap, map) {
2234 function getKeyMap(val) {
1915 function lookup(name, map, ft) {
2235 if (typeof val == "string") return keyMap[val];
2236 else return val;
2237 }
2238 function lookupKey(name, extraMap, map, handle, stop) {
2239 function lookup(map) {
2240 map = getKeyMap(map);
1916 var found = map[name];
2241 var found = map[name];
1917 if (found != null) return found;
2242 if (found != null && handle(found)) return true;
1918 if (ft == null) ft = map.fallthrough;
2243 if (map.nofallthrough) {
1919 if (ft == null) return map.catchall;
2244 if (stop) stop();
1920 if (typeof ft == "string") return lookup(name, keyMap[ft]);
2245 return true;
1921 for (var i = 0, e = ft.length; i < e; ++i) {
1922 found = lookup(name, keyMap[ft[i]]);
1923 if (found != null) return found;
1924 }
2246 }
1925 return null;
2247 var fallthrough = map.fallthrough;
2248 if (fallthrough == null) return false;
2249 if (Object.prototype.toString.call(fallthrough) != "[object Array]")
2250 return lookup(fallthrough);
2251 for (var i = 0, e = fallthrough.length; i < e; ++i) {
2252 if (lookup(fallthrough[i])) return true;
2253 }
2254 return false;
1926 }
2255 }
1927 return extraMap ? lookup(name, extraMap, map) : lookup(name, keyMap[map]);
2256 if (extraMap && lookup(extraMap)) return true;
2257 return lookup(map);
1928 }
2258 }
1929 function isModifierKey(event) {
2259 function isModifierKey(event) {
1930 var name = keyNames[e_prop(event, "keyCode")];
2260 var name = keyNames[e_prop(event, "keyCode")];
@@ -1936,6 +2266,8 b' var CodeMirror = (function() {'
1936 options.value = textarea.value;
2266 options.value = textarea.value;
1937 if (!options.tabindex && textarea.tabindex)
2267 if (!options.tabindex && textarea.tabindex)
1938 options.tabindex = textarea.tabindex;
2268 options.tabindex = textarea.tabindex;
2269 if (options.autofocus == null && textarea.getAttribute("autofocus") != null)
2270 options.autofocus = true;
1939
2271
1940 function save() {textarea.value = instance.getValue();}
2272 function save() {textarea.value = instance.getValue();}
1941 if (textarea.form) {
2273 if (textarea.form) {
@@ -2036,8 +2368,7 b' var CodeMirror = (function() {'
2036 if (consume !== false) this.pos += pattern.length;
2368 if (consume !== false) this.pos += pattern.length;
2037 return true;
2369 return true;
2038 }
2370 }
2039 }
2371 } else {
2040 else {
2041 var match = this.string.slice(this.pos).match(pattern);
2372 var match = this.string.slice(this.pos).match(pattern);
2042 if (match && consume !== false) this.pos += match[0].length;
2373 if (match && consume !== false) this.pos += match[0].length;
2043 return match;
2374 return match;
@@ -2047,34 +2378,34 b' var CodeMirror = (function() {'
2047 };
2378 };
2048 CodeMirror.StringStream = StringStream;
2379 CodeMirror.StringStream = StringStream;
2049
2380
2050 function MarkedText(from, to, className, set) {
2381 function MarkedText(from, to, className, marker) {
2051 this.from = from; this.to = to; this.style = className; this.set = set;
2382 this.from = from; this.to = to; this.style = className; this.marker = marker;
2052 }
2383 }
2053 MarkedText.prototype = {
2384 MarkedText.prototype = {
2054 attach: function(line) { this.set.push(line); },
2385 attach: function(line) { this.marker.set.push(line); },
2055 detach: function(line) {
2386 detach: function(line) {
2056 var ix = indexOf(this.set, line);
2387 var ix = indexOf(this.marker.set, line);
2057 if (ix > -1) this.set.splice(ix, 1);
2388 if (ix > -1) this.marker.set.splice(ix, 1);
2058 },
2389 },
2059 split: function(pos, lenBefore) {
2390 split: function(pos, lenBefore) {
2060 if (this.to <= pos && this.to != null) return null;
2391 if (this.to <= pos && this.to != null) return null;
2061 var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
2392 var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
2062 var to = this.to == null ? null : this.to - pos + lenBefore;
2393 var to = this.to == null ? null : this.to - pos + lenBefore;
2063 return new MarkedText(from, to, this.style, this.set);
2394 return new MarkedText(from, to, this.style, this.marker);
2064 },
2395 },
2065 dup: function() { return new MarkedText(null, null, this.style, this.set); },
2396 dup: function() { return new MarkedText(null, null, this.style, this.marker); },
2066 clipTo: function(fromOpen, from, toOpen, to, diff) {
2397 clipTo: function(fromOpen, from, toOpen, to, diff) {
2067 if (this.from != null && this.from >= from)
2068 this.from = Math.max(to, this.from) + diff;
2069 if (this.to != null && this.to > from)
2070 this.to = to < this.to ? this.to + diff : from;
2071 if (fromOpen && to > this.from && (to < this.to || this.to == null))
2398 if (fromOpen && to > this.from && (to < this.to || this.to == null))
2072 this.from = null;
2399 this.from = null;
2400 else if (this.from != null && this.from >= from)
2401 this.from = Math.max(to, this.from) + diff;
2073 if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
2402 if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
2074 this.to = null;
2403 this.to = null;
2404 else if (this.to != null && this.to > from)
2405 this.to = to < this.to ? this.to + diff : from;
2075 },
2406 },
2076 isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
2407 isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
2077 sameSet: function(x) { return this.set == x.set; }
2408 sameSet: function(x) { return this.marker == x.marker; }
2078 };
2409 };
2079
2410
2080 function Bookmark(pos) {
2411 function Bookmark(pos) {
@@ -2117,7 +2448,7 b' var CodeMirror = (function() {'
2117 this.styles = styles || [text, null];
2448 this.styles = styles || [text, null];
2118 this.text = text;
2449 this.text = text;
2119 this.height = 1;
2450 this.height = 1;
2120 this.marked = this.gutterMarker = this.className = this.handlers = null;
2451 this.marked = this.gutterMarker = this.className = this.bgClassName = this.handlers = null;
2121 this.stateAfter = this.parent = this.hidden = null;
2452 this.stateAfter = this.parent = this.hidden = null;
2122 }
2453 }
2123 Line.inheritMarks = function(text, orig) {
2454 Line.inheritMarks = function(text, orig) {
@@ -2163,6 +2494,7 b' var CodeMirror = (function() {'
2163 if (newmark) {
2494 if (newmark) {
2164 if (!taken.marked) taken.marked = [];
2495 if (!taken.marked) taken.marked = [];
2165 taken.marked.push(newmark); newmark.attach(taken);
2496 taken.marked.push(newmark); newmark.attach(taken);
2497 if (newmark == mark) mk.splice(i--, 1);
2166 }
2498 }
2167 }
2499 }
2168 }
2500 }
@@ -2203,11 +2535,20 b' var CodeMirror = (function() {'
2203 fixMarkEnds: function(other) {
2535 fixMarkEnds: function(other) {
2204 var mk = this.marked, omk = other.marked;
2536 var mk = this.marked, omk = other.marked;
2205 if (!mk) return;
2537 if (!mk) return;
2206 for (var i = 0; i < mk.length; ++i) {
2538 outer: for (var i = 0; i < mk.length; ++i) {
2207 var mark = mk[i], close = mark.to == null;
2539 var mark = mk[i], close = mark.to == null;
2208 if (close && omk) {
2540 if (close && omk) {
2209 for (var j = 0; j < omk.length; ++j)
2541 for (var j = 0; j < omk.length; ++j) {
2210 if (omk[j].sameSet(mark)) {close = false; break;}
2542 var om = omk[j];
2543 if (!om.sameSet(mark) || om.from != null) continue
2544 if (mark.from == this.text.length && om.to == 0) {
2545 omk.splice(j, 1);
2546 mk.splice(i--, 1);
2547 continue outer;
2548 } else {
2549 close = false; break;
2550 }
2551 }
2211 }
2552 }
2212 if (close) mark.to = this.text.length;
2553 if (close) mark.to = this.text.length;
2213 }
2554 }
@@ -2272,34 +2613,87 b' var CodeMirror = (function() {'
2272 indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2613 indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2273 // Produces an HTML fragment for the line, taking selection,
2614 // Produces an HTML fragment for the line, taking selection,
2274 // marking, and highlighting into account.
2615 // marking, and highlighting into account.
2275 getHTML: function(tabText, endAt) {
2616 getHTML: function(makeTab, wrapAt, wrapId, wrapWBR) {
2276 var html = [], first = true;
2617 var html = [], first = true, col = 0;
2277 function span(text, style) {
2618 function span_(text, style) {
2278 if (!text) return;
2619 if (!text) return;
2279 // Work around a bug where, in some compat modes, IE ignores leading spaces
2620 // Work around a bug where, in some compat modes, IE ignores leading spaces
2280 if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
2621 if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
2281 first = false;
2622 first = false;
2282 if (style) html.push('<span class="', style, '">', htmlEscape(text).replace(/\t/g, tabText), "</span>");
2623 if (text.indexOf("\t") == -1) {
2283 else html.push(htmlEscape(text).replace(/\t/g, tabText));
2624 col += text.length;
2625 var escaped = htmlEscape(text);
2626 } else {
2627 var escaped = "";
2628 for (var pos = 0;;) {
2629 var idx = text.indexOf("\t", pos);
2630 if (idx == -1) {
2631 escaped += htmlEscape(text.slice(pos));
2632 col += text.length - pos;
2633 break;
2634 } else {
2635 col += idx - pos;
2636 var tab = makeTab(col);
2637 escaped += htmlEscape(text.slice(pos, idx)) + tab.html;
2638 col += tab.width;
2639 pos = idx + 1;
2640 }
2641 }
2642 }
2643 if (style) html.push('<span class="', style, '">', escaped, "</span>");
2644 else html.push(escaped);
2645 }
2646 var span = span_;
2647 if (wrapAt != null) {
2648 var outPos = 0, open = "<span id=\"" + wrapId + "\">";
2649 span = function(text, style) {
2650 var l = text.length;
2651 if (wrapAt >= outPos && wrapAt < outPos + l) {
2652 if (wrapAt > outPos) {
2653 span_(text.slice(0, wrapAt - outPos), style);
2654 // See comment at the definition of spanAffectsWrapping
2655 if (wrapWBR) html.push("<wbr>");
2656 }
2657 html.push(open);
2658 var cut = wrapAt - outPos;
2659 span_(opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
2660 html.push("</span>");
2661 if (opera) span_(text.slice(cut + 1), style);
2662 wrapAt--;
2663 outPos += l;
2664 } else {
2665 outPos += l;
2666 span_(text, style);
2667 // Output empty wrapper when at end of line
2668 // (Gecko and IE8+ do strange wrapping when adding a space
2669 // to the end of the line. Other browsers don't react well
2670 // to zero-width spaces. So we do hideous browser sniffing
2671 // to determine which to use.)
2672 if (outPos == wrapAt && outPos == len)
2673 html.push(open + (gecko || (ie && !ie_lt8) ? "&#x200b;" : " ") + "</span>");
2674 // Stop outputting HTML when gone sufficiently far beyond measure
2675 else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
2676 }
2677 }
2284 }
2678 }
2679
2285 var st = this.styles, allText = this.text, marked = this.marked;
2680 var st = this.styles, allText = this.text, marked = this.marked;
2286 var len = allText.length;
2681 var len = allText.length;
2287 if (endAt != null) len = Math.min(endAt, len);
2288 function styleToClass(style) {
2682 function styleToClass(style) {
2289 if (!style) return null;
2683 if (!style) return null;
2290 return "cm-" + style.replace(/ +/g, " cm-");
2684 return "cm-" + style.replace(/ +/g, " cm-");
2291 }
2685 }
2292
2686
2293 if (!allText && endAt == null)
2687 if (!allText && wrapAt == null) {
2294 span(" ");
2688 span(" ");
2295 else if (!marked || !marked.length)
2689 } else if (!marked || !marked.length) {
2296 for (var i = 0, ch = 0; ch < len; i+=2) {
2690 for (var i = 0, ch = 0; ch < len; i+=2) {
2297 var str = st[i], style = st[i+1], l = str.length;
2691 var str = st[i], style = st[i+1], l = str.length;
2298 if (ch + l > len) str = str.slice(0, len - ch);
2692 if (ch + l > len) str = str.slice(0, len - ch);
2299 ch += l;
2693 ch += l;
2300 span(str, styleToClass(style));
2694 span(str, styleToClass(style));
2301 }
2695 }
2302 else {
2696 } else {
2303 var pos = 0, i = 0, text = "", style, sg = 0;
2697 var pos = 0, i = 0, text = "", style, sg = 0;
2304 var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2698 var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2305 function advanceMarks() {
2699 function advanceMarks() {
@@ -2311,7 +2705,8 b' var CodeMirror = (function() {'
2311 }
2705 }
2312 nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
2706 nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
2313 for (var i = 0; i < marks.length; ++i) {
2707 for (var i = 0; i < marks.length; ++i) {
2314 var to = marks[i].to || Infinity;
2708 var to = marks[i].to;
2709 if (to == null) to = Infinity;
2315 if (to == pos) marks.splice(i--, 1);
2710 if (to == pos) marks.splice(i--, 1);
2316 else nextChange = Math.min(to, nextChange);
2711 else nextChange = Math.min(to, nextChange);
2317 }
2712 }
@@ -2349,8 +2744,7 b' var CodeMirror = (function() {'
2349 if (state == 0) {
2744 if (state == 0) {
2350 if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
2745 if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
2351 if (end >= from) state = 1;
2746 if (end >= from) state = 1;
2352 }
2747 } else if (state == 1) {
2353 else if (state == 1) {
2354 if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
2748 if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
2355 else dest.push(part, source[i+1]);
2749 else dest.push(part, source[i+1]);
2356 }
2750 }
@@ -2385,7 +2779,7 b' var CodeMirror = (function() {'
2385 },
2779 },
2386 insertHeight: function(at, lines, height) {
2780 insertHeight: function(at, lines, height) {
2387 this.height += height;
2781 this.height += height;
2388 this.lines.splice.apply(this.lines, [at, 0].concat(lines));
2782 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
2389 for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
2783 for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
2390 },
2784 },
2391 iterN: function(at, n, op) {
2785 iterN: function(at, n, op) {
@@ -2551,33 +2945,36 b' var CodeMirror = (function() {'
2551 function History() {
2945 function History() {
2552 this.time = 0;
2946 this.time = 0;
2553 this.done = []; this.undone = [];
2947 this.done = []; this.undone = [];
2948 this.compound = 0;
2949 this.closed = false;
2554 }
2950 }
2555 History.prototype = {
2951 History.prototype = {
2556 addChange: function(start, added, old) {
2952 addChange: function(start, added, old) {
2557 this.undone.length = 0;
2953 this.undone.length = 0;
2558 var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2954 var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2559 var dtime = time - this.time;
2955 var dtime = time - this.time;
2560 if (dtime > 400 || !last) {
2956
2561 this.done.push([{start: start, added: added, old: old}]);
2957 if (this.compound && cur && !this.closed) {
2562 } else if (last.start > start + added || last.start + last.added < start - last.added + last.old.length) {
2563 cur.push({start: start, added: added, old: old});
2958 cur.push({start: start, added: added, old: old});
2959 } else if (dtime > 400 || !last || this.closed ||
2960 last.start > start + old.length || last.start + last.added < start) {
2961 this.done.push([{start: start, added: added, old: old}]);
2962 this.closed = false;
2564 } else {
2963 } else {
2565 var oldoff = 0;
2964 var startBefore = Math.max(0, last.start - start),
2566 if (start < last.start) {
2965 endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
2567 for (var i = last.start - start - 1; i >= 0; --i)
2966 for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
2568 last.old.unshift(old[i]);
2967 for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
2569 last.added += last.start - start;
2968 if (startBefore) last.start = start;
2570 last.start = start;
2969 last.added += added - (old.length - startBefore - endAfter);
2571 }
2572 else if (last.start < start) {
2573 oldoff = start - last.start;
2574 added += oldoff;
2575 }
2576 for (var i = last.added - oldoff, e = old.length; i < e; ++i)
2577 last.old.push(old[i]);
2578 if (last.added < added) last.added = added;
2579 }
2970 }
2580 this.time = time;
2971 this.time = time;
2972 },
2973 startCompound: function() {
2974 if (!this.compound++) this.closed = true;
2975 },
2976 endCompound: function() {
2977 if (!--this.compound) this.closed = true;
2581 }
2978 }
2582 };
2979 };
2583
2980
@@ -2603,10 +3000,14 b' var CodeMirror = (function() {'
2603
3000
2604 function e_target(e) {return e.target || e.srcElement;}
3001 function e_target(e) {return e.target || e.srcElement;}
2605 function e_button(e) {
3002 function e_button(e) {
2606 if (e.which) return e.which;
3003 var b = e.which;
2607 else if (e.button & 1) return 1;
3004 if (b == null) {
2608 else if (e.button & 2) return 3;
3005 if (e.button & 1) b = 1;
2609 else if (e.button & 4) return 2;
3006 else if (e.button & 2) b = 3;
3007 else if (e.button & 4) b = 2;
3008 }
3009 if (mac && e.ctrlKey && b == 1) b = 3;
3010 return b;
2610 }
3011 }
2611
3012
2612 // Allow 3rd-party code to override event properties by adding an override
3013 // Allow 3rd-party code to override event properties by adding an override
@@ -2622,8 +3023,7 b' var CodeMirror = (function() {'
2622 if (typeof node.addEventListener == "function") {
3023 if (typeof node.addEventListener == "function") {
2623 node.addEventListener(type, handler, false);
3024 node.addEventListener(type, handler, false);
2624 if (disconnect) return function() {node.removeEventListener(type, handler, false);};
3025 if (disconnect) return function() {node.removeEventListener(type, handler, false);};
2625 }
3026 } else {
2626 else {
2627 var wrapHandler = function(event) {handler(event || window.event);};
3027 var wrapHandler = function(event) {handler(event || window.event);};
2628 node.attachEvent("on" + type, wrapHandler);
3028 node.attachEvent("on" + type, wrapHandler);
2629 if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
3029 if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
@@ -2634,26 +3034,48 b' var CodeMirror = (function() {'
2634 function Delayed() {this.id = null;}
3034 function Delayed() {this.id = null;}
2635 Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
3035 Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
2636
3036
2637 // Detect drag-and-drop
3037 var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
2638 var dragAndDrop = function() {
2639 // IE8 has ondragstart and ondrop properties, but doesn't seem to
2640 // actually support ondragstart the way it's supposed to work.
2641 if (/MSIE [1-8]\b/.test(navigator.userAgent)) return false;
2642 var div = document.createElement('div');
2643 return "draggable" in div;
2644 }();
2645
3038
2646 var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
3039 var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
2647 var ie = /MSIE \d/.test(navigator.userAgent);
3040 var ie = /MSIE \d/.test(navigator.userAgent);
3041 var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
3042 var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
3043 var quirksMode = ie && document.documentMode == 5;
2648 var webkit = /WebKit\//.test(navigator.userAgent);
3044 var webkit = /WebKit\//.test(navigator.userAgent);
3045 var chrome = /Chrome\//.test(navigator.userAgent);
3046 var opera = /Opera\//.test(navigator.userAgent);
3047 var safari = /Apple Computer/.test(navigator.vendor);
3048 var khtml = /KHTML\//.test(navigator.userAgent);
3049 var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
3050
3051 // Detect drag-and-drop
3052 var dragAndDrop = function() {
3053 // There is *some* kind of drag-and-drop support in IE6-8, but I
3054 // couldn't get it to work yet.
3055 if (ie_lt9) return false;
3056 var div = document.createElement('div');
3057 return "draggable" in div || "dragDrop" in div;
3058 }();
2649
3059
2650 var lineSep = "\n";
2651 // Feature-detect whether newlines in textareas are converted to \r\n
3060 // Feature-detect whether newlines in textareas are converted to \r\n
2652 (function () {
3061 var lineSep = function () {
2653 var te = document.createElement("textarea");
3062 var te = document.createElement("textarea");
2654 te.value = "foo\nbar";
3063 te.value = "foo\nbar";
2655 if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
3064 if (te.value.indexOf("\r") > -1) return "\r\n";
2656 }());
3065 return "\n";
3066 }();
3067
3068 // For a reason I have yet to figure out, some browsers disallow
3069 // word wrapping between certain characters *only* if a new inline
3070 // element is started between them. This makes it hard to reliably
3071 // measure the position of things, since that requires inserting an
3072 // extra span. This terribly fragile set of regexps matches the
3073 // character combinations that suffer from this phenomenon on the
3074 // various browsers.
3075 var spanAffectsWrapping = /^$/; // Won't match any two-character string
3076 if (gecko) spanAffectsWrapping = /$'/;
3077 else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
3078 else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
2657
3079
2658 // Counts the column offset in a string, taking tabs into account.
3080 // Counts the column offset in a string, taking tabs into account.
2659 // Used mostly to find indentation.
3081 // Used mostly to find indentation.
@@ -2674,26 +3096,7 b' var CodeMirror = (function() {'
2674 return window.getComputedStyle(elt, null);
3096 return window.getComputedStyle(elt, null);
2675 }
3097 }
2676
3098
2677 // Find the position of an element by following the offsetParent chain.
2678 // If screen==true, it returns screen (rather than page) coordinates.
2679 function eltOffset(node, screen) {
3099 function eltOffset(node, screen) {
2680 var bod = node.ownerDocument.body;
2681 var x = 0, y = 0, skipBody = false;
2682 for (var n = node; n; n = n.offsetParent) {
2683 var ol = n.offsetLeft, ot = n.offsetTop;
2684 // Firefox reports weird inverted offsets when the body has a border.
2685 if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); }
2686 else { x += ol, y += ot; }
2687 if (screen && computedStyle(n).position == "fixed")
2688 skipBody = true;
2689 }
2690 var e = screen && !skipBody ? null : bod;
2691 for (var n = node.parentNode; n != e; n = n.parentNode)
2692 if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
2693 return {left: x, top: y};
2694 }
2695 // Use the faster and saner getBoundingClientRect method when possible.
2696 if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) {
2697 // Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
3100 // Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
2698 // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
3101 // since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
2699 try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
3102 try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
@@ -2709,7 +3112,7 b' var CodeMirror = (function() {'
2709 }
3112 }
2710 }
3113 }
2711 return box;
3114 return box;
2712 };
3115 }
2713
3116
2714 // Get a node's text content.
3117 // Get a node's text content.
2715 function eltText(node) {
3118 function eltText(node) {
@@ -2734,18 +3137,19 b' var CodeMirror = (function() {'
2734 }
3137 }
2735 // Recent (late 2011) Opera betas insert bogus newlines at the start
3138 // Recent (late 2011) Opera betas insert bogus newlines at the start
2736 // of the textContent, so we strip those.
3139 // of the textContent, so we strip those.
2737 if (htmlEscape("a") == "\na")
3140 if (htmlEscape("a") == "\na") {
2738 htmlEscape = function(str) {
3141 htmlEscape = function(str) {
2739 escapeElement.textContent = str;
3142 escapeElement.textContent = str;
2740 return escapeElement.innerHTML.slice(1);
3143 return escapeElement.innerHTML.slice(1);
2741 };
3144 };
2742 // Some IEs don't preserve tabs through innerHTML
3145 // Some IEs don't preserve tabs through innerHTML
2743 else if (htmlEscape("\t") != "\t")
3146 } else if (htmlEscape("\t") != "\t") {
2744 htmlEscape = function(str) {
3147 htmlEscape = function(str) {
2745 escapeElement.innerHTML = "";
3148 escapeElement.innerHTML = "";
2746 escapeElement.appendChild(document.createTextNode(str));
3149 escapeElement.appendChild(document.createTextNode(str));
2747 return escapeElement.innerHTML;
3150 return escapeElement.innerHTML;
2748 };
3151 };
3152 }
2749 CodeMirror.htmlEscape = htmlEscape;
3153 CodeMirror.htmlEscape = htmlEscape;
2750
3154
2751 // Used to position the cursor after an undo/redo by finding the
3155 // Used to position the cursor after an undo/redo by finding the
@@ -2771,14 +3175,22 b' var CodeMirror = (function() {'
2771 // See if "".split is the broken IE version, if so, provide an
3175 // See if "".split is the broken IE version, if so, provide an
2772 // alternative way to split lines.
3176 // alternative way to split lines.
2773 var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
3177 var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
2774 var pos = 0, nl, result = [];
3178 var pos = 0, result = [], l = string.length;
2775 while ((nl = string.indexOf("\n", pos)) > -1) {
3179 while (pos <= l) {
2776 result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
3180 var nl = string.indexOf("\n", pos);
2777 pos = nl + 1;
3181 if (nl == -1) nl = string.length;
3182 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
3183 var rt = line.indexOf("\r");
3184 if (rt != -1) {
3185 result.push(line.slice(0, rt));
3186 pos += rt + 1;
3187 } else {
3188 result.push(line);
3189 pos = nl + 1;
3190 }
2778 }
3191 }
2779 result.push(string.slice(pos));
2780 return result;
3192 return result;
2781 } : function(string){return string.split(/\r?\n/);};
3193 } : function(string){return string.split(/\r\n?|\n/);};
2782 CodeMirror.splitLines = splitLines;
3194 CodeMirror.splitLines = splitLines;
2783
3195
2784 var hasSelection = window.getSelection ? function(te) {
3196 var hasSelection = window.getSelection ? function(te) {
@@ -2799,10 +3211,10 b' var CodeMirror = (function() {'
2799 var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
3211 var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
2800 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
3212 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
2801 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
3213 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
2802 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 186: ";", 187: "=", 188: ",",
3214 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
2803 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63276: "PageUp",
3215 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
2804 63277: "PageDown", 63275: "End", 63273: "Home", 63234: "Left", 63232: "Up", 63235: "Right",
3216 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
2805 63233: "Down", 63302: "Insert", 63272: "Delete"};
3217 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
2806 CodeMirror.keyNames = keyNames;
3218 CodeMirror.keyNames = keyNames;
2807 (function() {
3219 (function() {
2808 // Number keys
3220 // Number keys
@@ -21,3 +21,7 b''
21 color: inherit;
21 color: inherit;
22 font-family: monospace;
22 font-family: monospace;
23 }
23 }
24
25 .CodeMirror-dialog button {
26 font-size: 70%;
27 } No newline at end of file
@@ -17,7 +17,7 b''
17 closed = true;
17 closed = true;
18 dialog.parentNode.removeChild(dialog);
18 dialog.parentNode.removeChild(dialog);
19 }
19 }
20 var inp = dialog.getElementsByTagName("input")[0];
20 var inp = dialog.getElementsByTagName("input")[0], button;
21 if (inp) {
21 if (inp) {
22 CodeMirror.connect(inp, "keydown", function(e) {
22 CodeMirror.connect(inp, "keydown", function(e) {
23 if (e.keyCode == 13 || e.keyCode == 27) {
23 if (e.keyCode == 13 || e.keyCode == 27) {
@@ -29,6 +29,10 b''
29 });
29 });
30 inp.focus();
30 inp.focus();
31 CodeMirror.connect(inp, "blur", close);
31 CodeMirror.connect(inp, "blur", close);
32 } else if (button = dialog.getElementsByTagName("button")[0]) {
33 CodeMirror.connect(button, "click", close);
34 button.focus();
35 CodeMirror.connect(button, "blur", close);
32 }
36 }
33 return close;
37 return close;
34 });
38 });
@@ -1,9 +1,9 b''
1 // the tagRangeFinder function is
1 // the tagRangeFinder function is
2 // Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
2 // Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
3 // released under the MIT license (../../LICENSE) like the rest of CodeMirror
3 // released under the MIT license (../../LICENSE) like the rest of CodeMirror
4 CodeMirror.tagRangeFinder = function(cm, line) {
4 CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
5 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";
5 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";
6 var nameChar = nameStartChar + "\-\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
6 var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
7 var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
7 var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
8
8
9 var lineText = cm.getLine(line);
9 var lineText = cm.getLine(line);
@@ -36,8 +36,10 b' CodeMirror.tagRangeFinder = function(cm, line) {'
36 var slash = lt.lastIndexOf("/", gt);
36 var slash = lt.lastIndexOf("/", gt);
37 if (-1 != slash && slash < gt) {
37 if (-1 != slash && slash < gt) {
38 var str = lineText.substr(slash, gt - slash + 1);
38 var str = lineText.substr(slash, gt - slash + 1);
39 if (!str.match( /\/\s*\>/ )) // yep, that's the end of empty tag
39 if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
40 return l+1;
40 if (hideEnd === true) l++;
41 return l;
42 }
41 }
43 }
42 }
44 }
43 l++;
45 l++;
@@ -80,7 +82,7 b' CodeMirror.tagRangeFinder = function(cm, line) {'
80 }
82 }
81
83
82 if (found) {
84 if (found) {
83 var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\s)|(\\<" + tag + "$)";
85 var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
84 var startTagRegExp = new RegExp(startTag, "g");
86 var startTagRegExp = new RegExp(startTag, "g");
85 var endTag = "</" + tag + ">";
87 var endTag = "</" + tag + ">";
86 var depth = 1;
88 var depth = 1;
@@ -95,8 +97,10 b' CodeMirror.tagRangeFinder = function(cm, line) {'
95 depth--;
97 depth--;
96 else
98 else
97 depth++;
99 depth++;
98 if (!depth)
100 if (!depth) {
99 return l+1;
101 if (hideEnd === true) l++;
102 return l;
103 }
100 }
104 }
101 }
105 }
102 l++;
106 l++;
@@ -105,11 +109,16 b' CodeMirror.tagRangeFinder = function(cm, line) {'
105 }
109 }
106 };
110 };
107
111
108 CodeMirror.braceRangeFinder = function(cm, line) {
112 CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
109 var lineText = cm.getLine(line);
113 var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
110 var startChar = lineText.lastIndexOf("{");
114 for (;;) {
111 if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return;
115 var found = lineText.lastIndexOf("{", at);
112 var tokenType = cm.getTokenAt({line: line, ch: startChar}).className;
116 if (found < 0) break;
117 tokenType = cm.getTokenAt({line: line, ch: found}).className;
118 if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
119 at = found - 1;
120 }
121 if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
113 var count = 1, lastLine = cm.lineCount(), end;
122 var count = 1, lastLine = cm.lineCount(), end;
114 outer: for (var i = line + 1; i < lastLine; ++i) {
123 outer: for (var i = line + 1; i < lastLine; ++i) {
115 var text = cm.getLine(i), pos = 0;
124 var text = cm.getLine(i), pos = 0;
@@ -127,11 +136,25 b' CodeMirror.braceRangeFinder = function(cm, line) {'
127 }
136 }
128 }
137 }
129 if (end == null || end == line + 1) return;
138 if (end == null || end == line + 1) return;
139 if (hideEnd === true) end++;
130 return end;
140 return end;
131 };
141 };
132
142
143 CodeMirror.indentRangeFinder = function(cm, line) {
144 var tabSize = cm.getOption("tabSize");
145 var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
146 for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
147 var handle = cm.getLineHandle(i);
148 if (!/^\s*$/.test(handle.text)) {
149 if (handle.indentation(tabSize) <= myIndent) break;
150 last = i;
151 }
152 }
153 if (!last) return null;
154 return last + 1;
155 };
133
156
134 CodeMirror.newFoldFunction = function(rangeFinder, markText) {
157 CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
135 var folded = [];
158 var folded = [];
136 if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
159 if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
137
160
@@ -156,7 +179,7 b' CodeMirror.newFoldFunction = function(rangeFinder, markText) {'
156 folded.splice(known.pos, 1);
179 folded.splice(known.pos, 1);
157 expand(cm, known.region);
180 expand(cm, known.region);
158 } else {
181 } else {
159 var end = rangeFinder(cm, line);
182 var end = rangeFinder(cm, line, hideEnd);
160 if (end == null) return;
183 if (end == null) return;
161 var hidden = [];
184 var hidden = [];
162 for (var i = line + 1; i < end; ++i) {
185 for (var i = line + 1; i < end; ++i) {
@@ -1,10 +1,13 b''
1 // ============== Formatting extensions ============================
1 // ============== Formatting extensions ============================
2 // A common storage for all mode-specific formatting features
2 // A common storage for all mode-specific formatting features
3 if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
3 if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
4
4
5 // Returns the extension of the editor's current mode
5 // Returns the extension of the editor's current mode
6 CodeMirror.defineExtension("getModeExt", function () {
6 CodeMirror.defineExtension("getModeExt", function () {
7 return CodeMirror.modeExtensions[this.getOption("mode")];
7 var mname = CodeMirror.resolveMode(this.getOption("mode")).name;
8 var ext = CodeMirror.modeExtensions[mname];
9 if (!ext) throw new Error("No extensions found for mode " + mname);
10 return ext;
8 });
11 });
9
12
10 // If the current mode is 'htmlmixed', returns the extension of a mode located at
13 // If the current mode is 'htmlmixed', returns the extension of a mode located at
@@ -81,7 +84,8 b' CodeMirror.modeExtensions["css"] = {'
81 commentStart: "/*",
84 commentStart: "/*",
82 commentEnd: "*/",
85 commentEnd: "*/",
83 wordWrapChars: [";", "\\{", "\\}"],
86 wordWrapChars: [";", "\\{", "\\}"],
84 autoFormatLineBreaks: function (text) {
87 autoFormatLineBreaks: function (text, startPos, endPos) {
88 text = text.substring(startPos, endPos);
85 return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
89 return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
86 }
90 }
87 };
91 };
@@ -94,6 +98,8 b' CodeMirror.modeExtensions["javascript"] = {'
94 getNonBreakableBlocks: function (text) {
98 getNonBreakableBlocks: function (text) {
95 var nonBreakableRegexes = [
99 var nonBreakableRegexes = [
96 new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
100 new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
101 new RegExp("\\\\\"([\\s\\S]*?)(\\\\\"|$)"),
102 new RegExp("\\\\\'([\\s\\S]*?)(\\\\\'|$)"),
97 new RegExp("'([\\s\\S]*?)('|$)"),
103 new RegExp("'([\\s\\S]*?)('|$)"),
98 new RegExp("\"([\\s\\S]*?)(\"|$)"),
104 new RegExp("\"([\\s\\S]*?)(\"|$)"),
99 new RegExp("//.*([\r\n]|$)")
105 new RegExp("//.*([\r\n]|$)")
@@ -122,7 +128,8 b' CodeMirror.modeExtensions["javascript"] = {'
122 return nonBreakableBlocks;
128 return nonBreakableBlocks;
123 },
129 },
124
130
125 autoFormatLineBreaks: function (text) {
131 autoFormatLineBreaks: function (text, startPos, endPos) {
132 text = text.substring(startPos, endPos);
126 var curPos = 0;
133 var curPos = 0;
127 var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
134 var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
128 var nonBreakableBlocks = this.getNonBreakableBlocks(text);
135 var nonBreakableBlocks = this.getNonBreakableBlocks(text);
@@ -155,7 +162,8 b' CodeMirror.modeExtensions["xml"] = {'
155 commentEnd: "-->",
162 commentEnd: "-->",
156 wordWrapChars: [">"],
163 wordWrapChars: [">"],
157
164
158 autoFormatLineBreaks: function (text) {
165 autoFormatLineBreaks: function (text, startPos, endPos) {
166 text = text.substring(startPos, endPos);
159 var lines = text.split("\n");
167 var lines = text.split("\n");
160 var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
168 var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
161 var reOpenBrackets = new RegExp("<", "g");
169 var reOpenBrackets = new RegExp("<", "g");
@@ -15,37 +15,81 b''
15 }
15 }
16 return arr.indexOf(item) != -1;
16 return arr.indexOf(item) != -1;
17 }
17 }
18
18
19 CodeMirror.javascriptHint = function(editor) {
19 function scriptHint(editor, keywords, getToken) {
20 // Find the token at the cursor
20 // Find the token at the cursor
21 var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token;
21 var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
22 // If it's not a 'word-style' token, ignore the token.
22 // If it's not a 'word-style' token, ignore the token.
23 if (!/^[\w$_]*$/.test(token.string)) {
23 if (!/^[\w$_]*$/.test(token.string)) {
24 token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
24 token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
25 className: token.string == "." ? "property" : null};
25 className: token.string == "." ? "property" : null};
26 }
26 }
27 // If it is a property, find out what it is a property of.
27 // If it is a property, find out what it is a property of.
28 while (tprop.className == "property") {
28 while (tprop.className == "property") {
29 tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
29 tprop = getToken(editor, {line: cur.line, ch: tprop.start});
30 if (tprop.string != ".") return;
30 if (tprop.string != ".") return;
31 tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
31 tprop = getToken(editor, {line: cur.line, ch: tprop.start});
32 if (tprop.string == ')') {
33 var level = 1;
34 do {
35 tprop = getToken(editor, {line: cur.line, ch: tprop.start});
36 switch (tprop.string) {
37 case ')': level++; break;
38 case '(': level--; break;
39 default: break;
40 }
41 } while (level > 0)
42 tprop = getToken(editor, {line: cur.line, ch: tprop.start});
43 if (tprop.className == 'variable')
44 tprop.className = 'function';
45 else return; // no clue
46 }
32 if (!context) var context = [];
47 if (!context) var context = [];
33 context.push(tprop);
48 context.push(tprop);
34 }
49 }
35 return {list: getCompletions(token, context),
50 return {list: getCompletions(token, context, keywords),
36 from: {line: cur.line, ch: token.start},
51 from: {line: cur.line, ch: token.start},
37 to: {line: cur.line, ch: token.end}};
52 to: {line: cur.line, ch: token.end}};
38 }
53 }
39
54
55 CodeMirror.javascriptHint = function(editor) {
56 return scriptHint(editor, javascriptKeywords,
57 function (e, cur) {return e.getTokenAt(cur);});
58 }
59
60 function getCoffeeScriptToken(editor, cur) {
61 // This getToken, it is for coffeescript, imitates the behavior of
62 // getTokenAt method in javascript.js, that is, returning "property"
63 // type and treat "." as indepenent token.
64 var token = editor.getTokenAt(cur);
65 if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
66 token.end = token.start;
67 token.string = '.';
68 token.className = "property";
69 }
70 else if (/^\.[\w$_]*$/.test(token.string)) {
71 token.className = "property";
72 token.start++;
73 token.string = token.string.replace(/\./, '');
74 }
75 return token;
76 }
77
78 CodeMirror.coffeescriptHint = function(editor) {
79 return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken);
80 }
81
40 var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
82 var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
41 "toUpperCase toLowerCase split concat match replace search").split(" ");
83 "toUpperCase toLowerCase split concat match replace search").split(" ");
42 var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
84 var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
43 "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
85 "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
44 var funcProps = "prototype apply call bind".split(" ");
86 var funcProps = "prototype apply call bind".split(" ");
45 var keywords = ("break case catch continue debugger default delete do else false finally for function " +
87 var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
46 "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
88 "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
89 var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
90 "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(" ");
47
91
48 function getCompletions(token, context) {
92 function getCompletions(token, context, keywords) {
49 var found = [], start = token.string;
93 var found = [], start = token.string;
50 function maybeAdd(str) {
94 function maybeAdd(str) {
51 if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
95 if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
@@ -67,6 +111,13 b''
67 base = "";
111 base = "";
68 else if (obj.className == "atom")
112 else if (obj.className == "atom")
69 base = 1;
113 base = 1;
114 else if (obj.className == "function") {
115 if (window.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
116 (typeof window.jQuery == 'function'))
117 base = window.jQuery();
118 else if (window._ != null && (obj.string == '_') && (typeof window._ == 'function'))
119 base = window._();
120 }
70 while (base != null && context.length)
121 while (base != null && context.length)
71 base = base[context.pop().string];
122 base = base[context.pop().string];
72 if (base != null) gatherCompletions(base);
123 if (base != null) gatherCompletions(base);
@@ -6,7 +6,8 b''
6 // overlay wins, unless the combine argument was true, in which case
6 // overlay wins, unless the combine argument was true, in which case
7 // the styles are combined.
7 // the styles are combined.
8
8
9 CodeMirror.overlayParser = function(base, overlay, combine) {
9 // overlayParser is the old, deprecated name
10 CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) {
10 return {
11 return {
11 startState: function() {
12 startState: function() {
12 return {
13 return {
@@ -43,7 +44,7 b' CodeMirror.overlayParser = function(base, overlay, combine) {'
43 else return state.overlayCur;
44 else return state.overlayCur;
44 },
45 },
45
46
46 indent: function(state, textAfter) {
47 indent: base.indent && function(state, textAfter) {
47 return base.indent(state.base, textAfter);
48 return base.indent(state.base, textAfter);
48 },
49 },
49 electricChars: base.electricChars
50 electricChars: base.electricChars
@@ -1,15 +1,37 b''
1 CodeMirror.runMode = function(string, modespec, callback) {
1 CodeMirror.runMode = function(string, modespec, callback, options) {
2 var mode = CodeMirror.getMode({indentUnit: 2}, modespec);
2 var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
3 var isNode = callback.nodeType == 1;
3 var isNode = callback.nodeType == 1;
4 var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
4 if (isNode) {
5 if (isNode) {
5 var node = callback, accum = [];
6 var node = callback, accum = [], col = 0;
6 callback = function(string, style) {
7 callback = function(text, style) {
7 if (string == "\n")
8 if (text == "\n") {
8 accum.push("<br>");
9 accum.push("<br>");
9 else if (style)
10 col = 0;
10 accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + CodeMirror.htmlEscape(string) + "</span>");
11 return;
12 }
13 var escaped = "";
14 // HTML-escape and replace tabs
15 for (var pos = 0;;) {
16 var idx = text.indexOf("\t", pos);
17 if (idx == -1) {
18 escaped += CodeMirror.htmlEscape(text.slice(pos));
19 col += text.length - pos;
20 break;
21 } else {
22 col += idx - pos;
23 escaped += CodeMirror.htmlEscape(text.slice(pos, idx));
24 var size = tabSize - col % tabSize;
25 col += size;
26 for (var i = 0; i < size; ++i) escaped += " ";
27 pos = idx + 1;
28 }
29 }
30
31 if (style)
32 accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + escaped + "</span>");
11 else
33 else
12 accum.push(CodeMirror.htmlEscape(string));
34 accum.push(escaped);
13 }
35 }
14 }
36 }
15 var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
37 var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
@@ -14,6 +14,10 b''
14 function getSearchState(cm) {
14 function getSearchState(cm) {
15 return cm._searchState || (cm._searchState = new SearchState());
15 return cm._searchState || (cm._searchState = new SearchState());
16 }
16 }
17 function getSearchCursor(cm, query, pos) {
18 // Heuristic: if the query string is all lowercase, do a case insensitive search.
19 return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
20 }
17 function dialog(cm, text, shortText, f) {
21 function dialog(cm, text, shortText, f) {
18 if (cm.openDialog) cm.openDialog(text, f);
22 if (cm.openDialog) cm.openDialog(text, f);
19 else f(prompt(shortText, ""));
23 else f(prompt(shortText, ""));
@@ -23,11 +27,11 b''
23 else if (confirm(shortText)) fs[0]();
27 else if (confirm(shortText)) fs[0]();
24 }
28 }
25 function parseQuery(query) {
29 function parseQuery(query) {
26 var isRE = query.match(/^\/(.*)\/$/);
30 var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
27 return isRE ? new RegExp(isRE[1]) : query;
31 return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : query;
28 }
32 }
29 var queryDialog =
33 var queryDialog =
30 'Search: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
34 'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
31 function doSearch(cm, rev) {
35 function doSearch(cm, rev) {
32 var state = getSearchState(cm);
36 var state = getSearchState(cm);
33 if (state.query) return findNext(cm, rev);
37 if (state.query) return findNext(cm, rev);
@@ -36,7 +40,7 b''
36 if (!query || state.query) return;
40 if (!query || state.query) return;
37 state.query = parseQuery(query);
41 state.query = parseQuery(query);
38 if (cm.lineCount() < 2000) { // This is too expensive on big documents.
42 if (cm.lineCount() < 2000) { // This is too expensive on big documents.
39 for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
43 for (var cursor = getSearchCursor(cm, query); cursor.findNext();)
40 state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
44 state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
41 }
45 }
42 state.posFrom = state.posTo = cm.getCursor();
46 state.posFrom = state.posTo = cm.getCursor();
@@ -46,9 +50,9 b''
46 }
50 }
47 function findNext(cm, rev) {cm.operation(function() {
51 function findNext(cm, rev) {cm.operation(function() {
48 var state = getSearchState(cm);
52 var state = getSearchState(cm);
49 var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
53 var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
50 if (!cursor.find(rev)) {
54 if (!cursor.find(rev)) {
51 cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
55 cursor = getSearchCursor(cm, state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
52 if (!cursor.find(rev)) return;
56 if (!cursor.find(rev)) return;
53 }
57 }
54 cm.setSelection(cursor.from(), cursor.to());
58 cm.setSelection(cursor.from(), cursor.to());
@@ -63,8 +67,8 b''
63 })}
67 })}
64
68
65 var replaceQueryDialog =
69 var replaceQueryDialog =
66 'Replace: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
70 'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
67 var replacementQueryDialog = 'With: <input type="text" style="width: 10em">';
71 var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
68 var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
72 var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
69 function replace(cm, all) {
73 function replace(cm, all) {
70 dialog(cm, replaceQueryDialog, "Replace:", function(query) {
74 dialog(cm, replaceQueryDialog, "Replace:", function(query) {
@@ -72,23 +76,23 b''
72 query = parseQuery(query);
76 query = parseQuery(query);
73 dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
77 dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
74 if (all) {
78 if (all) {
75 cm.operation(function() {
79 cm.compoundChange(function() { cm.operation(function() {
76 for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
80 for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
77 if (typeof query != "string") {
81 if (typeof query != "string") {
78 var match = cm.getRange(cursor.from(), cursor.to()).match(query);
82 var match = cm.getRange(cursor.from(), cursor.to()).match(query);
79 cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
83 cursor.replace(text.replace(/\$(\d)/, function(w, i) {return match[i];}));
80 } else cursor.replace(text);
84 } else cursor.replace(text);
81 }
85 }
82 });
86 })});
83 } else {
87 } else {
84 clearSearch(cm);
88 clearSearch(cm);
85 var cursor = cm.getSearchCursor(query, cm.getCursor());
89 var cursor = getSearchCursor(cm, query, cm.getCursor());
86 function advance() {
90 function advance() {
87 var start = cursor.from(), match;
91 var start = cursor.from(), match;
88 if (!(match = cursor.findNext())) {
92 if (!(match = cursor.findNext())) {
89 cursor = cm.getSearchCursor(query);
93 cursor = getSearchCursor(cm, query);
90 if (!(match = cursor.findNext()) ||
94 if (!(match = cursor.findNext()) ||
91 (cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
95 (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
92 }
96 }
93 cm.setSelection(cursor.from(), cursor.to());
97 cm.setSelection(cursor.from(), cursor.to());
94 confirmDialog(cm, doReplaceConfirm, "Replace?",
98 confirmDialog(cm, doReplaceConfirm, "Replace?",
@@ -1,7 +1,7 b''
1 (function(){
1 (function(){
2 function SearchCursor(cm, query, pos, caseFold) {
2 function SearchCursor(cm, query, pos, caseFold) {
3 this.atOccurrence = false; this.cm = cm;
3 this.atOccurrence = false; this.cm = cm;
4 if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
4 if (caseFold == null && typeof query == "string") caseFold = false;
5
5
6 pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
6 pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0};
7 this.pos = {from: pos, to: pos};
7 this.pos = {from: pos, to: pos};
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -2,6 +2,10 b''
2 CodeMirror.simpleHint = function(editor, getHints) {
2 CodeMirror.simpleHint = function(editor, getHints) {
3 // We want a single cursor position.
3 // We want a single cursor position.
4 if (editor.somethingSelected()) return;
4 if (editor.somethingSelected()) return;
5 //don't show completion if the token is empty
6 var tempToken = editor.getTokenAt(editor.getCursor());
7 if(!(/[\S]/gi.test(tempToken.string))) return;
8
5 var result = getHints(editor);
9 var result = getHints(editor);
6 if (!result || !result.list.length) return;
10 if (!result || !result.list.length) return;
7 var completions = result.list;
11 var completions = result.list;
@@ -29,6 +33,10 b''
29 complete.style.left = pos.x + "px";
33 complete.style.left = pos.x + "px";
30 complete.style.top = pos.yBot + "px";
34 complete.style.top = pos.yBot + "px";
31 document.body.appendChild(complete);
35 document.body.appendChild(complete);
36 // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
37 var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
38 if(winW - pos.x < sel.clientWidth)
39 complete.style.left = (pos.x - sel.clientWidth) + "px";
32 // Hack to hide the scrollbar.
40 // Hack to hide the scrollbar.
33 if (completions.length <= 10)
41 if (completions.length <= 10)
34 complete.style.width = (sel.clientWidth - 1) + "px";
42 complete.style.width = (sel.clientWidth - 1) + "px";
@@ -53,6 +61,8 b''
53 else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
61 else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();}
54 else if (code != 38 && code != 40) {
62 else if (code != 38 && code != 40) {
55 close(); editor.focus();
63 close(); editor.focus();
64 // Pass the event to the CodeMirror instance so that it can handle things like backspace properly.
65 editor.triggerOnKeyDown(event);
56 setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
66 setTimeout(function(){CodeMirror.simpleHint(editor, getHints);}, 50);
57 }
67 }
58 });
68 });
@@ -92,7 +92,7 b' CodeMirror.defineMode("css", function(config) {'
92 var style = state.tokenize(stream, state);
92 var style = state.tokenize(stream, state);
93
93
94 var context = state.stack[state.stack.length-1];
94 var context = state.stack[state.stack.length-1];
95 if (type == "hash" && context == "rule") style = "atom";
95 if (type == "hash" && context != "rule") style = "string-2";
96 else if (style == "variable") {
96 else if (style == "variable") {
97 if (context == "rule") style = "number";
97 if (context == "rule") style = "number";
98 else if (!context || context == "@media{") style = "tag";
98 else if (!context || context == "@media{") style = "tag";
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -28,7 +28,7 b' CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {'
28 function javascript(stream, state) {
28 function javascript(stream, state) {
29 if (stream.match(/^<\/\s*script\s*>/i, false)) {
29 if (stream.match(/^<\/\s*script\s*>/i, false)) {
30 state.token = html;
30 state.token = html;
31 state.curState = null;
31 state.localState = null;
32 state.mode = "html";
32 state.mode = "html";
33 return html(stream, state);
33 return html(stream, state);
34 }
34 }
@@ -73,11 +73,13 b' CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {'
73 },
73 },
74
74
75 compareStates: function(a, b) {
75 compareStates: function(a, b) {
76 if (a.mode != b.mode) return false;
77 if (a.localState) return CodeMirror.Pass;
76 return htmlMode.compareStates(a.htmlState, b.htmlState);
78 return htmlMode.compareStates(a.htmlState, b.htmlState);
77 },
79 },
78
80
79 electricChars: "/{}:"
81 electricChars: "/{}:"
80 }
82 }
81 });
83 }, "xml", "javascript", "css");
82
84
83 CodeMirror.defineMIME("text/html", "htmlmixed");
85 CodeMirror.defineMIME("text/html", "htmlmixed");
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
@@ -54,7 +54,7 b' CodeMirror.defineMode("javascript", function(config, parserConfig) {'
54 stream.eatWhile(/[\da-f]/i);
54 stream.eatWhile(/[\da-f]/i);
55 return ret("number", "number");
55 return ret("number", "number");
56 }
56 }
57 else if (/\d/.test(ch)) {
57 else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
58 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
58 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
59 return ret("number", "number");
59 return ret("number", "number");
60 }
60 }
@@ -243,7 +243,7 b' CodeMirror.defineMode("javascript", function(config, parserConfig) {'
243
243
244 function maybeoperator(type, value) {
244 function maybeoperator(type, value) {
245 if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
245 if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
246 if (type == "operator") return cont(expression);
246 if (type == "operator" || type == ":") return cont(expression);
247 if (type == ";") return;
247 if (type == ";") return;
248 if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
248 if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
249 if (type == ".") return cont(property, maybeoperator);
249 if (type == ".") return cont(property, maybeoperator);
@@ -319,8 +319,8 b' CodeMirror.defineMode("javascript", function(config, parserConfig) {'
319 kwAllowed: true,
319 kwAllowed: true,
320 cc: [],
320 cc: [],
321 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
321 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
322 localVars: null,
322 localVars: parserConfig.localVars,
323 context: null,
323 context: parserConfig.localVars && {vars: parserConfig.localVars},
324 indented: 0
324 indented: 0
325 };
325 };
326 },
326 },
@@ -334,15 +334,16 b' CodeMirror.defineMode("javascript", function(config, parserConfig) {'
334 if (stream.eatSpace()) return null;
334 if (stream.eatSpace()) return null;
335 var style = state.tokenize(stream, state);
335 var style = state.tokenize(stream, state);
336 if (type == "comment") return style;
336 if (type == "comment") return style;
337 state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
337 state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
338 state.kwAllowed = type != '.';
338 state.kwAllowed = type != '.';
339 return parseJS(state, style, type, content, stream);
339 return parseJS(state, style, type, content, stream);
340 },
340 },
341
341
342 indent: function(state, textAfter) {
342 indent: function(state, textAfter) {
343 if (state.tokenize != jsTokenBase) return 0;
343 if (state.tokenize != jsTokenBase) return 0;
344 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
344 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
345 type = lexical.type, closing = firstChar == type;
345 if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
346 var type = lexical.type, closing = firstChar == type;
346 if (type == "vardef") return lexical.indented + 4;
347 if (type == "vardef") return lexical.indented + 4;
347 else if (type == "form" && firstChar == "{") return lexical.indented;
348 else if (type == "form" && firstChar == "{") return lexical.indented;
348 else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
349 else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
@@ -6,7 +6,6 b''
6 <script src="../../lib/codemirror.js"></script>
6 <script src="../../lib/codemirror.js"></script>
7 <script src="../xml/xml.js"></script>
7 <script src="../xml/xml.js"></script>
8 <script src="markdown.js"></script>
8 <script src="markdown.js"></script>
9 <link rel="stylesheet" href="markdown.css">
10 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
11 <link rel="stylesheet" href="../../doc/docs.css">
10 <link rel="stylesheet" href="../../doc/docs.css">
12 </head>
11 </head>
@@ -333,6 +332,8 b' Output:'
333 });
332 });
334 </script>
333 </script>
335
334
335 <p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
336
336 <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
337 <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
337
338
338 </body>
339 </body>
@@ -1,6 +1,7 b''
1 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
1 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
2
2
3 var htmlMode = CodeMirror.getMode(cmCfg, { name: 'xml', htmlMode: true });
3 var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html");
4 var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain");
4
5
5 var header = 'header'
6 var header = 'header'
6 , code = 'comment'
7 , code = 'comment'
@@ -13,11 +14,10 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
13 , strong = 'strong'
14 , strong = 'strong'
14 , emstrong = 'emstrong';
15 , emstrong = 'emstrong';
15
16
16 var hrRE = /^[*-=_]/
17 var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
17 , ulRE = /^[*-+]\s+/
18 , ulRE = /^[*\-+]\s+/
18 , olRE = /^[0-9]+\.\s+/
19 , olRE = /^[0-9]+\.\s+/
19 , headerRE = /^(?:\={3,}|-{3,})$/
20 , headerRE = /^(?:\={3,}|-{3,})$/
20 , codeRE = /^(k:\t|\s{4,})/
21 , textRE = /^[^\[*_\\<>`]+/;
21 , textRE = /^[^\[*_\\<>`]+/;
22
22
23 function switchInline(stream, state, f) {
23 function switchInline(stream, state, f) {
@@ -33,36 +33,36 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
33
33
34 // Blocks
34 // Blocks
35
35
36 function blankLine(state) {
37 // Reset EM state
38 state.em = false;
39 // Reset STRONG state
40 state.strong = false;
41 if (!htmlFound && state.f == htmlBlock) {
42 state.f = inlineNormal;
43 state.block = blockNormal;
44 }
45 return null;
46 }
47
36 function blockNormal(stream, state) {
48 function blockNormal(stream, state) {
37 if (stream.match(codeRE)) {
49 var match;
50 if (state.indentationDiff >= 4) {
51 state.indentation -= state.indentationDiff;
38 stream.skipToEnd();
52 stream.skipToEnd();
39 return code;
53 return code;
40 }
54 } else if (stream.eatSpace()) {
41
42 if (stream.eatSpace()) {
43 return null;
55 return null;
44 }
56 } else if (stream.peek() === '#' || stream.match(headerRE)) {
45
57 state.header = true;
46 if (stream.peek() === '#' || stream.match(headerRE)) {
58 } else if (stream.eat('>')) {
47 stream.skipToEnd();
48 return header;
49 }
50 if (stream.eat('>')) {
51 state.indentation++;
59 state.indentation++;
52 return quote;
60 state.quote = true;
53 }
61 } else if (stream.peek() === '[') {
54 if (stream.peek() === '[') {
55 return switchInline(stream, state, footnoteLink);
62 return switchInline(stream, state, footnoteLink);
56 }
63 } else if (stream.match(hrRE, true)) {
57 if (hrRE.test(stream.peek())) {
64 return hr;
58 var re = new RegExp('(?:\s*['+stream.peek()+']){3,}$');
65 } else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
59 if (stream.match(re, true)) {
60 return hr;
61 }
62 }
63
64 var match;
65 if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
66 state.indentation += match[0].length;
66 state.indentation += match[0].length;
67 return list;
67 return list;
68 }
68 }
@@ -72,18 +72,30 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
72
72
73 function htmlBlock(stream, state) {
73 function htmlBlock(stream, state) {
74 var style = htmlMode.token(stream, state.htmlState);
74 var style = htmlMode.token(stream, state.htmlState);
75 if (style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
75 if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
76 state.f = inlineNormal;
76 state.f = inlineNormal;
77 state.block = blockNormal;
77 state.block = blockNormal;
78 }
78 }
79 if (state.md_inside && stream.current().indexOf(">")!=-1) {
80 state.f = inlineNormal;
81 state.block = blockNormal;
82 state.htmlState.context = undefined;
83 }
79 return style;
84 return style;
80 }
85 }
81
86
82
87
83 // Inline
88 // Inline
84 function getType(state) {
89 function getType(state) {
85 return state.strong ? (state.em ? emstrong : strong)
90 var styles = [];
86 : (state.em ? em : null);
91
92 if (state.strong) { styles.push(state.em ? emstrong : strong); }
93 else if (state.em) { styles.push(em); }
94
95 if (state.header) { styles.push(header); }
96 if (state.quote) { styles.push(quote); }
97
98 return styles.length ? styles.join(' ') : null;
87 }
99 }
88
100
89 function handleText(stream, state) {
101 function handleText(stream, state) {
@@ -111,10 +123,22 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
111 return switchInline(stream, state, linkText);
123 return switchInline(stream, state, linkText);
112 }
124 }
113 if (ch === '<' && stream.match(/^\w/, false)) {
125 if (ch === '<' && stream.match(/^\w/, false)) {
126 var md_inside = false;
127 if (stream.string.indexOf(">")!=-1) {
128 var atts = stream.string.substring(1,stream.string.indexOf(">"));
129 if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
130 state.md_inside = true;
131 }
132 }
114 stream.backUp(1);
133 stream.backUp(1);
115 return switchBlock(stream, state, htmlBlock);
134 return switchBlock(stream, state, htmlBlock);
116 }
135 }
117
136
137 if (ch === '<' && stream.match(/^\/\w*?>/)) {
138 state.md_inside = false;
139 return "tag";
140 }
141
118 var t = getType(state);
142 var t = getType(state);
119 if (ch === '*' || ch === '_') {
143 if (ch === '*' || ch === '_') {
120 if (stream.eat(ch)) {
144 if (stream.eat(ch)) {
@@ -186,13 +210,15 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
186 f: blockNormal,
210 f: blockNormal,
187
211
188 block: blockNormal,
212 block: blockNormal,
189 htmlState: htmlMode.startState(),
213 htmlState: CodeMirror.startState(htmlMode),
190 indentation: 0,
214 indentation: 0,
191
215
192 inline: inlineNormal,
216 inline: inlineNormal,
193 text: handleText,
217 text: handleText,
194 em: false,
218 em: false,
195 strong: false
219 strong: false,
220 header: false,
221 quote: false
196 };
222 };
197 },
223 },
198
224
@@ -203,44 +229,40 b' CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {'
203 block: s.block,
229 block: s.block,
204 htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
230 htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
205 indentation: s.indentation,
231 indentation: s.indentation,
206
232
207 inline: s.inline,
233 inline: s.inline,
208 text: s.text,
234 text: s.text,
209 em: s.em,
235 em: s.em,
210 strong: s.strong
236 strong: s.strong,
237 header: s.header,
238 quote: s.quote,
239 md_inside: s.md_inside
211 };
240 };
212 },
241 },
213
242
214 token: function(stream, state) {
243 token: function(stream, state) {
215 if (stream.sol()) {
244 if (stream.sol()) {
216 // Reset EM state
245 if (stream.match(/^\s*$/, true)) { return blankLine(state); }
217 state.em = false;
246
218 // Reset STRONG state
247 // Reset state.header
219 state.strong = false;
248 state.header = false;
249 // Reset state.quote
250 state.quote = false;
251
220 state.f = state.block;
252 state.f = state.block;
221 var previousIndentation = state.indentation
253 var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
222 , currentIndentation = 0;
254 state.indentationDiff = indentation - state.indentation;
223 while (previousIndentation > 0) {
255 state.indentation = indentation;
224 if (stream.eat(' ')) {
256 if (indentation > 0) { return null; }
225 previousIndentation--;
226 currentIndentation++;
227 } else if (previousIndentation >= 4 && stream.eat('\t')) {
228 previousIndentation -= 4;
229 currentIndentation += 4;
230 } else {
231 break;
232 }
233 }
234 state.indentation = currentIndentation;
235
236 if (currentIndentation > 0) return null;
237 }
257 }
238 return state.f(stream, state);
258 return state.f(stream, state);
239 },
259 },
240
260
261 blankLine: blankLine,
262
241 getType: getType
263 getType: getType
242 };
264 };
243
265
244 });
266 }, "xml");
245
267
246 CodeMirror.defineMIME("text/x-markdown", "markdown");
268 CodeMirror.defineMIME("text/x-markdown", "markdown");
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file chmod 100755 => 100644
NO CONTENT: modified file chmod 100755 => 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now