##// END OF EJS Templates
Merge pull request #850 from fperez/codemirror...
Fernando Perez -
r4987:e5a1dffc merge
parent child Browse files
Show More
@@ -0,0 +1,33 b''
1 =======================
2 CodeMirror in IPython
3 =======================
4
5 We carry a mostly unmodified copy of CodeMirror. The current version we use
6 is (*please update this information when updating versions*)::
7
8 CodeMirror 2.15
9
10 The only changes we've applied so far are these::
11
12 diff --git a/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js b/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
13 index ca94e7a..fc9a503 100644
14 --- a/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
15 +++ b/IPython/frontend/html/notebook/static/codemirror/mode/python/python.js
16 @@ -5,7 +5,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) {
17 return new RegExp("^((" + words.join(")|(") + "))\\b");
18 }
19
20 - var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
21 + // IPython-specific changes: add '?' as recognized character.
22 + //var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
23 + var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
24 + // End IPython changes.
25 +
26 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
27 var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
28 var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
29
30
31 In practice it's just a one-line change, adding `\\?` to singleOperators,
32 surrounded by a comment. We'll turn this into a proper patchset if it ever
33 gets more complicated than this, but for now this note should be enough.
@@ -0,0 +1,340 b''
1 <!doctype html>
2 <html>
3 <head>
4 <title>CodeMirror 2: Markdown 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.js"></script>
9 <link rel="stylesheet" href="../../theme/default.css">
10 <link rel="stylesheet" href="markdown.css">
11 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
12 <link rel="stylesheet" href="../../css/docs.css">
13 </head>
14 <body>
15 <h1>CodeMirror 2: Markdown mode</h1>
16
17 <!-- source: http://daringfireball.net/projects/markdown/basics.text -->
18 <form><textarea id="code" name="code">
19 Markdown: Basics
20 ================
21
22 &lt;ul id="ProjectSubmenu"&gt;
23 &lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
24 &lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
25 &lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
26 &lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
27 &lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
28 &lt;/ul&gt;
29
30
31 Getting the Gist of Markdown's Formatting Syntax
32 ------------------------------------------------
33
34 This page offers a brief overview of what it's like to use Markdown.
35 The [syntax page] [s] provides complete, detailed documentation for
36 every feature, but Markdown should be very easy to pick up simply by
37 looking at a few examples of it in action. The examples on this page
38 are written in a before/after style, showing example syntax and the
39 HTML output produced by Markdown.
40
41 It's also helpful to simply try Markdown out; the [Dingus] [d] is a
42 web application that allows you type your own Markdown-formatted text
43 and translate it to XHTML.
44
45 **Note:** This document is itself written using Markdown; you
46 can [see the source for it by adding '.text' to the URL] [src].
47
48 [s]: /projects/markdown/syntax "Markdown Syntax"
49 [d]: /projects/markdown/dingus "Markdown Dingus"
50 [src]: /projects/markdown/basics.text
51
52
53 ## Paragraphs, Headers, Blockquotes ##
54
55 A paragraph is simply one or more consecutive lines of text, separated
56 by one or more blank lines. (A blank line is any line that looks like
57 a blank line -- a line containing nothing but spaces or tabs is
58 considered blank.) Normal paragraphs should not be indented with
59 spaces or tabs.
60
61 Markdown offers two styles of headers: *Setext* and *atx*.
62 Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
63 "underlining" with equal signs (`=`) and hyphens (`-`), respectively.
64 To create an atx-style header, you put 1-6 hash marks (`#`) at the
65 beginning of the line -- the number of hashes equals the resulting
66 HTML header level.
67
68 Blockquotes are indicated using email-style '`&gt;`' angle brackets.
69
70 Markdown:
71
72 A First Level Header
73 ====================
74
75 A Second Level Header
76 ---------------------
77
78 Now is the time for all good men to come to
79 the aid of their country. This is just a
80 regular paragraph.
81
82 The quick brown fox jumped over the lazy
83 dog's back.
84
85 ### Header 3
86
87 &gt; This is a blockquote.
88 &gt;
89 &gt; This is the second paragraph in the blockquote.
90 &gt;
91 &gt; ## This is an H2 in a blockquote
92
93
94 Output:
95
96 &lt;h1&gt;A First Level Header&lt;/h1&gt;
97
98 &lt;h2&gt;A Second Level Header&lt;/h2&gt;
99
100 &lt;p&gt;Now is the time for all good men to come to
101 the aid of their country. This is just a
102 regular paragraph.&lt;/p&gt;
103
104 &lt;p&gt;The quick brown fox jumped over the lazy
105 dog's back.&lt;/p&gt;
106
107 &lt;h3&gt;Header 3&lt;/h3&gt;
108
109 &lt;blockquote&gt;
110 &lt;p&gt;This is a blockquote.&lt;/p&gt;
111
112 &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
113
114 &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
115 &lt;/blockquote&gt;
116
117
118
119 ### Phrase Emphasis ###
120
121 Markdown uses asterisks and underscores to indicate spans of emphasis.
122
123 Markdown:
124
125 Some of these words *are emphasized*.
126 Some of these words _are emphasized also_.
127
128 Use two asterisks for **strong emphasis**.
129 Or, if you prefer, __use two underscores instead__.
130
131 Output:
132
133 &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
134 Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
135
136 &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
137 Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
138
139
140
141 ## Lists ##
142
143 Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
144 `+`, and `-`) as list markers. These three markers are
145 interchangable; this:
146
147 * Candy.
148 * Gum.
149 * Booze.
150
151 this:
152
153 + Candy.
154 + Gum.
155 + Booze.
156
157 and this:
158
159 - Candy.
160 - Gum.
161 - Booze.
162
163 all produce the same output:
164
165 &lt;ul&gt;
166 &lt;li&gt;Candy.&lt;/li&gt;
167 &lt;li&gt;Gum.&lt;/li&gt;
168 &lt;li&gt;Booze.&lt;/li&gt;
169 &lt;/ul&gt;
170
171 Ordered (numbered) lists use regular numbers, followed by periods, as
172 list markers:
173
174 1. Red
175 2. Green
176 3. Blue
177
178 Output:
179
180 &lt;ol&gt;
181 &lt;li&gt;Red&lt;/li&gt;
182 &lt;li&gt;Green&lt;/li&gt;
183 &lt;li&gt;Blue&lt;/li&gt;
184 &lt;/ol&gt;
185
186 If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
187 list item text. You can create multi-paragraph list items by indenting
188 the paragraphs by 4 spaces or 1 tab:
189
190 * A list item.
191
192 With multiple paragraphs.
193
194 * Another item in the list.
195
196 Output:
197
198 &lt;ul&gt;
199 &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
200 &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
201 &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
202 &lt;/ul&gt;
203
204
205
206 ### Links ###
207
208 Markdown supports two styles for creating links: *inline* and
209 *reference*. With both styles, you use square brackets to delimit the
210 text you want to turn into a link.
211
212 Inline-style links use parentheses immediately after the link text.
213 For example:
214
215 This is an [example link](http://example.com/).
216
217 Output:
218
219 &lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
220 example link&lt;/a&gt;.&lt;/p&gt;
221
222 Optionally, you may include a title attribute in the parentheses:
223
224 This is an [example link](http://example.com/ "With a Title").
225
226 Output:
227
228 &lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
229 example link&lt;/a&gt;.&lt;/p&gt;
230
231 Reference-style links allow you to refer to your links by names, which
232 you define elsewhere in your document:
233
234 I get 10 times more traffic from [Google][1] than from
235 [Yahoo][2] or [MSN][3].
236
237 [1]: http://google.com/ "Google"
238 [2]: http://search.yahoo.com/ "Yahoo Search"
239 [3]: http://search.msn.com/ "MSN Search"
240
241 Output:
242
243 &lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
244 title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
245 title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
246 title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
247
248 The title attribute is optional. Link names may contain letters,
249 numbers and spaces, but are *not* case sensitive:
250
251 I start my morning with a cup of coffee and
252 [The New York Times][NY Times].
253
254 [ny times]: http://www.nytimes.com/
255
256 Output:
257
258 &lt;p&gt;I start my morning with a cup of coffee and
259 &lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
260
261
262 ### Images ###
263
264 Image syntax is very much like link syntax.
265
266 Inline (titles are optional):
267
268 ![alt text](/path/to/img.jpg "Title")
269
270 Reference-style:
271
272 ![alt text][id]
273
274 [id]: /path/to/img.jpg "Title"
275
276 Both of the above examples produce the same output:
277
278 &lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
279
280
281
282 ### Code ###
283
284 In a regular paragraph, you can create code span by wrapping text in
285 backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
286 `&gt;`) will automatically be translated into HTML entities. This makes
287 it easy to use Markdown to write about HTML example code:
288
289 I strongly recommend against using any `&lt;blink&gt;` tags.
290
291 I wish SmartyPants used named entities like `&amp;mdash;`
292 instead of decimal-encoded entites like `&amp;#8212;`.
293
294 Output:
295
296 &lt;p&gt;I strongly recommend against using any
297 &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
298
299 &lt;p&gt;I wish SmartyPants used named entities like
300 &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
301 entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
302
303
304 To specify an entire block of pre-formatted code, indent every line of
305 the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
306 and `&gt;` characters will be escaped automatically.
307
308 Markdown:
309
310 If you want your page to validate under XHTML 1.0 Strict,
311 you've got to put paragraph tags in your blockquotes:
312
313 &lt;blockquote&gt;
314 &lt;p&gt;For example.&lt;/p&gt;
315 &lt;/blockquote&gt;
316
317 Output:
318
319 &lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
320 you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
321
322 &lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
323 &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
324 &amp;lt;/blockquote&amp;gt;
325 &lt;/code&gt;&lt;/pre&gt;
326 </textarea></form>
327
328 <script>
329 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
330 mode: 'markdown',
331 lineNumbers: true,
332 matchBrackets: true,
333 theme: "default"
334 });
335 </script>
336
337 <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
338
339 </body>
340 </html>
@@ -0,0 +1,10 b''
1 .cm-s-default span.cm-header {color: #2f2f4f; font-weight:bold;}
2 .cm-s-default span.cm-code {color: #666;}
3 .cm-s-default span.cm-quote {color: #090;}
4 .cm-s-default span.cm-list {color: #a50;}
5 .cm-s-default span.cm-hr {color: #999;}
6 .cm-s-default span.cm-linktext {color: #00c; text-decoration: underline;}
7 .cm-s-default span.cm-linkhref {color: #00c;}
8 .cm-s-default span.cm-em {font-style: italic;}
9 .cm-s-default span.cm-strong {font-weight: bold;}
10 .cm-s-default span.cm-emstrong {font-style: italic; font-weight: bold;}
@@ -0,0 +1,230 b''
1 CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
2
3 var htmlMode = CodeMirror.getMode(cmCfg, { name: 'xml', htmlMode: true });
4
5 var header = 'header'
6 , code = 'code'
7 , quote = 'quote'
8 , list = 'list'
9 , hr = 'hr'
10 , linktext = 'linktext'
11 , linkhref = 'linkhref'
12 , em = 'em'
13 , strong = 'strong'
14 , emstrong = 'emstrong';
15
16 var hrRE = /^[*-=_]/
17 , ulRE = /^[*-+]\s+/
18 , olRE = /^[0-9]\.\s+/
19 , headerRE = /^(?:\={3,}|-{3,})$/
20 , codeRE = /^(k:\t|\s{4,})/
21 , textRE = /^[^\[*_\\<>`]+/;
22
23 function switchInline(stream, state, f) {
24 state.f = state.inline = f;
25 return f(stream, state);
26 }
27
28 function switchBlock(stream, state, f) {
29 state.f = state.block = f;
30 return f(stream, state);
31 }
32
33
34 // Blocks
35
36 function blockNormal(stream, state) {
37 if (stream.match(codeRE)) {
38 stream.skipToEnd();
39 return code;
40 }
41
42 if (stream.eatSpace()) {
43 return null;
44 }
45
46 if (stream.peek() === '#' || stream.match(headerRE)) {
47 stream.skipToEnd();
48 return header;
49 }
50 if (stream.eat('>')) {
51 state.indentation++;
52 return quote;
53 }
54 if (stream.peek() === '<') {
55 return switchBlock(stream, state, htmlBlock);
56 }
57 if (stream.peek() === '[') {
58 return switchInline(stream, state, footnoteLink);
59 }
60 if (hrRE.test(stream.peek())) {
61 var re = new RegExp('(?:\s*['+stream.peek()+']){3,}$');
62 if (stream.match(re, true)) {
63 return hr;
64 }
65 }
66
67 var match;
68 if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
69 state.indentation += match[0].length;
70 return list;
71 }
72
73 return switchInline(stream, state, state.inline);
74 }
75
76 function htmlBlock(stream, state) {
77 var type = htmlMode.token(stream, state.htmlState);
78 if (stream.eol() && !state.htmlState.context) {
79 state.block = blockNormal;
80 }
81 return type;
82 }
83
84
85 // Inline
86
87 function inlineNormal(stream, state) {
88 function getType() {
89 return state.strong ? (state.em ? emstrong : strong)
90 : (state.em ? em : null);
91 }
92
93 if (stream.match(textRE, true)) {
94 return getType();
95 }
96
97 var ch = stream.next();
98
99 if (ch === '\\') {
100 stream.next();
101 return getType();
102 }
103 if (ch === '`') {
104 return switchInline(stream, state, inlineElement(code, '`'));
105 }
106 if (ch === '<') {
107 return switchInline(stream, state, inlineElement(linktext, '>'));
108 }
109 if (ch === '[') {
110 return switchInline(stream, state, linkText);
111 }
112
113 var t = getType();
114 if (ch === '*' || ch === '_') {
115 if (stream.eat(ch)) {
116 return (state.strong = !state.strong) ? getType() : t;
117 }
118 return (state.em = !state.em) ? getType() : t;
119 }
120
121 return getType();
122 }
123
124 function linkText(stream, state) {
125 while (!stream.eol()) {
126 var ch = stream.next();
127 if (ch === '\\') stream.next();
128 if (ch === ']') {
129 state.inline = state.f = linkHref;
130 return linktext;
131 }
132 }
133 return linktext;
134 }
135
136 function linkHref(stream, state) {
137 stream.eatSpace();
138 var ch = stream.next();
139 if (ch === '(' || ch === '[') {
140 return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
141 }
142 return 'error';
143 }
144
145 function footnoteLink(stream, state) {
146 if (stream.match(/^[^\]]*\]:/, true)) {
147 state.f = footnoteUrl;
148 return linktext;
149 }
150 return switchInline(stream, state, inlineNormal);
151 }
152
153 function footnoteUrl(stream, state) {
154 stream.eatSpace();
155 stream.match(/^[^\s]+/, true);
156 state.f = state.inline = inlineNormal;
157 return linkhref;
158 }
159
160 function inlineElement(type, endChar, next) {
161 next = next || inlineNormal;
162 return function(stream, state) {
163 while (!stream.eol()) {
164 var ch = stream.next();
165 if (ch === '\\') stream.next();
166 if (ch === endChar) {
167 state.inline = state.f = next;
168 return type;
169 }
170 }
171 return type;
172 };
173 }
174
175 return {
176 startState: function() {
177 return {
178 f: blockNormal,
179
180 block: blockNormal,
181 htmlState: htmlMode.startState(),
182 indentation: 0,
183
184 inline: inlineNormal,
185 em: false,
186 strong: false
187 };
188 },
189
190 copyState: function(s) {
191 return {
192 f: s.f,
193
194 block: s.block,
195 htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
196 indentation: s.indentation,
197
198 inline: s.inline,
199 em: s.em,
200 strong: s.strong
201 };
202 },
203
204 token: function(stream, state) {
205 if (stream.sol()) {
206 state.f = state.block;
207 var previousIndentation = state.indentation
208 , currentIndentation = 0;
209 while (previousIndentation > 0) {
210 if (stream.eat(' ')) {
211 previousIndentation--;
212 currentIndentation++;
213 } else if (previousIndentation >= 4 && stream.eat('\t')) {
214 previousIndentation -= 4;
215 currentIndentation += 4;
216 } else {
217 break;
218 }
219 }
220 state.indentation = currentIndentation;
221
222 if (currentIndentation > 0) return null;
223 }
224 return state.f(stream, state);
225 }
226 };
227
228 });
229
230 CodeMirror.defineMIME("text/x-markdown", "markdown");
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/LICENSE to IPython/frontend/html/notebook/static/codemirror/LICENSE
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/README.md to IPython/frontend/html/notebook/static/codemirror/README.md
@@ -1,67 +1,68 b''
1 1 .CodeMirror {
2 2 line-height: 1em;
3 3 font-family: monospace;
4 4 }
5 5
6 6 .CodeMirror-scroll {
7 7 overflow: auto;
8 8 height: 300px;
9 9 /* This is needed to prevent an IE[67] bug where the scrolled content
10 10 is visible outside of the scrolling box. */
11 11 position: relative;
12 12 }
13 13
14 14 .CodeMirror-gutter {
15 15 position: absolute; left: 0; top: 0;
16 z-index: 10;
16 17 background-color: #f7f7f7;
17 18 border-right: 1px solid #eee;
18 19 min-width: 2em;
19 20 height: 100%;
20 21 }
21 22 .CodeMirror-gutter-text {
22 23 color: #aaa;
23 24 text-align: right;
24 25 padding: .4em .2em .4em .4em;
25 26 }
26 27 .CodeMirror-lines {
27 28 padding: .4em;
28 29 }
29 30
30 31 .CodeMirror pre {
31 32 -moz-border-radius: 0;
32 33 -webkit-border-radius: 0;
33 34 -o-border-radius: 0;
34 35 border-radius: 0;
35 36 border-width: 0; margin: 0; padding: 0; background: transparent;
36 37 font-family: inherit;
37 38 font-size: inherit;
38 39 padding: 0; margin: 0;
39 40 white-space: pre;
40 41 word-wrap: normal;
41 42 }
42 43
43 44 .CodeMirror textarea {
44 45 font-family: inherit !important;
45 46 font-size: inherit !important;
46 47 }
47 48
48 49 .CodeMirror-cursor {
49 50 z-index: 10;
50 51 position: absolute;
51 52 visibility: hidden;
52 53 border-left: 1px solid black !important;
53 54 }
54 55 .CodeMirror-focused .CodeMirror-cursor {
55 56 visibility: visible;
56 57 }
57 58
58 59 span.CodeMirror-selected {
59 60 background: #ccc !important;
60 61 color: HighlightText !important;
61 62 }
62 63 .CodeMirror-focused span.CodeMirror-selected {
63 64 background: Highlight !important;
64 65 }
65 66
66 67 .CodeMirror-matchingbracket {color: #0f0 !important;}
67 68 .CodeMirror-nonmatchingbracket {color: #f22 !important;}
@@ -1,2144 +1,2197 b''
1 1 // All functions that need access to the editor's state live inside
2 2 // the CodeMirror function. Below that, at the bottom of the file,
3 3 // some utilities are defined.
4 4
5 5 // CodeMirror is the only global var we claim
6 6 var CodeMirror = (function() {
7 7 // This is the function that produces an editor instance. It's
8 8 // closure is used to store the editor state.
9 9 function CodeMirror(place, givenOptions) {
10 10 // Determine effective options based on given values and defaults.
11 11 var options = {}, defaults = CodeMirror.defaults;
12 12 for (var opt in defaults)
13 13 if (defaults.hasOwnProperty(opt))
14 14 options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15 15
16 16 var targetDocument = options["document"];
17 17 // The element in which the editor lives.
18 18 var wrapper = targetDocument.createElement("div");
19 19 wrapper.className = "CodeMirror";
20 20 // This mess creates the base DOM structure for the editor.
21 21 wrapper.innerHTML =
22 22 '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23 '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
23 '<textarea style="position: absolute; width: 2px;" wrap="off" ' +
24 'autocorrect="off" autocapitalize="off"></textarea></div>' +
24 25 '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
25 26 '<div style="position: relative">' + // Set to the height of the text, causes scrolling
26 27 '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
27 28 '<div style="position: relative">' + // Moved around its parent to cover visible view
28 29 '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29 30 // Provides positioning relative to (visible) text origin
30 '<div class="CodeMirror-lines"><div style="position: relative">' +
31 '<div class="CodeMirror-lines"><div style="position: relative" draggable="true">' +
31 32 '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32 33 '<div></div>' + // This DIV contains the actual code
33 34 '</div></div></div></div></div>';
34 35 if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
35 36 // I've never seen more elegant code in my life.
36 37 var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
37 38 scroller = wrapper.lastChild, code = scroller.firstChild,
38 39 measure = code.firstChild, mover = measure.nextSibling,
39 40 gutter = mover.firstChild, gutterText = gutter.firstChild,
40 41 lineSpace = gutter.nextSibling.firstChild,
41 42 cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
42 43 if (options.tabindex != null) input.tabindex = options.tabindex;
43 44 if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
44 45
45 46 // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
46 47 var poll = new Delayed(), highlight = new Delayed(), blinker;
47 48
48 49 // mode holds a mode API object. lines an array of Line objects
49 50 // (see Line constructor), work an array of lines that should be
50 51 // parsed, and history the undo history (instance of History
51 52 // constructor).
52 53 var mode, lines = [new Line("")], work, history = new History(), focused;
53 54 loadMode();
54 55 // The selection. These are always maintained to point at valid
55 56 // positions. Inverted is used to remember that the user is
56 57 // selecting bottom-to-top.
57 58 var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
58 59 // Selection-related flags. shiftSelecting obviously tracks
59 60 // whether the user is holding shift. reducedSelection is a hack
60 61 // to get around the fact that we can't create inverted
61 62 // selections. See below.
62 var shiftSelecting, reducedSelection, lastDoubleClick;
63 var shiftSelecting, reducedSelection, lastClick, lastDoubleClick;
63 64 // Variables used by startOperation/endOperation to track what
64 65 // happened during the operation.
65 var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
66 var updateInput, changes, textChanged, selectionChanged, leaveInputAlone, gutterDirty;
66 67 // Current visible range (may be bigger than the view window).
67 68 var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
68 69 // editing will hold an object describing the things we put in the
69 70 // textarea, to help figure out whether something changed.
70 71 // bracketHighlighted is used to remember that a backet has been
71 72 // marked.
72 73 var editing, bracketHighlighted;
73 74 // Tracks the maximum line length so that the horizontal scrollbar
74 75 // can be kept static when scrolling.
75 76 var maxLine = "", maxWidth;
76 77
77 78 // Initialize the content.
78 79 operation(function(){setValue(options.value || ""); updateInput = false;})();
79 80
80 81 // Register our event handlers.
81 82 connect(scroller, "mousedown", operation(onMouseDown));
83 connect(lineSpace, "dragstart", onDragStart);
82 84 // Gecko browsers fire contextmenu *after* opening the menu, at
83 85 // which point we can't mess with it anymore. Context menu is
84 86 // handled in onMouseDown for Gecko.
85 87 if (!gecko) connect(scroller, "contextmenu", onContextMenu);
86 connect(code, "dblclick", operation(onDblClick));
87 connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
88 connect(scroller, "scroll", function() {
89 updateDisplay([]);
90 if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px";
91 if (options.onScroll) options.onScroll(instance);
92 });
88 93 connect(window, "resize", function() {updateDisplay(true);});
89 94 connect(input, "keyup", operation(onKeyUp));
90 95 connect(input, "keydown", operation(onKeyDown));
91 96 connect(input, "keypress", operation(onKeyPress));
92 97 connect(input, "focus", onFocus);
93 98 connect(input, "blur", onBlur);
94 99
95 100 connect(scroller, "dragenter", e_stop);
96 101 connect(scroller, "dragover", e_stop);
97 102 connect(scroller, "drop", operation(onDrop));
98 103 connect(scroller, "paste", function(){focusInput(); fastPoll();});
99 104 connect(input, "paste", function(){fastPoll();});
100 105 connect(input, "cut", function(){fastPoll();});
101 106
102 107 // IE throws unspecified error in certain cases, when
103 108 // trying to access activeElement before onload
104 109 var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
105 110 if (hasFocus) setTimeout(onFocus, 20);
106 111 else onBlur();
107 112
108 113 function isLine(l) {return l >= 0 && l < lines.length;}
109 114 // The instance object that we'll return. Mostly calls out to
110 115 // local functions in the CodeMirror function. Some do some extra
111 116 // range checking and/or clipping. operation is used to wrap the
112 117 // call so that changes it makes are tracked, and the display is
113 118 // updated afterwards.
114 var instance = {
119 var instance = wrapper.CodeMirror = {
115 120 getValue: getValue,
116 121 setValue: operation(setValue),
117 122 getSelection: getSelection,
118 123 replaceSelection: operation(replaceSelection),
119 124 focus: function(){focusInput(); onFocus(); fastPoll();},
120 125 setOption: function(option, value) {
121 126 options[option] = value;
122 if (option == "lineNumbers" || option == "gutter") gutterChanged();
127 if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber")
128 operation(gutterChanged)();
123 129 else if (option == "mode" || option == "indentUnit") loadMode();
124 130 else if (option == "readOnly" && value == "nocursor") input.blur();
125 131 else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
126 132 },
127 133 getOption: function(option) {return options[option];},
128 134 undo: operation(undo),
129 135 redo: operation(redo),
130 indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
136 indentLine: operation(function(n, dir) {
137 if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
138 }),
131 139 historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
132 140 matchBrackets: operation(function(){matchBrackets(true);}),
133 141 getTokenAt: function(pos) {
134 142 pos = clipPos(pos);
135 143 return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
136 144 },
137 145 getStateAfter: function(line) {
138 146 line = clipLine(line == null ? lines.length - 1: line);
139 147 return getStateBefore(line + 1);
140 148 },
141 149 cursorCoords: function(start){
142 150 if (start == null) start = sel.inverted;
143 151 return pageCoords(start ? sel.from : sel.to);
144 152 },
145 153 charCoords: function(pos){return pageCoords(clipPos(pos));},
146 154 coordsChar: function(coords) {
147 155 var off = eltOffset(lineSpace);
148 156 var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
149 157 return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
150 158 },
151 159 getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
152 160 markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
153 setMarker: addGutterMarker,
154 clearMarker: removeGutterMarker,
161 setMarker: operation(addGutterMarker),
162 clearMarker: operation(removeGutterMarker),
155 163 setLineClass: operation(setLineClass),
156 164 lineInfo: lineInfo,
157 addWidget: function(pos, node, scroll, where) {
165 addWidget: function(pos, node, scroll, vert, horiz) {
158 166 pos = localCoords(clipPos(pos));
159 167 var top = pos.yBot, left = pos.x;
160 168 node.style.position = "absolute";
161 169 code.appendChild(node);
162 node.style.left = left + "px";
163 if (where == "over") top = pos.y;
164 else if (where == "near") {
170 if (vert == "over") top = pos.y;
171 else if (vert == "near") {
165 172 var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
166 173 hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
167 174 if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
168 175 top = pos.y - node.offsetHeight;
169 176 if (left + node.offsetWidth > hspace)
170 177 left = hspace - node.offsetWidth;
171 178 }
172 179 node.style.top = (top + paddingTop()) + "px";
180 node.style.left = node.style.right = "";
181 if (horiz == "right") {
182 left = code.clientWidth - node.offsetWidth;
183 node.style.right = "0px";
184 } else {
185 if (horiz == "left") left = 0;
186 else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2;
173 187 node.style.left = (left + paddingLeft()) + "px";
188 }
174 189 if (scroll)
175 190 scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
176 191 },
177 192
178 193 lineCount: function() {return lines.length;},
179 194 getCursor: function(start) {
180 195 if (start == null) start = sel.inverted;
181 196 return copyPos(start ? sel.from : sel.to);
182 197 },
183 198 somethingSelected: function() {return !posEq(sel.from, sel.to);},
184 199 setCursor: operation(function(line, ch) {
185 200 if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
186 201 else setCursor(line, ch);
187 202 }),
188 203 setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
189 204 getLine: function(line) {if (isLine(line)) return lines[line].text;},
190 205 setLine: operation(function(line, text) {
191 206 if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
192 207 }),
193 208 removeLine: operation(function(line) {
194 209 if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
195 210 }),
196 211 replaceRange: operation(replaceRange),
197 212 getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
198 213
199 214 operation: function(f){return operation(f)();},
200 215 refresh: function(){updateDisplay(true);},
201 216 getInputField: function(){return input;},
202 217 getWrapperElement: function(){return wrapper;},
203 getScrollerElement: function(){return scroller;}
218 getScrollerElement: function(){return scroller;},
219 getGutterElement: function(){return gutter;}
204 220 };
205 221
206 222 function setValue(code) {
207 223 history = null;
208 224 var top = {line: 0, ch: 0};
209 225 updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
210 226 splitLines(code), top, top);
211 227 history = new History();
228 updateInput = true;
212 229 }
213 230 function getValue(code) {
214 231 var text = [];
215 232 for (var i = 0, l = lines.length; i < l; ++i)
216 233 text.push(lines[i].text);
217 234 return text.join("\n");
218 235 }
219 236
220 237 function onMouseDown(e) {
221 238 // Check whether this is a click in a widget
222 239 for (var n = e_target(e); n != wrapper; n = n.parentNode)
223 240 if (n.parentNode == code && n != mover) return;
224 var ld = lastDoubleClick; lastDoubleClick = null;
241
225 242 // First, see if this is a click in the gutter
226 243 for (var n = e_target(e); n != wrapper; n = n.parentNode)
227 244 if (n.parentNode == gutterText) {
228 245 if (options.onGutterClick)
229 options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
246 options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e);
230 247 return e_preventDefault(e);
231 248 }
232 249
233 250 var start = posFromMouse(e);
234 251
235 252 switch (e_button(e)) {
236 253 case 3:
237 254 if (gecko && !mac) onContextMenu(e);
238 255 return;
239 256 case 2:
240 257 if (start) setCursor(start.line, start.ch, true);
241 258 return;
242 259 }
243 260 // For button 1, if it was clicked inside the editor
244 261 // (posFromMouse returning non-null), we have to adjust the
245 262 // selection.
246 263 if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;}
247 264
248 265 if (!focused) onFocus();
266
267 var now = +new Date;
268 if (lastDoubleClick > now - 400) {
249 269 e_preventDefault(e);
250 if (ld && +new Date - ld < 400) return selectLine(start.line);
270 return selectLine(start.line);
271 } else if (lastClick > now - 400) {
272 lastDoubleClick = now;
273 e_preventDefault(e);
274 return selectWordAt(start);
275 } else { lastClick = now; }
251 276
252 setCursor(start.line, start.ch, true);
253 277 var last = start, going;
254 // And then we have to see if it's a drag event, in which case
255 // the dragged-over text must be selected.
256 function end() {
257 focusInput();
258 updateInput = true;
259 move(); up();
278 if (dragAndDrop && !posEq(sel.from, sel.to) &&
279 !posLess(start, sel.from) && !posLess(sel.to, start)) {
280 // Let the drag handler handle this.
281 return;
260 282 }
283 e_preventDefault(e);
284 setCursor(start.line, start.ch, true);
285
261 286 function extend(e) {
262 287 var cur = posFromMouse(e, true);
263 288 if (cur && !posEq(cur, last)) {
264 289 if (!focused) onFocus();
265 290 last = cur;
266 291 setSelectionUser(start, cur);
267 292 updateInput = false;
268 293 var visible = visibleLines();
269 294 if (cur.line >= visible.to || cur.line < visible.from)
270 295 going = setTimeout(operation(function(){extend(e);}), 150);
271 296 }
272 297 }
273 298
274 299 var move = connect(targetDocument, "mousemove", operation(function(e) {
275 300 clearTimeout(going);
276 301 e_preventDefault(e);
277 302 extend(e);
278 303 }), true);
279 304 var up = connect(targetDocument, "mouseup", operation(function(e) {
280 305 clearTimeout(going);
281 306 var cur = posFromMouse(e);
282 307 if (cur) setSelectionUser(start, cur);
283 308 e_preventDefault(e);
284 end();
309 focusInput();
310 updateInput = true;
311 move(); up();
285 312 }), true);
286 313 }
287 function onDblClick(e) {
288 var pos = posFromMouse(e);
289 if (!pos) return;
290 selectWordAt(pos);
291 e_preventDefault(e);
292 lastDoubleClick = +new Date;
293 }
294 314 function onDrop(e) {
295 315 e.preventDefault();
296 316 var pos = posFromMouse(e, true), files = e.dataTransfer.files;
297 317 if (!pos || options.readOnly) return;
298 318 if (files && files.length && window.FileReader && window.File) {
299 319 function loadFile(file, i) {
300 320 var reader = new FileReader;
301 321 reader.onload = function() {
302 322 text[i] = reader.result;
303 323 if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
304 324 };
305 325 reader.readAsText(file);
306 326 }
307 327 var n = files.length, text = Array(n), read = 0;
308 328 for (var i = 0; i < n; ++i) loadFile(files[i], i);
309 329 }
310 330 else {
311 331 try {
312 332 var text = e.dataTransfer.getData("Text");
313 333 if (text) replaceRange(text, pos, pos);
314 334 }
315 335 catch(e){}
316 336 }
317 337 }
338 function onDragStart(e) {
339 var txt = getSelection();
340 // This will reset escapeElement
341 htmlEscape(txt);
342 e.dataTransfer.setDragImage(escapeElement, 0, 0);
343 e.dataTransfer.setData("Text", txt);
344 }
318 345 function onKeyDown(e) {
319 346 if (!focused) onFocus();
320 347
321 348 var code = e.keyCode;
322 349 // IE does strange things with escape.
323 350 if (ie && code == 27) { e.returnValue = false; }
324 351 // Tries to detect ctrl on non-mac, cmd on mac.
325 352 var mod = (mac ? e.metaKey : e.ctrlKey) && !e.altKey, anyMod = e.ctrlKey || e.altKey || e.metaKey;
326 353 if (code == 16 || e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
327 354 else shiftSelecting = null;
328 355 // First give onKeyEvent option a chance to handle this.
329 356 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
330 357
331 358 if (code == 33 || code == 34) {scrollPage(code == 34); return e_preventDefault(e);} // page up/down
332 359 if (mod && ((code == 36 || code == 35) || // ctrl-home/end
333 360 mac && (code == 38 || code == 40))) { // cmd-up/down
334 361 scrollEnd(code == 36 || code == 38); return e_preventDefault(e);
335 362 }
336 363 if (mod && code == 65) {selectAll(); return e_preventDefault(e);} // ctrl-a
337 364 if (!options.readOnly) {
338 365 if (!anyMod && code == 13) {return;} // enter
339 366 if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
340 367 if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
341 368 if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
342 369 }
370 if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
343 371
344 372 // Key id to use in the movementKeys map. We also pass it to
345 373 // fastPoll in order to 'self learn'. We need this because
346 374 // reducedSelection, the hack where we collapse the selection to
347 375 // its start when it is inverted and a movement key is pressed
348 376 // (and later restore it again), shouldn't be used for
349 377 // non-movement keys.
350 curKeyId = (mod ? "c" : "") + code;
351 if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
378 curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
379 if (sel.inverted && movementKeys[curKeyId] === true) {
352 380 var range = selRange(input);
353 381 if (range) {
354 382 reducedSelection = {anchor: range.start};
355 383 setSelRange(input, range.start, range.start);
356 384 }
357 385 }
386 // Don't save the key as a movementkey unless it had a modifier
387 if (!mod && !e.altKey) curKeyId = null;
358 388 fastPoll(curKeyId);
359 389 }
360 390 function onKeyUp(e) {
361 391 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
362 392 if (reducedSelection) {
363 393 reducedSelection = null;
364 394 updateInput = true;
365 395 }
366 396 if (e.keyCode == 16) shiftSelecting = null;
367 397 }
368 398 function onKeyPress(e) {
369 399 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
370 400 if (options.electricChars && mode.electricChars) {
371 401 var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode);
372 402 if (mode.electricChars.indexOf(ch) > -1)
373 403 setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
374 404 }
375 405 var code = e.keyCode;
376 406 // Re-stop tab and enter. Necessary on some browsers.
377 407 if (code == 13) {if (!options.readOnly) handleEnter(); e_preventDefault(e);}
378 408 else if (!e.ctrlKey && !e.altKey && !e.metaKey && code == 9 && options.tabMode != "default") e_preventDefault(e);
379 409 else fastPoll(curKeyId);
380 410 }
381 411
382 412 function onFocus() {
383 413 if (options.readOnly == "nocursor") return;
384 414 if (!focused) {
385 415 if (options.onFocus) options.onFocus(instance);
386 416 focused = true;
387 417 if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
388 418 wrapper.className += " CodeMirror-focused";
389 419 if (!leaveInputAlone) prepareInput();
390 420 }
391 421 slowPoll();
392 422 restartBlink();
393 423 }
394 424 function onBlur() {
395 425 if (focused) {
396 426 if (options.onBlur) options.onBlur(instance);
397 427 focused = false;
398 428 wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
399 429 }
400 430 clearInterval(blinker);
401 431 setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
402 432 }
403 433
404 434 // Replace the range from from to to by the strings in newText.
405 435 // Afterwards, set the selection to selFrom, selTo.
406 436 function updateLines(from, to, newText, selFrom, selTo) {
407 437 if (history) {
408 438 var old = [];
409 439 for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
410 440 history.addChange(from.line, newText.length, old);
411 441 while (history.done.length > options.undoDepth) history.done.shift();
412 442 }
413 443 updateLinesNoUndo(from, to, newText, selFrom, selTo);
414 444 }
415 445 function unredoHelper(from, to) {
416 446 var change = from.pop();
417 447 if (change) {
418 448 var replaced = [], end = change.start + change.added;
419 449 for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
420 450 to.push({start: change.start, added: change.old.length, old: replaced});
421 451 var pos = clipPos({line: change.start + change.old.length - 1,
422 452 ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
423 453 updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
424 454 updateInput = true;
425 455 }
426 456 }
427 457 function undo() {unredoHelper(history.done, history.undone);}
428 458 function redo() {unredoHelper(history.undone, history.done);}
429 459
430 460 function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
431 461 var recomputeMaxLength = false, maxLineLength = maxLine.length;
432 462 for (var i = from.line; i <= to.line; ++i) {
433 463 if (lines[i].text.length == maxLineLength) {recomputeMaxLength = true; break;}
434 464 }
435 465
436 466 var nlines = to.line - from.line, firstLine = lines[from.line], lastLine = lines[to.line];
437 467 // First adjust the line structure, taking some care to leave highlighting intact.
438 468 if (firstLine == lastLine) {
439 469 if (newText.length == 1)
440 470 firstLine.replace(from.ch, to.ch, newText[0]);
441 471 else {
442 472 lastLine = firstLine.split(to.ch, newText[newText.length-1]);
443 473 var spliceargs = [from.line + 1, nlines];
444 474 firstLine.replace(from.ch, firstLine.text.length, newText[0]);
445 475 for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
446 476 spliceargs.push(lastLine);
447 477 lines.splice.apply(lines, spliceargs);
448 478 }
449 479 }
450 480 else if (newText.length == 1) {
451 481 firstLine.replace(from.ch, firstLine.text.length, newText[0] + lastLine.text.slice(to.ch));
452 482 lines.splice(from.line + 1, nlines);
453 483 }
454 484 else {
455 485 var spliceargs = [from.line + 1, nlines - 1];
456 486 firstLine.replace(from.ch, firstLine.text.length, newText[0]);
457 487 lastLine.replace(0, to.ch, newText[newText.length-1]);
458 488 for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
459 489 lines.splice.apply(lines, spliceargs);
460 490 }
461 491
462 492
463 493 for (var i = from.line, e = i + newText.length; i < e; ++i) {
464 494 var l = lines[i].text;
465 495 if (l.length > maxLineLength) {
466 496 maxLine = l; maxLineLength = l.length; maxWidth = null;
467 497 recomputeMaxLength = false;
468 498 }
469 499 }
470 500 if (recomputeMaxLength) {
471 501 maxLineLength = 0; maxLine = ""; maxWidth = null;
472 502 for (var i = 0, e = lines.length; i < e; ++i) {
473 503 var l = lines[i].text;
474 504 if (l.length > maxLineLength) {
475 505 maxLineLength = l.length; maxLine = l;
476 506 }
477 507 }
478 508 }
479 509
480 510 // Add these lines to the work array, so that they will be
481 511 // highlighted. Adjust work lines if lines were added/removed.
482 512 var newWork = [], lendiff = newText.length - nlines - 1;
483 513 for (var i = 0, l = work.length; i < l; ++i) {
484 514 var task = work[i];
485 515 if (task < from.line) newWork.push(task);
486 516 else if (task > to.line) newWork.push(task + lendiff);
487 517 }
488 518 if (newText.length < 5) {
489 519 highlightLines(from.line, from.line + newText.length);
490 520 newWork.push(from.line + newText.length);
491 521 } else {
492 522 newWork.push(from.line);
493 523 }
494 524 work = newWork;
495 525 startWorker(100);
496 526 // Remember that these lines changed, for updating the display
497 527 changes.push({from: from.line, to: to.line + 1, diff: lendiff});
498 528 textChanged = {from: from, to: to, text: newText};
499 529
500 530 // Update the selection
501 531 function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
502 532 setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
503 533
504 534 // Make sure the scroll-size div has the correct height.
505 535 code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
506 536 }
507 537
508 538 function replaceRange(code, from, to) {
509 539 from = clipPos(from);
510 540 if (!to) to = from; else to = clipPos(to);
511 541 code = splitLines(code);
512 542 function adjustPos(pos) {
513 543 if (posLess(pos, from)) return pos;
514 544 if (!posLess(to, pos)) return end;
515 545 var line = pos.line + code.length - (to.line - from.line) - 1;
516 546 var ch = pos.ch;
517 547 if (pos.line == to.line)
518 548 ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0));
519 549 return {line: line, ch: ch};
520 550 }
521 551 var end;
522 552 replaceRange1(code, from, to, function(end1) {
523 553 end = end1;
524 554 return {from: adjustPos(sel.from), to: adjustPos(sel.to)};
525 555 });
526 556 return end;
527 557 }
528 558 function replaceSelection(code, collapse) {
529 559 replaceRange1(splitLines(code), sel.from, sel.to, function(end) {
530 560 if (collapse == "end") return {from: end, to: end};
531 561 else if (collapse == "start") return {from: sel.from, to: sel.from};
532 562 else return {from: sel.from, to: end};
533 563 });
534 564 }
535 565 function replaceRange1(code, from, to, computeSel) {
536 566 var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length;
537 567 var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
538 568 updateLines(from, to, code, newSel.from, newSel.to);
539 569 }
540 570
541 571 function getRange(from, to) {
542 572 var l1 = from.line, l2 = to.line;
543 573 if (l1 == l2) return lines[l1].text.slice(from.ch, to.ch);
544 574 var code = [lines[l1].text.slice(from.ch)];
545 575 for (var i = l1 + 1; i < l2; ++i) code.push(lines[i].text);
546 576 code.push(lines[l2].text.slice(0, to.ch));
547 577 return code.join("\n");
548 578 }
549 579 function getSelection() {
550 580 return getRange(sel.from, sel.to);
551 581 }
552 582
553 583 var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
554 584 function slowPoll() {
555 585 if (pollingFast) return;
556 586 poll.set(2000, function() {
557 587 startOperation();
558 588 readInput();
559 589 if (focused) slowPoll();
560 590 endOperation();
561 591 });
562 592 }
563 593 function fastPoll(keyId) {
564 594 var missed = false;
565 595 pollingFast = true;
566 596 function p() {
567 597 startOperation();
568 598 var changed = readInput();
569 if (changed == "moved" && keyId) movementKeys[keyId] = true;
599 if (changed && keyId) {
600 if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
601 if (changed == "changed") movementKeys[keyId] = false;
602 }
570 603 if (!changed && !missed) {missed = true; poll.set(80, p);}
571 604 else {pollingFast = false; slowPoll();}
572 605 endOperation();
573 606 }
574 607 poll.set(20, p);
575 608 }
576 609
577 610 // Inspects the textarea, compares its state (content, selection)
578 611 // to the data in the editing variable, and updates the editor
579 612 // content or cursor if something changed.
580 613 function readInput() {
581 614 if (leaveInputAlone || !focused) return;
582 615 var changed = false, text = input.value, sr = selRange(input);
583 616 if (!sr) return false;
584 617 var changed = editing.text != text, rs = reducedSelection;
585 618 var moved = changed || sr.start != editing.start || sr.end != (rs ? editing.start : editing.end);
586 619 if (!moved && !rs) return false;
587 620 if (changed) {
588 621 shiftSelecting = reducedSelection = null;
589 622 if (options.readOnly) {updateInput = true; return "changed";}
590 623 }
591 624
592 625 // Compute selection start and end based on start/end offsets in textarea
593 626 function computeOffset(n, startLine) {
594 627 var pos = 0;
595 628 for (;;) {
596 629 var found = text.indexOf("\n", pos);
597 630 if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
598 631 return {line: startLine, ch: n - pos};
599 632 ++startLine;
600 633 pos = found + 1;
601 634 }
602 635 }
603 636 var from = computeOffset(sr.start, editing.from),
604 637 to = computeOffset(sr.end, editing.from);
605 638 // Here we have to take the reducedSelection hack into account,
606 639 // so that you can, for example, press shift-up at the start of
607 640 // your selection and have the right thing happen.
608 641 if (rs) {
609 642 var head = sr.start == rs.anchor ? to : from;
610 643 var tail = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
611 644 if (sel.inverted = posLess(head, tail)) { from = head; to = tail; }
612 645 else { reducedSelection = null; from = tail; to = head; }
613 646 }
614 647
615 648 // In some cases (cursor on same line as before), we don't have
616 649 // to update the textarea content at all.
617 650 if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
618 651 updateInput = false;
619 652
620 653 // Magic mess to extract precise edited range from the changed
621 654 // string.
622 655 if (changed) {
623 656 var start = 0, end = text.length, len = Math.min(end, editing.text.length);
624 657 var c, line = editing.from, nl = -1;
625 658 while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
626 659 ++start;
627 660 if (c == "\n") {line++; nl = start;}
628 661 }
629 662 var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
630 663 for (;;) {
631 664 c = editing.text.charAt(edend);
632 665 if (text.charAt(end) != c) {++end; ++edend; break;}
633 666 if (c == "\n") endline--;
634 667 if (edend <= start || end <= start) break;
635 668 --end; --edend;
636 669 }
637 670 var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
638 671 updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
639 672 if (line != endline || from.line != line) updateInput = true;
640 673 }
641 674 else setSelection(from, to);
642 675
643 676 editing.text = text; editing.start = sr.start; editing.end = sr.end;
644 677 return changed ? "changed" : moved ? "moved" : false;
645 678 }
646 679
647 680 // Set the textarea content and selection range to match the
648 681 // editor state.
649 682 function prepareInput() {
650 683 var text = [];
651 684 var from = Math.max(0, sel.from.line - 1), to = Math.min(lines.length, sel.to.line + 2);
652 685 for (var i = from; i < to; ++i) text.push(lines[i].text);
653 686 text = input.value = text.join(lineSep);
654 687 var startch = sel.from.ch, endch = sel.to.ch;
655 688 for (var i = from; i < sel.from.line; ++i)
656 689 startch += lineSep.length + lines[i].text.length;
657 690 for (var i = from; i < sel.to.line; ++i)
658 691 endch += lineSep.length + lines[i].text.length;
659 692 editing = {text: text, from: from, to: to, start: startch, end: endch};
660 693 setSelRange(input, startch, reducedSelection ? startch : endch);
661 694 }
662 695 function focusInput() {
663 696 if (options.readOnly != "nocursor") input.focus();
664 697 }
665 698
699 function scrollEditorIntoView() {
700 if (!cursor.getBoundingClientRect) return;
701 var rect = cursor.getBoundingClientRect();
702 var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
703 if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
704 }
666 705 function scrollCursorIntoView() {
667 706 var cursor = localCoords(sel.inverted ? sel.from : sel.to);
668 707 return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
669 708 }
670 709 function scrollIntoView(x1, y1, x2, y2) {
671 710 var pl = paddingLeft(), pt = paddingTop(), lh = lineHeight();
672 711 y1 += pt; y2 += pt; x1 += pl; x2 += pl;
673 712 var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true;
674 713 if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;}
675 714 else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;}
676 715
677 716 var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
678 if (x1 < screenleft) {
717 var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
718 if (x1 < screenleft + gutterw) {
679 719 if (x1 < 50) x1 = 0;
680 scroller.scrollLeft = Math.max(0, x1 - 10);
720 scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw);
681 721 scrolled = true;
682 722 }
683 723 else if (x2 > screenw + screenleft) {
684 724 scroller.scrollLeft = x2 + 10 - screenw;
685 725 scrolled = true;
686 726 if (x2 > code.clientWidth) result = false;
687 727 }
688 728 if (scrolled && options.onScroll) options.onScroll(instance);
689 729 return result;
690 730 }
691 731
692 732 function visibleLines() {
693 733 var lh = lineHeight(), top = scroller.scrollTop - paddingTop();
694 734 return {from: Math.min(lines.length, Math.max(0, Math.floor(top / lh))),
695 735 to: Math.min(lines.length, Math.ceil((top + scroller.clientHeight) / lh))};
696 736 }
697 737 // Uses a set of changes plus the current scroll position to
698 738 // determine which DOM updates have to be made, and makes the
699 739 // updates.
700 740 function updateDisplay(changes) {
701 741 if (!scroller.clientWidth) {
702 742 showingFrom = showingTo = 0;
703 743 return;
704 744 }
705 745 // First create a range of theoretically intact lines, and punch
706 746 // holes in that using the change info.
707 747 var intact = changes === true ? [] : [{from: showingFrom, to: showingTo, domStart: 0}];
708 748 for (var i = 0, l = changes.length || 0; i < l; ++i) {
709 749 var change = changes[i], intact2 = [], diff = change.diff || 0;
710 750 for (var j = 0, l2 = intact.length; j < l2; ++j) {
711 751 var range = intact[j];
712 752 if (change.to <= range.from)
713 753 intact2.push({from: range.from + diff, to: range.to + diff, domStart: range.domStart});
714 754 else if (range.to <= change.from)
715 755 intact2.push(range);
716 756 else {
717 757 if (change.from > range.from)
718 758 intact2.push({from: range.from, to: change.from, domStart: range.domStart})
719 759 if (change.to < range.to)
720 760 intact2.push({from: change.to + diff, to: range.to + diff,
721 761 domStart: range.domStart + (change.to - range.from)});
722 762 }
723 763 }
724 764 intact = intact2;
725 765 }
726 766
727 767 // Then, determine which lines we'd want to see, and which
728 768 // updates have to be made to get there.
729 769 var visible = visibleLines();
730 770 var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
731 771 to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
732 772 updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
733 773
734 774 for (var i = 0, l = intact.length; i < l; ++i) {
735 775 var range = intact[i];
736 776 if (range.to <= from) continue;
737 777 if (range.from >= to) break;
738 778 if (range.domStart > domPos || range.from > pos) {
739 779 updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
740 780 changedLines += range.from - pos;
741 781 }
742 782 pos = range.to;
743 783 domPos = range.domStart + (range.to - range.from);
744 784 }
745 785 if (domPos != domEnd || pos != to) {
746 786 changedLines += Math.abs(to - pos);
747 787 updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
788 if (to - pos != domEnd - domPos) gutterDirty = true;
748 789 }
749 790
750 791 if (!updates.length) return;
751 792 lineDiv.style.display = "none";
752 793 // If more than 30% of the screen needs update, just do a full
753 794 // redraw (which is quicker than patching)
754 795 if (changedLines > (visible.to - visible.from) * .3)
755 796 refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
756 797 // Otherwise, only update the stuff that needs updating.
757 798 else
758 799 patchDisplay(updates);
759 800 lineDiv.style.display = "";
760 801
761 802 // Position the mover div to align with the lines it's supposed
762 803 // to be showing (which will cover the visible display)
763 804 var different = from != showingFrom || to != showingTo || lastHeight != scroller.clientHeight;
764 805 showingFrom = from; showingTo = to;
765 806 mover.style.top = (from * lineHeight()) + "px";
766 807 if (different) {
767 808 lastHeight = scroller.clientHeight;
768 809 code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
769 updateGutter();
770 810 }
811 if (different || gutterDirty) updateGutter();
771 812
772 813 if (maxWidth == null) maxWidth = stringWidth(maxLine);
773 814 if (maxWidth > scroller.clientWidth) {
774 815 lineSpace.style.width = maxWidth + "px";
775 816 // Needed to prevent odd wrapping/hiding of widgets placed in here.
776 817 code.style.width = "";
777 818 code.style.width = scroller.scrollWidth + "px";
778 819 } else {
779 820 lineSpace.style.width = code.style.width = "";
780 821 }
781 822
782 823 // Since this is all rather error prone, it is honoured with the
783 824 // only assertion in the whole file.
784 825 if (lineDiv.childNodes.length != showingTo - showingFrom)
785 826 throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
786 827 " nodes=" + lineDiv.childNodes.length);
787 828 updateCursor();
788 829 }
789 830
790 831 function refreshDisplay(from, to) {
791 832 var html = [], start = {line: from, ch: 0}, inSel = posLess(sel.from, start) && !posLess(sel.to, start);
792 833 for (var i = from; i < to; ++i) {
793 834 var ch1 = null, ch2 = null;
794 835 if (inSel) {
795 836 ch1 = 0;
796 837 if (sel.to.line == i) {inSel = false; ch2 = sel.to.ch;}
797 838 }
798 839 else if (sel.from.line == i) {
799 840 if (sel.to.line == i) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
800 841 else {inSel = true; ch1 = sel.from.ch;}
801 842 }
802 843 html.push(lines[i].getHTML(ch1, ch2, true));
803 844 }
804 845 lineDiv.innerHTML = html.join("");
805 846 }
806 847 function patchDisplay(updates) {
807 848 // Slightly different algorithm for IE (badInnerHTML), since
808 849 // there .innerHTML on PRE nodes is dumb, and discards
809 850 // whitespace.
810 851 var sfrom = sel.from.line, sto = sel.to.line, off = 0,
811 852 scratch = badInnerHTML && targetDocument.createElement("div");
812 853 for (var i = 0, e = updates.length; i < e; ++i) {
813 854 var rec = updates[i];
814 855 var extra = (rec.to - rec.from) - rec.domSize;
815 856 var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
816 857 if (badInnerHTML)
817 858 for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
818 859 lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
819 860 else if (extra) {
820 861 for (var j = Math.max(0, extra); j > 0; --j)
821 862 lineDiv.insertBefore(targetDocument.createElement("pre"), nodeAfter);
822 863 for (var j = Math.max(0, -extra); j > 0; --j)
823 864 lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
824 865 }
825 866 var node = lineDiv.childNodes[rec.domStart + off], inSel = sfrom < rec.from && sto >= rec.from;
826 867 for (var j = rec.from; j < rec.to; ++j) {
827 868 var ch1 = null, ch2 = null;
828 869 if (inSel) {
829 870 ch1 = 0;
830 871 if (sto == j) {inSel = false; ch2 = sel.to.ch;}
831 872 }
832 873 else if (sfrom == j) {
833 874 if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
834 875 else {inSel = true; ch1 = sel.from.ch;}
835 876 }
836 877 if (badInnerHTML) {
837 878 scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
838 879 lineDiv.insertBefore(scratch.firstChild, nodeAfter);
839 880 }
840 881 else {
841 882 node.innerHTML = lines[j].getHTML(ch1, ch2, false);
842 883 node.className = lines[j].className || "";
843 884 node = node.nextSibling;
844 885 }
845 886 }
846 887 off += extra;
847 888 }
848 889 }
849 890
850 891 function updateGutter() {
851 892 if (!options.gutter && !options.lineNumbers) return;
852 893 var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
853 894 gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
854 895 var html = [];
855 896 for (var i = showingFrom; i < Math.max(showingTo, showingFrom + 1); ++i) {
856 897 var marker = lines[i].gutterMarker;
857 898 var text = options.lineNumbers ? i + options.firstLineNumber : null;
858 899 if (marker && marker.text)
859 900 text = marker.text.replace("%N%", text != null ? text : "");
860 901 else if (text == null)
861 902 text = "\u00a0";
862 903 html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text, "</pre>");
863 904 }
864 905 gutter.style.display = "none";
865 906 gutterText.innerHTML = html.join("");
866 907 var minwidth = String(lines.length).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
867 908 while (val.length + pad.length < minwidth) pad += "\u00a0";
868 909 if (pad) firstNode.insertBefore(targetDocument.createTextNode(pad), firstNode.firstChild);
869 910 gutter.style.display = "";
870 911 lineSpace.style.marginLeft = gutter.offsetWidth + "px";
912 gutterDirty = false;
871 913 }
872 914 function updateCursor() {
873 915 var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
874 var x = charX(head.line, head.ch) + "px", y = (head.line - showingFrom) * lh + "px";
875 inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
916 var x = charX(head.line, head.ch);
917 var top = head.line * lh - scroller.scrollTop;
918 inputDiv.style.top = Math.max(Math.min(top, scroller.offsetHeight), 0) + "px";
919 inputDiv.style.left = (x - scroller.scrollLeft) + "px";
876 920 if (posEq(sel.from, sel.to)) {
877 cursor.style.top = y; cursor.style.left = x;
921 cursor.style.top = (head.line - showingFrom) * lh + "px";
922 cursor.style.left = x + "px";
878 923 cursor.style.display = "";
879 924 }
880 925 else cursor.style.display = "none";
881 926 }
882 927
883 928 function setSelectionUser(from, to) {
884 929 var sh = shiftSelecting && clipPos(shiftSelecting);
885 930 if (sh) {
886 931 if (posLess(sh, from)) from = sh;
887 932 else if (posLess(to, sh)) to = sh;
888 933 }
889 934 setSelection(from, to);
890 935 }
891 936 // Update the selection. Last two args are only used by
892 937 // updateLines, since they have to be expressed in the line
893 938 // numbers before the update.
894 939 function setSelection(from, to, oldFrom, oldTo) {
895 940 if (posEq(sel.from, from) && posEq(sel.to, to)) return;
896 941 if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
897 942
898 943 if (posEq(from, to)) sel.inverted = false;
899 944 else if (posEq(from, sel.to)) sel.inverted = false;
900 945 else if (posEq(to, sel.from)) sel.inverted = true;
901 946
902 947 // Some ugly logic used to only mark the lines that actually did
903 948 // see a change in selection as changed, rather than the whole
904 949 // selected range.
905 950 if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
906 951 if (posEq(from, to)) {
907 952 if (!posEq(sel.from, sel.to))
908 953 changes.push({from: oldFrom, to: oldTo + 1});
909 954 }
910 955 else if (posEq(sel.from, sel.to)) {
911 956 changes.push({from: from.line, to: to.line + 1});
912 957 }
913 958 else {
914 959 if (!posEq(from, sel.from)) {
915 960 if (from.line < oldFrom)
916 961 changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
917 962 else
918 963 changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
919 964 }
920 965 if (!posEq(to, sel.to)) {
921 966 if (to.line < oldTo)
922 967 changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
923 968 else
924 969 changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
925 970 }
926 971 }
927 972 sel.from = from; sel.to = to;
928 973 selectionChanged = true;
929 974 }
930 975 function setCursor(line, ch, user) {
931 976 var pos = clipPos({line: line, ch: ch || 0});
932 977 (user ? setSelectionUser : setSelection)(pos, pos);
933 978 }
934 979
935 980 function clipLine(n) {return Math.max(0, Math.min(n, lines.length-1));}
936 981 function clipPos(pos) {
937 982 if (pos.line < 0) return {line: 0, ch: 0};
938 983 if (pos.line >= lines.length) return {line: lines.length-1, ch: lines[lines.length-1].text.length};
939 984 var ch = pos.ch, linelen = lines[pos.line].text.length;
940 985 if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
941 986 else if (ch < 0) return {line: pos.line, ch: 0};
942 987 else return pos;
943 988 }
944 989
945 990 function scrollPage(down) {
946 991 var linesPerPage = Math.floor(scroller.clientHeight / lineHeight()), head = sel.inverted ? sel.from : sel.to;
947 992 setCursor(head.line + (Math.max(linesPerPage - 1, 1) * (down ? 1 : -1)), head.ch, true);
948 993 }
949 994 function scrollEnd(top) {
950 995 var pos = top ? {line: 0, ch: 0} : {line: lines.length - 1, ch: lines[lines.length-1].text.length};
951 996 setSelectionUser(pos, pos);
952 997 }
953 998 function selectAll() {
954 999 var endLine = lines.length - 1;
955 1000 setSelection({line: 0, ch: 0}, {line: endLine, ch: lines[endLine].text.length});
956 1001 }
957 1002 function selectWordAt(pos) {
958 1003 var line = lines[pos.line].text;
959 1004 var start = pos.ch, end = pos.ch;
960 1005 while (start > 0 && /\w/.test(line.charAt(start - 1))) --start;
961 1006 while (end < line.length && /\w/.test(line.charAt(end))) ++end;
962 1007 setSelectionUser({line: pos.line, ch: start}, {line: pos.line, ch: end});
963 1008 }
964 1009 function selectLine(line) {
965 1010 setSelectionUser({line: line, ch: 0}, {line: line, ch: lines[line].text.length});
966 1011 }
967 1012 function handleEnter() {
968 1013 replaceSelection("\n", "end");
969 1014 if (options.enterMode != "flat")
970 1015 indentLine(sel.from.line, options.enterMode == "keep" ? "prev" : "smart");
971 1016 }
972 1017 function handleTab(shift) {
973 1018 function indentSelected(mode) {
974 1019 if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
975 1020 var e = sel.to.line - (sel.to.ch ? 0 : 1);
976 1021 for (var i = sel.from.line; i <= e; ++i) indentLine(i, mode);
977 1022 }
978 1023 shiftSelecting = null;
979 1024 switch (options.tabMode) {
980 1025 case "default":
981 1026 return false;
982 1027 case "indent":
983 1028 indentSelected("smart");
984 1029 break;
985 1030 case "classic":
986 1031 if (posEq(sel.from, sel.to)) {
987 1032 if (shift) indentLine(sel.from.line, "smart");
988 1033 else replaceSelection("\t", "end");
989 1034 break;
990 1035 }
991 1036 case "shift":
992 1037 indentSelected(shift ? "subtract" : "add");
993 1038 break;
994 1039 }
995 1040 return true;
996 1041 }
1042 function smartHome() {
1043 var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
1044 setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
1045 }
997 1046
998 1047 function indentLine(n, how) {
999 1048 if (how == "smart") {
1000 1049 if (!mode.indent) how = "prev";
1001 1050 else var state = getStateBefore(n);
1002 1051 }
1003 1052
1004 1053 var line = lines[n], curSpace = line.indentation(), curSpaceString = line.text.match(/^\s*/)[0], indentation;
1005 1054 if (how == "prev") {
1006 1055 if (n) indentation = lines[n-1].indentation();
1007 1056 else indentation = 0;
1008 1057 }
1009 1058 else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
1010 1059 else if (how == "add") indentation = curSpace + options.indentUnit;
1011 1060 else if (how == "subtract") indentation = curSpace - options.indentUnit;
1012 1061 indentation = Math.max(0, indentation);
1013 1062 var diff = indentation - curSpace;
1014 1063
1015 1064 if (!diff) {
1016 1065 if (sel.from.line != n && sel.to.line != n) return;
1017 1066 var indentString = curSpaceString;
1018 1067 }
1019 1068 else {
1020 1069 var indentString = "", pos = 0;
1021 1070 if (options.indentWithTabs)
1022 1071 for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
1023 1072 while (pos < indentation) {++pos; indentString += " ";}
1024 1073 }
1025 1074
1026 1075 replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
1027 1076 }
1028 1077
1029 1078 function loadMode() {
1030 1079 mode = CodeMirror.getMode(options, options.mode);
1031 1080 for (var i = 0, l = lines.length; i < l; ++i)
1032 1081 lines[i].stateAfter = null;
1033 1082 work = [0];
1034 1083 startWorker();
1035 1084 }
1036 1085 function gutterChanged() {
1037 1086 var visible = options.gutter || options.lineNumbers;
1038 1087 gutter.style.display = visible ? "" : "none";
1039 if (visible) updateGutter();
1088 if (visible) gutterDirty = true;
1040 1089 else lineDiv.parentNode.style.marginLeft = 0;
1041 1090 }
1042 1091
1043 1092 function markText(from, to, className) {
1044 1093 from = clipPos(from); to = clipPos(to);
1045 1094 var accum = [];
1046 1095 function add(line, from, to, className) {
1047 1096 var line = lines[line], mark = line.addMark(from, to, className);
1048 1097 mark.line = line;
1049 1098 accum.push(mark);
1050 1099 }
1051 1100 if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1052 1101 else {
1053 1102 add(from.line, from.ch, null, className);
1054 1103 for (var i = from.line + 1, e = to.line; i < e; ++i)
1055 1104 add(i, 0, null, className);
1056 1105 add(to.line, 0, to.ch, className);
1057 1106 }
1058 1107 changes.push({from: from.line, to: to.line + 1});
1059 1108 return function() {
1060 1109 var start, end;
1061 1110 for (var i = 0; i < accum.length; ++i) {
1062 1111 var mark = accum[i], found = indexOf(lines, mark.line);
1063 1112 mark.line.removeMark(mark);
1064 1113 if (found > -1) {
1065 1114 if (start == null) start = found;
1066 1115 end = found;
1067 1116 }
1068 1117 }
1069 1118 if (start != null) changes.push({from: start, to: end + 1});
1070 1119 };
1071 1120 }
1072 1121
1073 1122 function addGutterMarker(line, text, className) {
1074 1123 if (typeof line == "number") line = lines[clipLine(line)];
1075 1124 line.gutterMarker = {text: text, style: className};
1076 updateGutter();
1125 gutterDirty = true;
1077 1126 return line;
1078 1127 }
1079 1128 function removeGutterMarker(line) {
1080 1129 if (typeof line == "number") line = lines[clipLine(line)];
1081 1130 line.gutterMarker = null;
1082 updateGutter();
1131 gutterDirty = true;
1083 1132 }
1084 1133 function setLineClass(line, className) {
1085 1134 if (typeof line == "number") {
1086 1135 var no = line;
1087 1136 line = lines[clipLine(line)];
1088 1137 }
1089 1138 else {
1090 1139 var no = indexOf(lines, line);
1091 1140 if (no == -1) return null;
1092 1141 }
1093 1142 if (line.className != className) {
1094 1143 line.className = className;
1095 1144 changes.push({from: no, to: no + 1});
1096 1145 }
1097 1146 return line;
1098 1147 }
1099 1148
1100 1149 function lineInfo(line) {
1101 1150 if (typeof line == "number") {
1102 1151 var n = line;
1103 1152 line = lines[line];
1104 1153 if (!line) return null;
1105 1154 }
1106 1155 else {
1107 1156 var n = indexOf(lines, line);
1108 1157 if (n == -1) return null;
1109 1158 }
1110 1159 var marker = line.gutterMarker;
1111 1160 return {line: n, text: line.text, markerText: marker && marker.text, markerClass: marker && marker.style};
1112 1161 }
1113 1162
1114 1163 function stringWidth(str) {
1115 1164 measure.innerHTML = "<pre><span>x</span></pre>";
1116 1165 measure.firstChild.firstChild.firstChild.nodeValue = str;
1117 1166 return measure.firstChild.firstChild.offsetWidth || 10;
1118 1167 }
1119 1168 // These are used to go from pixel positions to character
1120 1169 // positions, taking varying character widths into account.
1121 1170 function charX(line, pos) {
1122 1171 if (pos == 0) return 0;
1123 1172 measure.innerHTML = "<pre><span>" + lines[line].getHTML(null, null, false, pos) + "</span></pre>";
1124 1173 return measure.firstChild.firstChild.offsetWidth;
1125 1174 }
1126 1175 function charFromX(line, x) {
1127 1176 if (x <= 0) return 0;
1128 1177 var lineObj = lines[line], text = lineObj.text;
1129 1178 function getX(len) {
1130 1179 measure.innerHTML = "<pre><span>" + lineObj.getHTML(null, null, false, len) + "</span></pre>";
1131 1180 return measure.firstChild.firstChild.offsetWidth;
1132 1181 }
1133 1182 var from = 0, fromX = 0, to = text.length, toX;
1134 1183 // Guess a suitable upper bound for our search.
1135 1184 var estimated = Math.min(to, Math.ceil(x / stringWidth("x")));
1136 1185 for (;;) {
1137 1186 var estX = getX(estimated);
1138 1187 if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
1139 1188 else {toX = estX; to = estimated; break;}
1140 1189 }
1141 1190 if (x > toX) return to;
1142 1191 // Try to guess a suitable lower bound as well.
1143 1192 estimated = Math.floor(to * 0.8); estX = getX(estimated);
1144 1193 if (estX < x) {from = estimated; fromX = estX;}
1145 1194 // Do a binary search between these bounds.
1146 1195 for (;;) {
1147 1196 if (to - from <= 1) return (toX - x > x - fromX) ? from : to;
1148 1197 var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
1149 1198 if (middleX > x) {to = middle; toX = middleX;}
1150 1199 else {from = middle; fromX = middleX;}
1151 1200 }
1152 1201 }
1153 1202
1154 1203 function localCoords(pos, inLineWrap) {
1155 1204 var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
1156 1205 return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
1157 1206 }
1158 1207 function pageCoords(pos) {
1159 1208 var local = localCoords(pos, true), off = eltOffset(lineSpace);
1160 1209 return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
1161 1210 }
1162 1211
1163 1212 function lineHeight() {
1164 1213 var nlines = lineDiv.childNodes.length;
1165 1214 if (nlines) return (lineDiv.offsetHeight / nlines) || 1;
1166 1215 measure.innerHTML = "<pre>x</pre>";
1167 1216 return measure.firstChild.offsetHeight || 1;
1168 1217 }
1169 1218 function paddingTop() {return lineSpace.offsetTop;}
1170 1219 function paddingLeft() {return lineSpace.offsetLeft;}
1171 1220
1172 1221 function posFromMouse(e, liberal) {
1173 1222 var offW = eltOffset(scroller, true), x, y;
1174 1223 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
1175 1224 try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
1176 1225 // This is a mess of a heuristic to try and determine whether a
1177 1226 // scroll-bar was clicked or not, and to return null if one was
1178 1227 // (and !liberal).
1179 1228 if (!liberal && (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))
1180 1229 return null;
1181 1230 var offL = eltOffset(lineSpace, true);
1182 1231 var line = showingFrom + Math.floor((y - offL.top) / lineHeight());
1183 1232 return clipPos({line: line, ch: charFromX(clipLine(line), x - offL.left)});
1184 1233 }
1185 1234 function onContextMenu(e) {
1186 1235 var pos = posFromMouse(e);
1187 1236 if (!pos || window.opera) return; // Opera is difficult.
1188 1237 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1189 1238 operation(setCursor)(pos.line, pos.ch);
1190 1239
1191 1240 var oldCSS = input.style.cssText;
1192 1241 inputDiv.style.position = "absolute";
1193 input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e_pageY(e) - 1) +
1194 "px; left: " + (e_pageX(e) - 1) + "px; z-index: 1000; background: white; " +
1242 input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1243 "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
1195 1244 "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1196 1245 leaveInputAlone = true;
1197 1246 var val = input.value = getSelection();
1198 1247 focusInput();
1199 1248 setSelRange(input, 0, input.value.length);
1200 1249 function rehide() {
1201 1250 var newVal = splitLines(input.value).join("\n");
1202 1251 if (newVal != val) operation(replaceSelection)(newVal, "end");
1203 1252 inputDiv.style.position = "relative";
1204 1253 input.style.cssText = oldCSS;
1205 1254 leaveInputAlone = false;
1206 1255 prepareInput();
1207 1256 slowPoll();
1208 1257 }
1209 1258
1210 1259 if (gecko) {
1211 1260 e_stop(e);
1212 1261 var mouseup = connect(window, "mouseup", function() {
1213 1262 mouseup();
1214 1263 setTimeout(rehide, 20);
1215 1264 }, true);
1216 1265 }
1217 1266 else {
1218 1267 setTimeout(rehide, 50);
1219 1268 }
1220 1269 }
1221 1270
1222 1271 // Cursor-blinking
1223 1272 function restartBlink() {
1224 1273 clearInterval(blinker);
1225 1274 var on = true;
1226 1275 cursor.style.visibility = "";
1227 1276 blinker = setInterval(function() {
1228 1277 cursor.style.visibility = (on = !on) ? "" : "hidden";
1229 1278 }, 650);
1230 1279 }
1231 1280
1232 1281 var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
1233 1282 function matchBrackets(autoclear) {
1234 1283 var head = sel.inverted ? sel.from : sel.to, line = lines[head.line], pos = head.ch - 1;
1235 1284 var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
1236 1285 if (!match) return;
1237 1286 var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
1238 1287 for (var off = pos + 1, i = 0, e = st.length; i < e; i+=2)
1239 1288 if ((off -= st[i].length) <= 0) {var style = st[i+1]; break;}
1240 1289
1241 1290 var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
1242 1291 function scan(line, from, to) {
1243 1292 if (!line.text) return;
1244 1293 var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1245 1294 for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1246 1295 var text = st[i];
1247 1296 if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1248 1297 for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1249 1298 if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1250 1299 var match = matching[cur];
1251 1300 if (match.charAt(1) == ">" == forward) stack.push(cur);
1252 1301 else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
1253 1302 else if (!stack.length) return {pos: pos, match: true};
1254 1303 }
1255 1304 }
1256 1305 }
1257 1306 }
1258 1307 for (var i = head.line, e = forward ? Math.min(i + 100, lines.length) : Math.max(-1, i - 100); i != e; i+=d) {
1259 1308 var line = lines[i], first = i == head.line;
1260 1309 var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
1261 1310 if (found) break;
1262 1311 }
1263 1312 if (!found) found = {pos: null, match: false};
1264 1313 var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1265 1314 var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
1266 1315 two = found.pos != null
1267 1316 ? markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style)
1268 1317 : function() {};
1269 1318 var clear = operation(function(){one(); two();});
1270 1319 if (autoclear) setTimeout(clear, 800);
1271 1320 else bracketHighlighted = clear;
1272 1321 }
1273 1322
1274 1323 // Finds the line to start with when starting a parse. Tries to
1275 1324 // find a line with a stateAfter, so that it can start with a
1276 1325 // valid state. If that fails, it returns the line with the
1277 1326 // smallest indentation, which tends to need the least context to
1278 1327 // parse correctly.
1279 1328 function findStartLine(n) {
1280 1329 var minindent, minline;
1281 1330 for (var search = n, lim = n - 40; search > lim; --search) {
1282 1331 if (search == 0) return 0;
1283 1332 var line = lines[search-1];
1284 1333 if (line.stateAfter) return search;
1285 1334 var indented = line.indentation();
1286 1335 if (minline == null || minindent > indented) {
1287 minline = search;
1336 minline = search - 1;
1288 1337 minindent = indented;
1289 1338 }
1290 1339 }
1291 1340 return minline;
1292 1341 }
1293 1342 function getStateBefore(n) {
1294 1343 var start = findStartLine(n), state = start && lines[start-1].stateAfter;
1295 1344 if (!state) state = startState(mode);
1296 1345 else state = copyState(mode, state);
1297 1346 for (var i = start; i < n; ++i) {
1298 1347 var line = lines[i];
1299 1348 line.highlight(mode, state);
1300 1349 line.stateAfter = copyState(mode, state);
1301 1350 }
1302 1351 if (n < lines.length && !lines[n].stateAfter) work.push(n);
1303 1352 return state;
1304 1353 }
1305 1354 function highlightLines(start, end) {
1306 1355 var state = getStateBefore(start);
1307 1356 for (var i = start; i < end; ++i) {
1308 1357 var line = lines[i];
1309 1358 line.highlight(mode, state);
1310 1359 line.stateAfter = copyState(mode, state);
1311 1360 }
1312 1361 }
1313 1362 function highlightWorker() {
1314 1363 var end = +new Date + options.workTime;
1315 1364 var foundWork = work.length;
1316 1365 while (work.length) {
1317 1366 if (!lines[showingFrom].stateAfter) var task = showingFrom;
1318 1367 else var task = work.pop();
1319 1368 if (task >= lines.length) continue;
1320 1369 var start = findStartLine(task), state = start && lines[start-1].stateAfter;
1321 1370 if (state) state = copyState(mode, state);
1322 1371 else state = startState(mode);
1323 1372
1324 var unchanged = 0, compare = mode.compareStates;
1373 var unchanged = 0, compare = mode.compareStates, realChange = false;
1325 1374 for (var i = start, l = lines.length; i < l; ++i) {
1326 1375 var line = lines[i], hadState = line.stateAfter;
1327 1376 if (+new Date > end) {
1328 1377 work.push(i);
1329 1378 startWorker(options.workDelay);
1330 changes.push({from: task, to: i + 1});
1379 if (realChange) changes.push({from: task, to: i + 1});
1331 1380 return;
1332 1381 }
1333 1382 var changed = line.highlight(mode, state);
1383 if (changed) realChange = true;
1334 1384 line.stateAfter = copyState(mode, state);
1335 1385 if (compare) {
1336 1386 if (hadState && compare(hadState, state)) break;
1337 1387 } else {
1338 if (changed || !hadState) unchanged = 0;
1388 if (changed !== false || !hadState) unchanged = 0;
1339 1389 else if (++unchanged > 3) break;
1340 1390 }
1341 1391 }
1342 changes.push({from: task, to: i + 1});
1392 if (realChange) changes.push({from: task, to: i + 1});
1343 1393 }
1344 1394 if (foundWork && options.onHighlightComplete)
1345 1395 options.onHighlightComplete(instance);
1346 1396 }
1347 1397 function startWorker(time) {
1348 1398 if (!work.length) return;
1349 1399 highlight.set(time, operation(highlightWorker));
1350 1400 }
1351 1401
1352 1402 // Operations are used to wrap changes in such a way that each
1353 1403 // change won't have to update the cursor and display (which would
1354 1404 // be awkward, slow, and error-prone), but instead updates are
1355 1405 // batched and then all combined and executed at once.
1356 1406 function startOperation() {
1357 1407 updateInput = null; changes = []; textChanged = selectionChanged = false;
1358 1408 }
1359 1409 function endOperation() {
1360 1410 var reScroll = false;
1361 1411 if (selectionChanged) reScroll = !scrollCursorIntoView();
1362 1412 if (changes.length) updateDisplay(changes);
1363 else if (selectionChanged) updateCursor();
1413 else {
1414 if (selectionChanged) updateCursor();
1415 if (gutterDirty) updateGutter();
1416 }
1364 1417 if (reScroll) scrollCursorIntoView();
1365 if (selectionChanged) restartBlink();
1418 if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
1366 1419
1367 1420 // updateInput can be set to a boolean value to force/prevent an
1368 1421 // update.
1369 1422 if (focused && !leaveInputAlone &&
1370 1423 (updateInput === true || (updateInput !== false && selectionChanged)))
1371 1424 prepareInput();
1372 1425
1373 1426 if (selectionChanged && options.matchBrackets)
1374 1427 setTimeout(operation(function() {
1375 1428 if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1376 1429 matchBrackets(false);
1377 1430 }), 20);
1378 1431 var tc = textChanged; // textChanged can be reset by cursoractivity callback
1379 1432 if (selectionChanged && options.onCursorActivity)
1380 1433 options.onCursorActivity(instance);
1381 1434 if (tc && options.onChange && instance)
1382 1435 options.onChange(instance, tc);
1383 1436 }
1384 1437 var nestedOperation = 0;
1385 1438 function operation(f) {
1386 1439 return function() {
1387 1440 if (!nestedOperation++) startOperation();
1388 1441 try {var result = f.apply(this, arguments);}
1389 1442 finally {if (!--nestedOperation) endOperation();}
1390 1443 return result;
1391 1444 };
1392 1445 }
1393 1446
1394 1447 function SearchCursor(query, pos, caseFold) {
1395 1448 this.atOccurrence = false;
1396 1449 if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
1397 1450
1398 1451 if (pos && typeof pos == "object") pos = clipPos(pos);
1399 1452 else pos = {line: 0, ch: 0};
1400 1453 this.pos = {from: pos, to: pos};
1401 1454
1402 1455 // The matches method is filled in based on the type of query.
1403 1456 // It takes a position and a direction, and returns an object
1404 1457 // describing the next occurrence of the query, or null if no
1405 1458 // more matches were found.
1406 1459 if (typeof query != "string") // Regexp match
1407 1460 this.matches = function(reverse, pos) {
1408 1461 if (reverse) {
1409 1462 var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
1410 1463 while (match) {
1411 1464 var ind = line.indexOf(match[0]);
1412 1465 start += ind;
1413 1466 line = line.slice(ind + 1);
1414 1467 var newmatch = line.match(query);
1415 1468 if (newmatch) match = newmatch;
1416 1469 else break;
1417 1470 start++;
1418 1471 }
1419 1472 }
1420 1473 else {
1421 1474 var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
1422 1475 start = match && pos.ch + line.indexOf(match[0]);
1423 1476 }
1424 1477 if (match)
1425 1478 return {from: {line: pos.line, ch: start},
1426 1479 to: {line: pos.line, ch: start + match[0].length},
1427 1480 match: match};
1428 1481 };
1429 1482 else { // String query
1430 1483 if (caseFold) query = query.toLowerCase();
1431 1484 var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
1432 1485 var target = query.split("\n");
1433 1486 // Different methods for single-line and multi-line queries
1434 1487 if (target.length == 1)
1435 1488 this.matches = function(reverse, pos) {
1436 1489 var line = fold(lines[pos.line].text), len = query.length, match;
1437 1490 if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
1438 1491 : (match = line.indexOf(query, pos.ch)) != -1)
1439 1492 return {from: {line: pos.line, ch: match},
1440 1493 to: {line: pos.line, ch: match + len}};
1441 1494 };
1442 1495 else
1443 1496 this.matches = function(reverse, pos) {
1444 1497 var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
1445 1498 var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
1446 1499 if (reverse ? offsetA >= pos.ch || offsetA != match.length
1447 1500 : offsetA <= pos.ch || offsetA != line.length - match.length)
1448 1501 return;
1449 1502 for (;;) {
1450 1503 if (reverse ? !ln : ln == lines.length - 1) return;
1451 1504 line = fold(lines[ln += reverse ? -1 : 1].text);
1452 1505 match = target[reverse ? --idx : ++idx];
1453 1506 if (idx > 0 && idx < target.length - 1) {
1454 1507 if (line != match) return;
1455 1508 else continue;
1456 1509 }
1457 1510 var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
1458 1511 if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
1459 1512 return;
1460 1513 var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
1461 1514 return {from: reverse ? end : start, to: reverse ? start : end};
1462 1515 }
1463 1516 };
1464 1517 }
1465 1518 }
1466 1519
1467 1520 SearchCursor.prototype = {
1468 1521 findNext: function() {return this.find(false);},
1469 1522 findPrevious: function() {return this.find(true);},
1470 1523
1471 1524 find: function(reverse) {
1472 1525 var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
1473 1526 function savePosAndFail(line) {
1474 1527 var pos = {line: line, ch: 0};
1475 1528 self.pos = {from: pos, to: pos};
1476 1529 self.atOccurrence = false;
1477 1530 return false;
1478 1531 }
1479 1532
1480 1533 for (;;) {
1481 1534 if (this.pos = this.matches(reverse, pos)) {
1482 1535 this.atOccurrence = true;
1483 1536 return this.pos.match || true;
1484 1537 }
1485 1538 if (reverse) {
1486 1539 if (!pos.line) return savePosAndFail(0);
1487 1540 pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
1488 1541 }
1489 1542 else {
1490 1543 if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
1491 1544 pos = {line: pos.line+1, ch: 0};
1492 1545 }
1493 1546 }
1494 1547 },
1495 1548
1496 1549 from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
1497 1550 to: function() {if (this.atOccurrence) return copyPos(this.pos.to);},
1498 1551
1499 1552 replace: function(newText) {
1500 1553 var self = this;
1501 1554 if (this.atOccurrence)
1502 1555 operation(function() {
1503 1556 self.pos.to = replaceRange(newText, self.pos.from, self.pos.to);
1504 1557 })();
1505 1558 }
1506 1559 };
1507 1560
1508 1561 for (var ext in extensions)
1509 1562 if (extensions.propertyIsEnumerable(ext) &&
1510 1563 !instance.propertyIsEnumerable(ext))
1511 1564 instance[ext] = extensions[ext];
1512 1565 return instance;
1513 1566 } // (end of function CodeMirror)
1514 1567
1515 1568 // The default configuration options.
1516 1569 CodeMirror.defaults = {
1517 1570 value: "",
1518 1571 mode: null,
1519 1572 theme: "default",
1520 1573 indentUnit: 2,
1521 1574 indentWithTabs: false,
1522 1575 tabMode: "classic",
1523 1576 enterMode: "indent",
1524 1577 electricChars: true,
1525 1578 onKeyEvent: null,
1526 1579 lineNumbers: false,
1527 1580 gutter: false,
1581 fixedGutter: false,
1528 1582 firstLineNumber: 1,
1529 1583 readOnly: false,
1584 smartHome: true,
1530 1585 onChange: null,
1531 1586 onCursorActivity: null,
1532 1587 onGutterClick: null,
1533 1588 onHighlightComplete: null,
1534 1589 onFocus: null, onBlur: null, onScroll: null,
1535 1590 matchBrackets: false,
1536 1591 workTime: 100,
1537 1592 workDelay: 200,
1538 1593 undoDepth: 40,
1539 1594 tabindex: null,
1540 1595 document: window.document
1541 1596 };
1542 1597
1543 1598 // Known modes, by name and by MIME
1544 1599 var modes = {}, mimeModes = {};
1545 1600 CodeMirror.defineMode = function(name, mode) {
1546 1601 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
1547 1602 modes[name] = mode;
1548 1603 };
1549 1604 CodeMirror.defineMIME = function(mime, spec) {
1550 1605 mimeModes[mime] = spec;
1551 1606 };
1552 1607 CodeMirror.getMode = function(options, spec) {
1553 1608 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1554 1609 spec = mimeModes[spec];
1555 1610 if (typeof spec == "string")
1556 1611 var mname = spec, config = {};
1557 1612 else if (spec != null)
1558 1613 var mname = spec.name, config = spec;
1559 1614 var mfactory = modes[mname];
1560 1615 if (!mfactory) {
1561 1616 if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1562 1617 return CodeMirror.getMode(options, "text/plain");
1563 1618 }
1564 1619 return mfactory(options, config || {});
1565 1620 };
1566 1621 CodeMirror.listModes = function() {
1567 1622 var list = [];
1568 1623 for (var m in modes)
1569 1624 if (modes.propertyIsEnumerable(m)) list.push(m);
1570 1625 return list;
1571 1626 };
1572 1627 CodeMirror.listMIMEs = function() {
1573 1628 var list = [];
1574 1629 for (var m in mimeModes)
1575 if (mimeModes.propertyIsEnumerable(m)) list.push(m);
1630 if (mimeModes.propertyIsEnumerable(m)) list.push({mime: m, mode: mimeModes[m]});
1576 1631 return list;
1577 1632 };
1578 1633
1579 1634 var extensions = {};
1580 1635 CodeMirror.defineExtension = function(name, func) {
1581 1636 extensions[name] = func;
1582 1637 };
1583 1638
1584 1639 CodeMirror.fromTextArea = function(textarea, options) {
1585 1640 if (!options) options = {};
1586 1641 options.value = textarea.value;
1587 1642 if (!options.tabindex && textarea.tabindex)
1588 1643 options.tabindex = textarea.tabindex;
1589 1644
1590 1645 function save() {textarea.value = instance.getValue();}
1591 1646 if (textarea.form) {
1592 1647 // Deplorable hack to make the submit method do the right thing.
1593 1648 var rmSubmit = connect(textarea.form, "submit", save, true);
1594 1649 if (typeof textarea.form.submit == "function") {
1595 1650 var realSubmit = textarea.form.submit;
1596 1651 function wrappedSubmit() {
1597 1652 save();
1598 1653 textarea.form.submit = realSubmit;
1599 1654 textarea.form.submit();
1600 1655 textarea.form.submit = wrappedSubmit;
1601 1656 }
1602 1657 textarea.form.submit = wrappedSubmit;
1603 1658 }
1604 1659 }
1605 1660
1606 1661 textarea.style.display = "none";
1607 1662 var instance = CodeMirror(function(node) {
1608 1663 textarea.parentNode.insertBefore(node, textarea.nextSibling);
1609 1664 }, options);
1610 1665 instance.save = save;
1611 1666 instance.toTextArea = function() {
1612 1667 save();
1613 1668 textarea.parentNode.removeChild(instance.getWrapperElement());
1614 1669 textarea.style.display = "";
1615 1670 if (textarea.form) {
1616 1671 rmSubmit();
1617 1672 if (typeof textarea.form.submit == "function")
1618 1673 textarea.form.submit = realSubmit;
1619 1674 }
1620 1675 };
1621 1676 return instance;
1622 1677 };
1623 1678
1624 1679 // Utility functions for working with state. Exported because modes
1625 1680 // sometimes need to do this.
1626 1681 function copyState(mode, state) {
1627 1682 if (state === true) return state;
1628 1683 if (mode.copyState) return mode.copyState(state);
1629 1684 var nstate = {};
1630 1685 for (var n in state) {
1631 1686 var val = state[n];
1632 1687 if (val instanceof Array) val = val.concat([]);
1633 1688 nstate[n] = val;
1634 1689 }
1635 1690 return nstate;
1636 1691 }
1637 1692 CodeMirror.startState = startState;
1638 1693 function startState(mode, a1, a2) {
1639 1694 return mode.startState ? mode.startState(a1, a2) : true;
1640 1695 }
1641 1696 CodeMirror.copyState = copyState;
1642 1697
1643 1698 // The character stream used by a mode's parser.
1644 1699 function StringStream(string) {
1645 1700 this.pos = this.start = 0;
1646 1701 this.string = string;
1647 1702 }
1648 1703 StringStream.prototype = {
1649 1704 eol: function() {return this.pos >= this.string.length;},
1650 1705 sol: function() {return this.pos == 0;},
1651 1706 peek: function() {return this.string.charAt(this.pos);},
1652 1707 next: function() {
1653 1708 if (this.pos < this.string.length)
1654 1709 return this.string.charAt(this.pos++);
1655 1710 },
1656 1711 eat: function(match) {
1657 1712 var ch = this.string.charAt(this.pos);
1658 1713 if (typeof match == "string") var ok = ch == match;
1659 1714 else var ok = ch && (match.test ? match.test(ch) : match(ch));
1660 1715 if (ok) {++this.pos; return ch;}
1661 1716 },
1662 1717 eatWhile: function(match) {
1663 var start = this.start;
1718 var start = this.pos;
1664 1719 while (this.eat(match)){}
1665 1720 return this.pos > start;
1666 1721 },
1667 1722 eatSpace: function() {
1668 1723 var start = this.pos;
1669 1724 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
1670 1725 return this.pos > start;
1671 1726 },
1672 1727 skipToEnd: function() {this.pos = this.string.length;},
1673 1728 skipTo: function(ch) {
1674 1729 var found = this.string.indexOf(ch, this.pos);
1675 1730 if (found > -1) {this.pos = found; return true;}
1676 1731 },
1677 1732 backUp: function(n) {this.pos -= n;},
1678 1733 column: function() {return countColumn(this.string, this.start);},
1679 1734 indentation: function() {return countColumn(this.string);},
1680 1735 match: function(pattern, consume, caseInsensitive) {
1681 1736 if (typeof pattern == "string") {
1682 1737 function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
1683 1738 if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
1684 1739 if (consume !== false) this.pos += pattern.length;
1685 1740 return true;
1686 1741 }
1687 1742 }
1688 1743 else {
1689 1744 var match = this.string.slice(this.pos).match(pattern);
1690 1745 if (match && consume !== false) this.pos += match[0].length;
1691 1746 return match;
1692 1747 }
1693 1748 },
1694 1749 current: function(){return this.string.slice(this.start, this.pos);}
1695 1750 };
1696 1751 CodeMirror.StringStream = StringStream;
1697 1752
1698 1753 // Line objects. These hold state related to a line, including
1699 1754 // highlighting info (the styles array).
1700 1755 function Line(text, styles) {
1701 1756 this.styles = styles || [text, null];
1702 1757 this.stateAfter = null;
1703 1758 this.text = text;
1704 1759 this.marked = this.gutterMarker = this.className = null;
1705 1760 }
1706 1761 Line.prototype = {
1707 1762 // Replace a piece of a line, keeping the styles around it intact.
1708 1763 replace: function(from, to, text) {
1709 1764 var st = [], mk = this.marked;
1710 1765 copyStyles(0, from, this.styles, st);
1711 1766 if (text) st.push(text, null);
1712 1767 copyStyles(to, this.text.length, this.styles, st);
1713 1768 this.styles = st;
1714 1769 this.text = this.text.slice(0, from) + text + this.text.slice(to);
1715 1770 this.stateAfter = null;
1716 1771 if (mk) {
1717 1772 var diff = text.length - (to - from), end = this.text.length;
1718 1773 function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
1719 1774 for (var i = 0; i < mk.length; ++i) {
1720 1775 var mark = mk[i], del = false;
1721 1776 if (mark.from >= end) del = true;
1722 1777 else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
1723 1778 if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
1724 1779 }
1725 1780 }
1726 1781 },
1727 1782 // Split a line in two, again keeping styles intact.
1728 1783 split: function(pos, textBefore) {
1729 1784 var st = [textBefore, null];
1730 1785 copyStyles(pos, this.text.length, this.styles, st);
1731 1786 return new Line(textBefore + this.text.slice(pos), st);
1732 1787 },
1733 1788 addMark: function(from, to, style) {
1734 1789 var mk = this.marked, mark = {from: from, to: to, style: style};
1735 1790 if (this.marked == null) this.marked = [];
1736 1791 this.marked.push(mark);
1737 1792 this.marked.sort(function(a, b){return a.from - b.from;});
1738 1793 return mark;
1739 1794 },
1740 1795 removeMark: function(mark) {
1741 1796 var mk = this.marked;
1742 1797 if (!mk) return;
1743 1798 for (var i = 0; i < mk.length; ++i)
1744 1799 if (mk[i] == mark) {mk.splice(i, 1); break;}
1745 1800 },
1746 1801 // Run the given mode's parser over a line, update the styles
1747 1802 // array, which contains alternating fragments of text and CSS
1748 1803 // classes.
1749 1804 highlight: function(mode, state) {
1750 1805 var stream = new StringStream(this.text), st = this.styles, pos = 0;
1751 1806 var changed = false, curWord = st[0], prevWord;
1752 1807 if (this.text == "" && mode.blankLine) mode.blankLine(state);
1753 1808 while (!stream.eol()) {
1754 1809 var style = mode.token(stream, state);
1755 1810 var substr = this.text.slice(stream.start, stream.pos);
1756 1811 stream.start = stream.pos;
1757 1812 if (pos && st[pos-1] == style)
1758 1813 st[pos-2] += substr;
1759 1814 else if (substr) {
1760 1815 if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
1761 1816 st[pos++] = substr; st[pos++] = style;
1762 1817 prevWord = curWord; curWord = st[pos];
1763 1818 }
1764 1819 // Give up when line is ridiculously long
1765 1820 if (stream.pos > 5000) {
1766 1821 st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
1767 1822 break;
1768 1823 }
1769 1824 }
1770 1825 if (st.length != pos) {st.length = pos; changed = true;}
1771 1826 if (pos && st[pos-2] != prevWord) changed = true;
1772 // Short lines with simple highlights always count as changed,
1773 // because they are likely to highlight the same way in various
1774 // contexts.
1775 return changed || (st.length < 5 && this.text.length < 10);
1827 // Short lines with simple highlights return null, and are
1828 // counted as changed by the driver because they are likely to
1829 // highlight the same way in various contexts.
1830 return changed || (st.length < 5 && this.text.length < 10 ? null : false);
1776 1831 },
1777 1832 // Fetch the parser token for a given character. Useful for hacks
1778 1833 // that want to inspect the mode state (say, for completion).
1779 1834 getTokenAt: function(mode, state, ch) {
1780 1835 var txt = this.text, stream = new StringStream(txt);
1781 1836 while (stream.pos < ch && !stream.eol()) {
1782 1837 stream.start = stream.pos;
1783 1838 var style = mode.token(stream, state);
1784 1839 }
1785 1840 return {start: stream.start,
1786 1841 end: stream.pos,
1787 1842 string: stream.current(),
1788 1843 className: style || null,
1789 1844 state: state};
1790 1845 },
1791 1846 indentation: function() {return countColumn(this.text);},
1792 1847 // Produces an HTML fragment for the line, taking selection,
1793 1848 // marking, and highlighting into account.
1794 1849 getHTML: function(sfrom, sto, includePre, endAt) {
1795 1850 var html = [];
1796 1851 if (includePre)
1797 1852 html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
1798 1853 function span(text, style) {
1799 1854 if (!text) return;
1800 1855 if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
1801 1856 else html.push(htmlEscape(text));
1802 1857 }
1803 1858 var st = this.styles, allText = this.text, marked = this.marked;
1804 1859 if (sfrom == sto) sfrom = null;
1805 1860 var len = allText.length;
1806 1861 if (endAt != null) len = Math.min(endAt, len);
1807 1862
1808 1863 if (!allText && endAt == null)
1809 1864 span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
1810 1865 else if (!marked && sfrom == null)
1811 1866 for (var i = 0, ch = 0; ch < len; i+=2) {
1812 1867 var str = st[i], l = str.length;
1813 1868 if (ch + l > len) str = str.slice(0, len - ch);
1814 1869 ch += l;
1815 1870 span(str, "cm-" + st[i+1]);
1816 1871 }
1817 1872 else {
1818 1873 var pos = 0, i = 0, text = "", style, sg = 0;
1819 1874 var markpos = -1, mark = null;
1820 1875 function nextMark() {
1821 1876 if (marked) {
1822 1877 markpos += 1;
1823 1878 mark = (markpos < marked.length) ? marked[markpos] : null;
1824 1879 }
1825 1880 }
1826 1881 nextMark();
1827 1882 while (pos < len) {
1828 1883 var upto = len;
1829 1884 var extraStyle = "";
1830 1885 if (sfrom != null) {
1831 1886 if (sfrom > pos) upto = sfrom;
1832 1887 else if (sto == null || sto > pos) {
1833 1888 extraStyle = " CodeMirror-selected";
1834 1889 if (sto != null) upto = Math.min(upto, sto);
1835 1890 }
1836 1891 }
1837 1892 while (mark && mark.to != null && mark.to <= pos) nextMark();
1838 1893 if (mark) {
1839 1894 if (mark.from > pos) upto = Math.min(upto, mark.from);
1840 1895 else {
1841 1896 extraStyle += " " + mark.style;
1842 1897 if (mark.to != null) upto = Math.min(upto, mark.to);
1843 1898 }
1844 1899 }
1845 1900 for (;;) {
1846 1901 var end = pos + text.length;
1847 1902 var appliedStyle = style;
1848 1903 if (extraStyle) appliedStyle = style ? style + extraStyle : extraStyle;
1849 1904 span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
1850 1905 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
1851 1906 pos = end;
1852 1907 text = st[i++]; style = "cm-" + st[i++];
1853 1908 }
1854 1909 }
1855 1910 if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
1856 1911 }
1857 1912 if (includePre) html.push("</pre>");
1858 1913 return html.join("");
1859 1914 }
1860 1915 };
1861 1916 // Utility used by replace and split above
1862 1917 function copyStyles(from, to, source, dest) {
1863 1918 for (var i = 0, pos = 0, state = 0; pos < to; i+=2) {
1864 1919 var part = source[i], end = pos + part.length;
1865 1920 if (state == 0) {
1866 1921 if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
1867 1922 if (end >= from) state = 1;
1868 1923 }
1869 1924 else if (state == 1) {
1870 1925 if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
1871 1926 else dest.push(part, source[i+1]);
1872 1927 }
1873 1928 pos = end;
1874 1929 }
1875 1930 }
1876 1931
1877 1932 // The history object 'chunks' changes that are made close together
1878 1933 // and at almost the same time into bigger undoable units.
1879 1934 function History() {
1880 1935 this.time = 0;
1881 1936 this.done = []; this.undone = [];
1882 1937 }
1883 1938 History.prototype = {
1884 1939 addChange: function(start, added, old) {
1885 1940 this.undone.length = 0;
1886 1941 var time = +new Date, last = this.done[this.done.length - 1];
1887 1942 if (time - this.time > 400 || !last ||
1888 1943 last.start > start + added || last.start + last.added < start - last.added + last.old.length)
1889 1944 this.done.push({start: start, added: added, old: old});
1890 1945 else {
1891 1946 var oldoff = 0;
1892 1947 if (start < last.start) {
1893 1948 for (var i = last.start - start - 1; i >= 0; --i)
1894 1949 last.old.unshift(old[i]);
1895 1950 last.added += last.start - start;
1896 1951 last.start = start;
1897 1952 }
1898 1953 else if (last.start < start) {
1899 1954 oldoff = start - last.start;
1900 1955 added += oldoff;
1901 1956 }
1902 1957 for (var i = last.added - oldoff, e = old.length; i < e; ++i)
1903 1958 last.old.push(old[i]);
1904 1959 if (last.added < added) last.added = added;
1905 1960 }
1906 1961 this.time = time;
1907 1962 }
1908 1963 };
1909 1964
1910 1965 function stopMethod() {e_stop(this);}
1911 1966 // Ensure an event has a stop method.
1912 1967 function addStop(event) {
1913 1968 if (!event.stop) event.stop = stopMethod;
1914 1969 return event;
1915 1970 }
1916 1971
1917 1972 function e_preventDefault(e) {
1918 1973 if (e.preventDefault) e.preventDefault();
1919 1974 else e.returnValue = false;
1920 1975 }
1921 1976 function e_stopPropagation(e) {
1922 1977 if (e.stopPropagation) e.stopPropagation();
1923 1978 else e.cancelBubble = true;
1924 1979 }
1925 1980 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
1926 1981 function e_target(e) {return e.target || e.srcElement;}
1927 1982 function e_button(e) {
1928 1983 if (e.which) return e.which;
1929 1984 else if (e.button & 1) return 1;
1930 1985 else if (e.button & 2) return 3;
1931 1986 else if (e.button & 4) return 2;
1932 1987 }
1933 function e_pageX(e) {
1934 if (e.pageX != null) return e.pageX;
1935 var doc = e_target(e).ownerDocument;
1936 return e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
1937 }
1938 function e_pageY(e) {
1939 if (e.pageY != null) return e.pageY;
1940 var doc = e_target(e).ownerDocument;
1941 return e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
1942 }
1943 1988
1944 1989 // Event handler registration. If disconnect is true, it'll return a
1945 1990 // function that unregisters the handler.
1946 1991 function connect(node, type, handler, disconnect) {
1947 1992 function wrapHandler(event) {handler(event || window.event);}
1948 1993 if (typeof node.addEventListener == "function") {
1949 1994 node.addEventListener(type, wrapHandler, false);
1950 1995 if (disconnect) return function() {node.removeEventListener(type, wrapHandler, false);};
1951 1996 }
1952 1997 else {
1953 1998 node.attachEvent("on" + type, wrapHandler);
1954 1999 if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
1955 2000 }
1956 2001 }
1957 2002
1958 2003 function Delayed() {this.id = null;}
1959 2004 Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
1960 2005
1961 2006 // Some IE versions don't preserve whitespace when setting the
1962 2007 // innerHTML of a PRE tag.
1963 2008 var badInnerHTML = (function() {
1964 2009 var pre = document.createElement("pre");
1965 2010 pre.innerHTML = " "; return !pre.innerHTML;
1966 2011 })();
1967 2012
2013 // Detect drag-and-drop
2014 var dragAndDrop = (function() {
2015 // IE8 has ondragstart and ondrop properties, but doesn't seem to
2016 // actually support ondragstart the way it's supposed to work.
2017 if (/MSIE [1-8]\b/.test(navigator.userAgent)) return false;
2018 var div = document.createElement('div');
2019 return "ondragstart" in div && "ondrop" in div;
2020 })();
2021
1968 2022 var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
1969 2023 var ie = /MSIE \d/.test(navigator.userAgent);
1970 2024 var safari = /Apple Computer/.test(navigator.vendor);
1971 2025
1972 2026 var lineSep = "\n";
1973 2027 // Feature-detect whether newlines in textareas are converted to \r\n
1974 2028 (function () {
1975 2029 var te = document.createElement("textarea");
1976 2030 te.value = "foo\nbar";
1977 2031 if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
1978 2032 }());
1979 2033
1980 2034 var tabSize = 8;
1981 2035 var mac = /Mac/.test(navigator.platform);
1982 2036 var movementKeys = {};
1983 2037 for (var i = 35; i <= 40; ++i)
1984 2038 movementKeys[i] = movementKeys["c" + i] = true;
1985 2039
1986 2040 // Counts the column offset in a string, taking tabs into account.
1987 2041 // Used mostly to find indentation.
1988 2042 function countColumn(string, end) {
1989 2043 if (end == null) {
1990 2044 end = string.search(/[^\s\u00a0]/);
1991 2045 if (end == -1) end = string.length;
1992 2046 }
1993 2047 for (var i = 0, n = 0; i < end; ++i) {
1994 2048 if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
1995 2049 else ++n;
1996 2050 }
1997 2051 return n;
1998 2052 }
1999 2053
2000 2054 function computedStyle(elt) {
2001 2055 if (elt.currentStyle) return elt.currentStyle;
2002 2056 return window.getComputedStyle(elt, null);
2003 2057 }
2004 2058 // Find the position of an element by following the offsetParent chain.
2005 2059 // If screen==true, it returns screen (rather than page) coordinates.
2006 2060 function eltOffset(node, screen) {
2007 2061 var doc = node.ownerDocument.body;
2008 2062 var x = 0, y = 0, skipDoc = false;
2009 2063 for (var n = node; n; n = n.offsetParent) {
2010 2064 x += n.offsetLeft; y += n.offsetTop;
2011 2065 if (screen && computedStyle(n).position == "fixed")
2012 2066 skipDoc = true;
2013 2067 }
2014 2068 var e = screen && !skipDoc ? null : doc;
2015 2069 for (var n = node.parentNode; n != e; n = n.parentNode)
2016 2070 if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
2017 2071 return {left: x, top: y};
2018 2072 }
2019 2073 // Get a node's text content.
2020 2074 function eltText(node) {
2021 2075 return node.textContent || node.innerText || node.nodeValue || "";
2022 2076 }
2023 2077
2024 2078 // Operations on {line, ch} objects.
2025 2079 function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
2026 2080 function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
2027 2081 function copyPos(x) {return {line: x.line, ch: x.ch};}
2028 2082
2029 2083 var escapeElement = document.createElement("div");
2030 2084 function htmlEscape(str) {
2031 2085 escapeElement.innerText = escapeElement.textContent = str;
2032 2086 return escapeElement.innerHTML;
2033 2087 }
2034 2088 CodeMirror.htmlEscape = htmlEscape;
2035 2089
2036 2090 // Used to position the cursor after an undo/redo by finding the
2037 2091 // last edited character.
2038 2092 function editEnd(from, to) {
2039 2093 if (!to) return from ? from.length : 0;
2040 2094 if (!from) return to.length;
2041 2095 for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
2042 2096 if (from.charAt(i) != to.charAt(j)) break;
2043 2097 return j + 1;
2044 2098 }
2045 2099
2046 2100 function indexOf(collection, elt) {
2047 2101 if (collection.indexOf) return collection.indexOf(elt);
2048 2102 for (var i = 0, e = collection.length; i < e; ++i)
2049 2103 if (collection[i] == elt) return i;
2050 2104 return -1;
2051 2105 }
2052 2106
2053 2107 // See if "".split is the broken IE version, if so, provide an
2054 2108 // alternative way to split lines.
2055 2109 var splitLines, selRange, setSelRange;
2056 2110 if ("\n\nb".split(/\n/).length != 3)
2057 2111 splitLines = function(string) {
2058 2112 var pos = 0, nl, result = [];
2059 2113 while ((nl = string.indexOf("\n", pos)) > -1) {
2060 2114 result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
2061 2115 pos = nl + 1;
2062 2116 }
2063 2117 result.push(string.slice(pos));
2064 2118 return result;
2065 2119 };
2066 2120 else
2067 2121 splitLines = function(string){return string.split(/\r?\n/);};
2068 2122 CodeMirror.splitLines = splitLines;
2069 2123
2070 2124 // Sane model of finding and setting the selection in a textarea
2071 2125 if (window.getSelection) {
2072 2126 selRange = function(te) {
2073 2127 try {return {start: te.selectionStart, end: te.selectionEnd};}
2074 2128 catch(e) {return null;}
2075 2129 };
2076 2130 if (safari)
2077 2131 // On Safari, selection set with setSelectionRange are in a sort
2078 2132 // of limbo wrt their anchor. If you press shift-left in them,
2079 2133 // the anchor is put at the end, and the selection expanded to
2080 2134 // the left. If you press shift-right, the anchor ends up at the
2081 2135 // front. This is not what CodeMirror wants, so it does a
2082 2136 // spurious modify() call to get out of limbo.
2083 2137 setSelRange = function(te, start, end) {
2084 2138 if (start == end)
2085 2139 te.setSelectionRange(start, end);
2086 2140 else {
2087 2141 te.setSelectionRange(start, end - 1);
2088 2142 window.getSelection().modify("extend", "forward", "character");
2089 2143 }
2090 2144 };
2091 2145 else
2092 2146 setSelRange = function(te, start, end) {
2093 2147 try {te.setSelectionRange(start, end);}
2094 2148 catch(e) {} // Fails on Firefox when textarea isn't part of the document
2095 2149 };
2096 2150 }
2097 2151 // IE model. Don't ask.
2098 2152 else {
2099 2153 selRange = function(te) {
2100 2154 try {var range = te.ownerDocument.selection.createRange();}
2101 2155 catch(e) {return null;}
2102 2156 if (!range || range.parentElement() != te) return null;
2103 2157 var val = te.value, len = val.length, localRange = te.createTextRange();
2104 2158 localRange.moveToBookmark(range.getBookmark());
2105 2159 var endRange = te.createTextRange();
2106 2160 endRange.collapse(false);
2107 2161
2108 2162 if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
2109 2163 return {start: len, end: len};
2110 2164
2111 2165 var start = -localRange.moveStart("character", -len);
2112 2166 for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
2113 2167
2114 2168 if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
2115 2169 return {start: start, end: len};
2116 2170
2117 2171 var end = -localRange.moveEnd("character", -len);
2118 2172 for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
2119 2173 return {start: start, end: end};
2120 2174 };
2121 2175 setSelRange = function(te, start, end) {
2122 2176 var range = te.createTextRange();
2123 2177 range.collapse(true);
2124 2178 var endrange = range.duplicate();
2125 2179 var newlines = 0, txt = te.value;
2126 2180 for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
2127 2181 ++newlines;
2128 2182 range.move("character", start - newlines);
2129 2183 for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
2130 2184 ++newlines;
2131 2185 endrange.move("character", end - newlines);
2132 2186 range.setEndPoint("EndToEnd", endrange);
2133 2187 range.select();
2134 2188 };
2135 2189 }
2136 2190
2137 2191 CodeMirror.defineMode("null", function() {
2138 2192 return {token: function(stream) {stream.skipToEnd();}};
2139 2193 });
2140 2194 CodeMirror.defineMIME("text/plain", "null");
2141 2195
2142 2196 return CodeMirror;
2143 })()
2144 ; No newline at end of file
2197 })();
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/lib/overlay.js to IPython/frontend/html/notebook/static/codemirror/lib/overlay.js, modified file
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/lib/runmode.js to IPython/frontend/html/notebook/static/codemirror/lib/runmode.js
@@ -1,124 +1,124 b''
1 1 CodeMirror.defineMode("css", function(config) {
2 2 var indentUnit = config.indentUnit, type;
3 3 function ret(style, tp) {type = tp; return style;}
4 4
5 5 function tokenBase(stream, state) {
6 6 var ch = stream.next();
7 if (ch == "@") {stream.eatWhile(/\w/); return ret("meta", stream.current());}
7 if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
8 8 else if (ch == "/" && stream.eat("*")) {
9 9 state.tokenize = tokenCComment;
10 10 return tokenCComment(stream, state);
11 11 }
12 12 else if (ch == "<" && stream.eat("!")) {
13 13 state.tokenize = tokenSGMLComment;
14 14 return tokenSGMLComment(stream, state);
15 15 }
16 16 else if (ch == "=") ret(null, "compare");
17 17 else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
18 18 else if (ch == "\"" || ch == "'") {
19 19 state.tokenize = tokenString(ch);
20 20 return state.tokenize(stream, state);
21 21 }
22 22 else if (ch == "#") {
23 stream.eatWhile(/\w/);
23 stream.eatWhile(/[\w\\\-]/);
24 24 return ret("atom", "hash");
25 25 }
26 26 else if (ch == "!") {
27 27 stream.match(/^\s*\w*/);
28 28 return ret("keyword", "important");
29 29 }
30 30 else if (/\d/.test(ch)) {
31 31 stream.eatWhile(/[\w.%]/);
32 32 return ret("number", "unit");
33 33 }
34 34 else if (/[,.+>*\/]/.test(ch)) {
35 35 return ret(null, "select-op");
36 36 }
37 37 else if (/[;{}:\[\]]/.test(ch)) {
38 38 return ret(null, ch);
39 39 }
40 40 else {
41 stream.eatWhile(/[\w\\\-_]/);
41 stream.eatWhile(/[\w\\\-]/);
42 42 return ret("variable", "variable");
43 43 }
44 44 }
45 45
46 46 function tokenCComment(stream, state) {
47 47 var maybeEnd = false, ch;
48 48 while ((ch = stream.next()) != null) {
49 49 if (maybeEnd && ch == "/") {
50 50 state.tokenize = tokenBase;
51 51 break;
52 52 }
53 53 maybeEnd = (ch == "*");
54 54 }
55 55 return ret("comment", "comment");
56 56 }
57 57
58 58 function tokenSGMLComment(stream, state) {
59 59 var dashes = 0, ch;
60 60 while ((ch = stream.next()) != null) {
61 61 if (dashes >= 2 && ch == ">") {
62 62 state.tokenize = tokenBase;
63 63 break;
64 64 }
65 65 dashes = (ch == "-") ? dashes + 1 : 0;
66 66 }
67 67 return ret("comment", "comment");
68 68 }
69 69
70 70 function tokenString(quote) {
71 71 return function(stream, state) {
72 72 var escaped = false, ch;
73 73 while ((ch = stream.next()) != null) {
74 74 if (ch == quote && !escaped)
75 75 break;
76 76 escaped = !escaped && ch == "\\";
77 77 }
78 78 if (!escaped) state.tokenize = tokenBase;
79 79 return ret("string", "string");
80 80 };
81 81 }
82 82
83 83 return {
84 84 startState: function(base) {
85 85 return {tokenize: tokenBase,
86 86 baseIndent: base || 0,
87 87 stack: []};
88 88 },
89 89
90 90 token: function(stream, state) {
91 91 if (stream.eatSpace()) return null;
92 92 var style = state.tokenize(stream, state);
93 93
94 94 var context = state.stack[state.stack.length-1];
95 95 if (type == "hash" && context == "rule") style = "atom";
96 96 else if (style == "variable") {
97 97 if (context == "rule") style = "number";
98 98 else if (!context || context == "@media{") style = "tag";
99 99 }
100 100
101 101 if (context == "rule" && /^[\{\};]$/.test(type))
102 102 state.stack.pop();
103 103 if (type == "{") {
104 104 if (context == "@media") state.stack[state.stack.length-1] = "@media{";
105 105 else state.stack.push("{");
106 106 }
107 107 else if (type == "}") state.stack.pop();
108 108 else if (type == "@media") state.stack.push("@media");
109 109 else if (context == "{" && type != "comment") state.stack.push("rule");
110 110 return style;
111 111 },
112 112
113 113 indent: function(state, textAfter) {
114 114 var n = state.stack.length;
115 115 if (/^\}/.test(textAfter))
116 116 n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
117 117 return state.baseIndent + n * indentUnit;
118 118 },
119 119
120 120 electricChars: "}"
121 121 };
122 122 });
123 123
124 124 CodeMirror.defineMIME("text/css", "css");
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/css/index.html to IPython/frontend/html/notebook/static/codemirror/mode/css/index.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/htmlmixed/htmlmixed.js to IPython/frontend/html/notebook/static/codemirror/mode/htmlmixed/htmlmixed.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/htmlmixed/index.html to IPython/frontend/html/notebook/static/codemirror/mode/htmlmixed/index.html
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/javascript/index.html to IPython/frontend/html/notebook/static/codemirror/mode/javascript/index.html
@@ -1,348 +1,352 b''
1 1 CodeMirror.defineMode("javascript", function(config, parserConfig) {
2 2 var indentUnit = config.indentUnit;
3 3 var jsonMode = parserConfig.json;
4 4
5 5 // Tokenizer
6 6
7 7 var keywords = function(){
8 8 function kw(type) {return {type: type, style: "keyword"};}
9 9 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10 10 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11 11 return {
12 12 "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13 13 "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14 14 "var": kw("var"), "function": kw("function"), "catch": kw("catch"),
15 15 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
16 16 "in": operator, "typeof": operator, "instanceof": operator,
17 17 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
18 18 };
19 19 }();
20 20
21 21 var isOperatorChar = /[+\-*&%=<>!?|]/;
22 22
23 23 function chain(stream, state, f) {
24 24 state.tokenize = f;
25 25 return f(stream, state);
26 26 }
27 27
28 28 function nextUntilUnescaped(stream, end) {
29 29 var escaped = false, next;
30 30 while ((next = stream.next()) != null) {
31 31 if (next == end && !escaped)
32 32 return false;
33 33 escaped = !escaped && next == "\\";
34 34 }
35 35 return escaped;
36 36 }
37 37
38 38 // Used as scratch variables to communicate multiple values without
39 39 // consing up tons of objects.
40 40 var type, content;
41 41 function ret(tp, style, cont) {
42 42 type = tp; content = cont;
43 43 return style;
44 44 }
45 45
46 46 function jsTokenBase(stream, state) {
47 47 var ch = stream.next();
48 48 if (ch == '"' || ch == "'")
49 49 return chain(stream, state, jsTokenString(ch));
50 50 else if (/[\[\]{}\(\),;\:\.]/.test(ch))
51 51 return ret(ch);
52 52 else if (ch == "0" && stream.eat(/x/i)) {
53 53 stream.eatWhile(/[\da-f]/i);
54 54 return ret("number", "number");
55 55 }
56 56 else if (/\d/.test(ch)) {
57 57 stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
58 58 return ret("number", "number");
59 59 }
60 60 else if (ch == "/") {
61 61 if (stream.eat("*")) {
62 62 return chain(stream, state, jsTokenComment);
63 63 }
64 64 else if (stream.eat("/")) {
65 65 stream.skipToEnd();
66 66 return ret("comment", "comment");
67 67 }
68 68 else if (state.reAllowed) {
69 69 nextUntilUnescaped(stream, "/");
70 70 stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
71 71 return ret("regexp", "string");
72 72 }
73 73 else {
74 74 stream.eatWhile(isOperatorChar);
75 75 return ret("operator", null, stream.current());
76 76 }
77 77 }
78 else if (ch == "#") {
79 stream.skipToEnd();
80 return ret("error", "error");
81 }
78 82 else if (isOperatorChar.test(ch)) {
79 83 stream.eatWhile(isOperatorChar);
80 84 return ret("operator", null, stream.current());
81 85 }
82 86 else {
83 87 stream.eatWhile(/[\w\$_]/);
84 88 var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
85 89 return known ? ret(known.type, known.style, word) :
86 90 ret("variable", "variable", word);
87 91 }
88 92 }
89 93
90 94 function jsTokenString(quote) {
91 95 return function(stream, state) {
92 96 if (!nextUntilUnescaped(stream, quote))
93 97 state.tokenize = jsTokenBase;
94 98 return ret("string", "string");
95 99 };
96 100 }
97 101
98 102 function jsTokenComment(stream, state) {
99 103 var maybeEnd = false, ch;
100 104 while (ch = stream.next()) {
101 105 if (ch == "/" && maybeEnd) {
102 106 state.tokenize = jsTokenBase;
103 107 break;
104 108 }
105 109 maybeEnd = (ch == "*");
106 110 }
107 111 return ret("comment", "comment");
108 112 }
109 113
110 114 // Parser
111 115
112 116 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
113 117
114 118 function JSLexical(indented, column, type, align, prev, info) {
115 119 this.indented = indented;
116 120 this.column = column;
117 121 this.type = type;
118 122 this.prev = prev;
119 123 this.info = info;
120 124 if (align != null) this.align = align;
121 125 }
122 126
123 127 function inScope(state, varname) {
124 128 for (var v = state.localVars; v; v = v.next)
125 129 if (v.name == varname) return true;
126 130 }
127 131
128 132 function parseJS(state, style, type, content, stream) {
129 133 var cc = state.cc;
130 134 // Communicate our context to the combinators.
131 135 // (Less wasteful than consing up a hundred closures on every call.)
132 136 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
133 137
134 138 if (!state.lexical.hasOwnProperty("align"))
135 139 state.lexical.align = true;
136 140
137 141 while(true) {
138 142 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
139 143 if (combinator(type, content)) {
140 144 while(cc.length && cc[cc.length - 1].lex)
141 145 cc.pop()();
142 146 if (cx.marked) return cx.marked;
143 147 if (type == "variable" && inScope(state, content)) return "variable-2";
144 148 return style;
145 149 }
146 150 }
147 151 }
148 152
149 153 // Combinator utils
150 154
151 155 var cx = {state: null, column: null, marked: null, cc: null};
152 156 function pass() {
153 157 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
154 158 }
155 159 function cont() {
156 160 pass.apply(null, arguments);
157 161 return true;
158 162 }
159 163 function register(varname) {
160 164 var state = cx.state;
161 165 if (state.context) {
162 166 cx.marked = "def";
163 167 for (var v = state.localVars; v; v = v.next)
164 168 if (v.name == varname) return;
165 169 state.localVars = {name: varname, next: state.localVars};
166 170 }
167 171 }
168 172
169 173 // Combinators
170 174
171 175 var defaultVars = {name: "this", next: {name: "arguments"}};
172 176 function pushcontext() {
173 177 if (!cx.state.context) cx.state.localVars = defaultVars;
174 178 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
175 179 }
176 180 function popcontext() {
177 181 cx.state.localVars = cx.state.context.vars;
178 182 cx.state.context = cx.state.context.prev;
179 183 }
180 184 function pushlex(type, info) {
181 185 var result = function() {
182 186 var state = cx.state;
183 187 state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
184 188 };
185 189 result.lex = true;
186 190 return result;
187 191 }
188 192 function poplex() {
189 193 var state = cx.state;
190 194 if (state.lexical.prev) {
191 195 if (state.lexical.type == ")")
192 196 state.indented = state.lexical.indented;
193 197 state.lexical = state.lexical.prev;
194 198 }
195 199 }
196 200 poplex.lex = true;
197 201
198 202 function expect(wanted) {
199 203 return function expecting(type) {
200 204 if (type == wanted) return cont();
201 205 else if (wanted == ";") return pass();
202 206 else return cont(arguments.callee);
203 207 };
204 208 }
205 209
206 210 function statement(type) {
207 211 if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
208 212 if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
209 213 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
210 214 if (type == "{") return cont(pushlex("}"), block, poplex);
211 215 if (type == ";") return cont();
212 216 if (type == "function") return cont(functiondef);
213 217 if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
214 218 poplex, statement, poplex);
215 219 if (type == "variable") return cont(pushlex("stat"), maybelabel);
216 220 if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
217 221 block, poplex, poplex);
218 222 if (type == "case") return cont(expression, expect(":"));
219 223 if (type == "default") return cont(expect(":"));
220 224 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
221 225 statement, poplex, popcontext);
222 226 return pass(pushlex("stat"), expression, expect(";"), poplex);
223 227 }
224 228 function expression(type) {
225 229 if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
226 230 if (type == "function") return cont(functiondef);
227 231 if (type == "keyword c") return cont(expression);
228 232 if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
229 233 if (type == "operator") return cont(expression);
230 234 if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
231 235 if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
232 236 return cont();
233 237 }
234 238 function maybeoperator(type, value) {
235 239 if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
236 240 if (type == "operator") return cont(expression);
237 241 if (type == ";") return;
238 242 if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
239 243 if (type == ".") return cont(property, maybeoperator);
240 244 if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
241 245 }
242 246 function maybelabel(type) {
243 247 if (type == ":") return cont(poplex, statement);
244 248 return pass(maybeoperator, expect(";"), poplex);
245 249 }
246 250 function property(type) {
247 251 if (type == "variable") {cx.marked = "property"; return cont();}
248 252 }
249 253 function objprop(type) {
250 254 if (type == "variable") cx.marked = "property";
251 255 if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
252 256 }
253 257 function commasep(what, end) {
254 258 function proceed(type) {
255 259 if (type == ",") return cont(what, proceed);
256 260 if (type == end) return cont();
257 261 return cont(expect(end));
258 262 }
259 263 return function commaSeparated(type) {
260 264 if (type == end) return cont();
261 265 else return pass(what, proceed);
262 266 };
263 267 }
264 268 function block(type) {
265 269 if (type == "}") return cont();
266 270 return pass(statement, block);
267 271 }
268 272 function vardef1(type, value) {
269 273 if (type == "variable"){register(value); return cont(vardef2);}
270 274 return cont();
271 275 }
272 276 function vardef2(type, value) {
273 277 if (value == "=") return cont(expression, vardef2);
274 278 if (type == ",") return cont(vardef1);
275 279 }
276 280 function forspec1(type) {
277 281 if (type == "var") return cont(vardef1, forspec2);
278 282 if (type == ";") return pass(forspec2);
279 283 if (type == "variable") return cont(formaybein);
280 284 return pass(forspec2);
281 285 }
282 286 function formaybein(type, value) {
283 287 if (value == "in") return cont(expression);
284 288 return cont(maybeoperator, forspec2);
285 289 }
286 290 function forspec2(type, value) {
287 291 if (type == ";") return cont(forspec3);
288 292 if (value == "in") return cont(expression);
289 293 return cont(expression, expect(";"), forspec3);
290 294 }
291 295 function forspec3(type) {
292 296 if (type != ")") cont(expression);
293 297 }
294 298 function functiondef(type, value) {
295 299 if (type == "variable") {register(value); return cont(functiondef);}
296 300 if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
297 301 }
298 302 function funarg(type, value) {
299 303 if (type == "variable") {register(value); return cont();}
300 304 }
301 305
302 306 // Interface
303 307
304 308 return {
305 309 startState: function(basecolumn) {
306 310 return {
307 311 tokenize: jsTokenBase,
308 312 reAllowed: true,
309 313 cc: [],
310 314 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
311 315 localVars: null,
312 316 context: null,
313 317 indented: 0
314 318 };
315 319 },
316 320
317 321 token: function(stream, state) {
318 322 if (stream.sol()) {
319 323 if (!state.lexical.hasOwnProperty("align"))
320 324 state.lexical.align = false;
321 325 state.indented = stream.indentation();
322 326 }
323 327 if (stream.eatSpace()) return null;
324 328 var style = state.tokenize(stream, state);
325 329 if (type == "comment") return style;
326 330 state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
327 331 return parseJS(state, style, type, content, stream);
328 332 },
329 333
330 334 indent: function(state, textAfter) {
331 335 if (state.tokenize != jsTokenBase) return 0;
332 336 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
333 337 type = lexical.type, closing = firstChar == type;
334 338 if (type == "vardef") return lexical.indented + 4;
335 339 else if (type == "form" && firstChar == "{") return lexical.indented;
336 340 else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
337 341 else if (lexical.info == "switch" && !closing)
338 342 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
339 343 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
340 344 else return lexical.indented + (closing ? 0 : indentUnit);
341 345 },
342 346
343 347 electricChars: ":{}"
344 348 };
345 349 });
346 350
347 351 CodeMirror.defineMIME("text/javascript", "javascript");
348 352 CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/LICENSE.txt to IPython/frontend/html/notebook/static/codemirror/mode/python/LICENSE.txt
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/python/index.html to IPython/frontend/html/notebook/static/codemirror/mode/python/index.html, modified file
@@ -1,321 +1,324 b''
1 CodeMirror.defineMode("python", function(conf) {
1 CodeMirror.defineMode("python", function(conf, parserConf) {
2 2 var ERRORCLASS = 'error';
3 3
4 4 function wordRegexp(words) {
5 5 return new RegExp("^((" + words.join(")|(") + "))\\b");
6 6 }
7 7
8 // IPython-specific changes: add '?' as recognized character.
9 //var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
8 10 var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]");
11 // End IPython changes.
12
9 13 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10 14 var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11 15 var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12 16 var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13 17 var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14 18
15 19 var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
16 20 var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
17 21 'def', 'del', 'elif', 'else', 'except', 'finally',
18 22 'for', 'from', 'global', 'if', 'import',
19 23 'lambda', 'pass', 'raise', 'return',
20 24 'try', 'while', 'with', 'yield'];
21 25 var commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
22 26 'float', 'frozenset', 'int', 'list', 'object',
23 27 'property', 'reversed', 'set', 'slice', 'staticmethod',
24 28 'str', 'super', 'tuple', 'type'];
25 29 var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
26 30 'xrange'],
27 31 'keywords': ['exec', 'print']};
28 32 var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
29 33 'open', 'range', 'zip'],
30 34 'keywords': ['nonlocal']};
31 35
32 if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
36 if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
33 37 commonkeywords = commonkeywords.concat(py3.keywords);
34 38 commontypes = commontypes.concat(py3.types);
35 39 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
36 40 } else {
37 41 commonkeywords = commonkeywords.concat(py2.keywords);
38 42 commontypes = commontypes.concat(py2.types);
39 43 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
40 44 }
41 45 var keywords = wordRegexp(commonkeywords);
42 46 var types = wordRegexp(commontypes);
43 47
44 48 var indentInfo = null;
45 49
46 50 // tokenizers
47 51 function tokenBase(stream, state) {
48 52 // Handle scope changes
49 53 if (stream.sol()) {
50 54 var scopeOffset = state.scopes[0].offset;
51 55 if (stream.eatSpace()) {
52 56 var lineOffset = stream.indentation();
53 57 if (lineOffset > scopeOffset) {
54 58 indentInfo = 'indent';
55 59 } else if (lineOffset < scopeOffset) {
56 60 indentInfo = 'dedent';
57 61 }
58 62 return null;
59 63 } else {
60 64 if (scopeOffset > 0) {
61 65 dedent(stream, state);
62 66 }
63 67 }
64 68 }
65 69 if (stream.eatSpace()) {
66 70 return null;
67 71 }
68 72
69 73 var ch = stream.peek();
70 74
71 75 // Handle Comments
72 76 if (ch === '#') {
73 77 stream.skipToEnd();
74 78 return 'comment';
75 79 }
76 80
77 81 // Handle Number Literals
78 82 if (stream.match(/^[0-9\.]/, false)) {
79 83 var floatLiteral = false;
80 84 // Floats
81 85 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
82 86 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
83 87 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
84 88 if (floatLiteral) {
85 89 // Float literals may be "imaginary"
86 90 stream.eat(/J/i);
87 91 return 'number';
88 92 }
89 93 // Integers
90 94 var intLiteral = false;
91 95 // Hex
92 96 if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
93 97 // Binary
94 98 if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
95 99 // Octal
96 100 if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
97 101 // Decimal
98 102 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
99 103 // Decimal literals may be "imaginary"
100 104 stream.eat(/J/i);
101 105 // TODO - Can you have imaginary longs?
102 106 intLiteral = true;
103 107 }
104 108 // Zero by itself with no other piece of number.
105 109 if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
106 110 if (intLiteral) {
107 111 // Integer literals may be "long"
108 112 stream.eat(/L/i);
109 113 return 'number';
110 114 }
111 115 }
112 116
113 117 // Handle Strings
114 118 if (stream.match(stringPrefixes)) {
115 119 state.tokenize = tokenStringFactory(stream.current());
116 120 return state.tokenize(stream, state);
117 121 }
118 122
119 123 // Handle operators and Delimiters
120 124 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
121 125 return null;
122 126 }
123 127 if (stream.match(doubleOperators)
124 128 || stream.match(singleOperators)
125 129 || stream.match(wordOperators)) {
126 130 return 'operator';
127 131 }
128 132 if (stream.match(singleDelimiters)) {
129 133 return null;
130 134 }
131 135
132 136 if (stream.match(types)) {
133 137 return 'builtin';
134 138 }
135 139
136 140 if (stream.match(keywords)) {
137 141 return 'keyword';
138 142 }
139 143
140 144 if (stream.match(identifiers)) {
141 145 return 'variable';
142 146 }
143 147
144 148 // Handle non-detected items
145 149 stream.next();
146 150 return ERRORCLASS;
147 151 }
148 152
149 153 function tokenStringFactory(delimiter) {
150 while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
154 while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
151 155 delimiter = delimiter.substr(1);
152 156 }
153 var delim_re = new RegExp(delimiter);
154 157 var singleline = delimiter.length == 1;
155 158 var OUTCLASS = 'string';
156 159
157 160 return function tokenString(stream, state) {
158 161 while (!stream.eol()) {
159 162 stream.eatWhile(/[^'"\\]/);
160 163 if (stream.eat('\\')) {
161 164 stream.next();
162 165 if (singleline && stream.eol()) {
163 166 return OUTCLASS;
164 167 }
165 } else if (stream.match(delim_re)) {
168 } else if (stream.match(delimiter)) {
166 169 state.tokenize = tokenBase;
167 170 return OUTCLASS;
168 171 } else {
169 172 stream.eat(/['"]/);
170 173 }
171 174 }
172 175 if (singleline) {
173 if (conf.mode.singleLineStringErrors) {
174 OUTCLASS = ERRORCLASS
176 if (parserConf.singleLineStringErrors) {
177 return ERRORCLASS;
175 178 } else {
176 179 state.tokenize = tokenBase;
177 180 }
178 181 }
179 182 return OUTCLASS;
180 183 };
181 184 }
182 185
183 186 function indent(stream, state, type) {
184 187 type = type || 'py';
185 188 var indentUnit = 0;
186 189 if (type === 'py') {
187 190 for (var i = 0; i < state.scopes.length; ++i) {
188 191 if (state.scopes[i].type === 'py') {
189 192 indentUnit = state.scopes[i].offset + conf.indentUnit;
190 193 break;
191 194 }
192 195 }
193 196 } else {
194 197 indentUnit = stream.column() + stream.current().length;
195 198 }
196 199 state.scopes.unshift({
197 200 offset: indentUnit,
198 201 type: type
199 202 });
200 203 }
201 204
202 205 function dedent(stream, state) {
203 206 if (state.scopes.length == 1) return;
204 207 if (state.scopes[0].type === 'py') {
205 208 var _indent = stream.indentation();
206 209 var _indent_index = -1;
207 210 for (var i = 0; i < state.scopes.length; ++i) {
208 211 if (_indent === state.scopes[i].offset) {
209 212 _indent_index = i;
210 213 break;
211 214 }
212 215 }
213 216 if (_indent_index === -1) {
214 217 return true;
215 218 }
216 219 while (state.scopes[0].offset !== _indent) {
217 220 state.scopes.shift();
218 221 }
219 222 return false
220 223 } else {
221 224 state.scopes.shift();
222 225 return false;
223 226 }
224 227 }
225 228
226 229 function tokenLexer(stream, state) {
227 230 indentInfo = null;
228 231 var style = state.tokenize(stream, state);
229 232 var current = stream.current();
230 233
231 234 // Handle '.' connected identifiers
232 235 if (current === '.') {
233 236 style = state.tokenize(stream, state);
234 237 current = stream.current();
235 238 if (style === 'variable') {
236 239 return 'variable';
237 240 } else {
238 241 return ERRORCLASS;
239 242 }
240 243 }
241 244
242 245 // Handle decorators
243 246 if (current === '@') {
244 247 style = state.tokenize(stream, state);
245 248 current = stream.current();
246 249 if (style === 'variable'
247 250 || current === '@staticmethod'
248 251 || current === '@classmethod') {
249 252 return 'meta';
250 253 } else {
251 254 return ERRORCLASS;
252 255 }
253 256 }
254 257
255 258 // Handle scope changes.
256 259 if (current === 'pass' || current === 'return') {
257 260 state.dedent += 1;
258 261 }
259 262 if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
260 263 || indentInfo === 'indent') {
261 264 indent(stream, state);
262 265 }
263 266 var delimiter_index = '[({'.indexOf(current);
264 267 if (delimiter_index !== -1) {
265 268 indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
266 269 }
267 270 if (indentInfo === 'dedent') {
268 271 if (dedent(stream, state)) {
269 272 return ERRORCLASS;
270 273 }
271 274 }
272 275 delimiter_index = '])}'.indexOf(current);
273 276 if (delimiter_index !== -1) {
274 277 if (dedent(stream, state)) {
275 278 return ERRORCLASS;
276 279 }
277 280 }
278 281 if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
279 282 if (state.scopes.length > 1) state.scopes.shift();
280 283 state.dedent -= 1;
281 284 }
282 285
283 286 return style;
284 287 }
285 288
286 289 var external = {
287 290 startState: function(basecolumn) {
288 291 return {
289 292 tokenize: tokenBase,
290 293 scopes: [{offset:basecolumn || 0, type:'py'}],
291 294 lastToken: null,
292 295 lambda: false,
293 296 dedent: 0
294 297 };
295 298 },
296 299
297 300 token: function(stream, state) {
298 301 var style = tokenLexer(stream, state);
299 302
300 303 state.lastToken = {style:style, content: stream.current()};
301 304
302 305 if (stream.eol() && stream.lambda) {
303 306 state.lambda = false;
304 307 }
305 308
306 309 return style;
307 310 },
308 311
309 312 indent: function(state, textAfter) {
310 313 if (state.tokenize != tokenBase) {
311 314 return 0;
312 315 }
313 316
314 317 return state.scopes[0].offset;
315 318 }
316 319
317 320 };
318 321 return external;
319 322 });
320 323
321 324 CodeMirror.defineMIME("text/x-python", "python");
@@ -1,526 +1,525 b''
1 1 <!doctype html>
2 2 <html>
3 3 <head>
4 4 <title>CodeMirror 2: reStructuredText mode</title>
5 5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 6 <script src="../../lib/codemirror.js"></script>
7 7 <script src="rst.js"></script>
8 8 <link rel="stylesheet" href="rst.css">
9 9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 10 <link rel="stylesheet" href="../../css/docs.css">
11 11 </head>
12 12 <body>
13 13 <h1>CodeMirror 2: reStructuredText mode</h1>
14 14
15 15 <form><textarea id="code" name="code">
16 16 .. This is an excerpt from Sphinx documentation: http://sphinx.pocoo.org/_sources/rest.txt
17 17
18 18 .. highlightlang:: rest
19 19
20 20 .. _rst-primer:
21 21
22 22 reStructuredText Primer
23 23 =======================
24 24
25 25 This section is a brief introduction to reStructuredText (reST) concepts and
26 26 syntax, intended to provide authors with enough information to author documents
27 27 productively. Since reST was designed to be a simple, unobtrusive markup
28 28 language, this will not take too long.
29 29
30 30 .. seealso::
31 31
32 32 The authoritative `reStructuredText User Documentation
33 33 &lt;http://docutils.sourceforge.net/rst.html&gt;`_. The "ref" links in this
34 34 document link to the description of the individual constructs in the reST
35 35 reference.
36 36
37 37
38 38 Paragraphs
39 39 ----------
40 40
41 41 The paragraph (:duref:`ref &lt;paragraphs&gt;`) is the most basic block in a reST
42 42 document. Paragraphs are simply chunks of text separated by one or more blank
43 43 lines. As in Python, indentation is significant in reST, so all lines of the
44 44 same paragraph must be left-aligned to the same level of indentation.
45 45
46 46
47 47 .. _inlinemarkup:
48 48
49 49 Inline markup
50 50 -------------
51 51
52 52 The standard reST inline markup is quite simple: use
53 53
54 54 * one asterisk: ``*text*`` for emphasis (italics),
55 55 * two asterisks: ``**text**`` for strong emphasis (boldface), and
56 56 * backquotes: ````text```` for code samples.
57 57
58 58 If asterisks or backquotes appear in running text and could be confused with
59 59 inline markup delimiters, they have to be escaped with a backslash.
60 60
61 61 Be aware of some restrictions of this markup:
62 62
63 63 * it may not be nested,
64 64 * content may not start or end with whitespace: ``* text*`` is wrong,
65 65 * it must be separated from surrounding text by non-word characters. Use a
66 66 backslash escaped space to work around that: ``thisis\ *one*\ word``.
67 67
68 68 These restrictions may be lifted in future versions of the docutils.
69 69
70 70 reST also allows for custom "interpreted text roles"', which signify that the
71 71 enclosed text should be interpreted in a specific way. Sphinx uses this to
72 72 provide semantic markup and cross-referencing of identifiers, as described in
73 73 the appropriate section. The general syntax is ``:rolename:`content```.
74 74
75 75 Standard reST provides the following roles:
76 76
77 77 * :durole:`emphasis` -- alternate spelling for ``*emphasis*``
78 78 * :durole:`strong` -- alternate spelling for ``**strong**``
79 79 * :durole:`literal` -- alternate spelling for ````literal````
80 80 * :durole:`subscript` -- subscript text
81 81 * :durole:`superscript` -- superscript text
82 82 * :durole:`title-reference` -- for titles of books, periodicals, and other
83 83 materials
84 84
85 85 See :ref:`inline-markup` for roles added by Sphinx.
86 86
87 87
88 88 Lists and Quote-like blocks
89 89 ---------------------------
90 90
91 91 List markup (:duref:`ref &lt;bullet-lists&gt;`) is natural: just place an asterisk at
92 92 the start of a paragraph and indent properly. The same goes for numbered lists;
93 93 they can also be autonumbered using a ``#`` sign::
94 94
95 95 * This is a bulleted list.
96 96 * It has two items, the second
97 97 item uses two lines.
98 98
99 99 1. This is a numbered list.
100 100 2. It has two items too.
101 101
102 102 #. This is a numbered list.
103 103 #. It has two items too.
104 104
105 105
106 106 Nested lists are possible, but be aware that they must be separated from the
107 107 parent list items by blank lines::
108 108
109 109 * this is
110 110 * a list
111 111
112 112 * with a nested list
113 113 * and some subitems
114 114
115 115 * and here the parent list continues
116 116
117 117 Definition lists (:duref:`ref &lt;definition-lists&gt;`) are created as follows::
118 118
119 119 term (up to a line of text)
120 120 Definition of the term, which must be indented
121 121
122 122 and can even consist of multiple paragraphs
123 123
124 124 next term
125 125 Description.
126 126
127 127 Note that the term cannot have more than one line of text.
128 128
129 129 Quoted paragraphs (:duref:`ref &lt;block-quotes&gt;`) are created by just indenting
130 130 them more than the surrounding paragraphs.
131 131
132 132 Line blocks (:duref:`ref &lt;line-blocks&gt;`) are a way of preserving line breaks::
133 133
134 134 | These lines are
135 135 | broken exactly like in
136 136 | the source file.
137 137
138 138 There are also several more special blocks available:
139 139
140 140 * field lists (:duref:`ref &lt;field-lists&gt;`)
141 141 * option lists (:duref:`ref &lt;option-lists&gt;`)
142 142 * quoted literal blocks (:duref:`ref &lt;quoted-literal-blocks&gt;`)
143 143 * doctest blocks (:duref:`ref &lt;doctest-blocks&gt;`)
144 144
145 145
146 146 Source Code
147 147 -----------
148 148
149 149 Literal code blocks (:duref:`ref &lt;literal-blocks&gt;`) are introduced by ending a
150 150 paragraph with the special marker ``::``. The literal block must be indented
151 151 (and, like all paragraphs, separated from the surrounding ones by blank lines)::
152 152
153 153 This is a normal text paragraph. The next paragraph is a code sample::
154 154
155 155 It is not processed in any way, except
156 156 that the indentation is removed.
157 157
158 158 It can span multiple lines.
159 159
160 160 This is a normal text paragraph again.
161 161
162 162 The handling of the ``::`` marker is smart:
163 163
164 164 * If it occurs as a paragraph of its own, that paragraph is completely left
165 165 out of the document.
166 166 * If it is preceded by whitespace, the marker is removed.
167 167 * If it is preceded by non-whitespace, the marker is replaced by a single
168 168 colon.
169 169
170 170 That way, the second sentence in the above example's first paragraph would be
171 171 rendered as "The next paragraph is a code sample:".
172 172
173 173
174 174 .. _rst-tables:
175 175
176 176 Tables
177 177 ------
178 178
179 179 Two forms of tables are supported. For *grid tables* (:duref:`ref
180 180 &lt;grid-tables&gt;`), you have to "paint" the cell grid yourself. They look like
181 181 this::
182 182
183 183 +------------------------+------------+----------+----------+
184 184 | Header row, column 1 | Header 2 | Header 3 | Header 4 |
185 185 | (header rows optional) | | | |
186 186 +========================+============+==========+==========+
187 187 | body row 1, column 1 | column 2 | column 3 | column 4 |
188 188 +------------------------+------------+----------+----------+
189 189 | body row 2 | ... | ... | |
190 190 +------------------------+------------+----------+----------+
191 191
192 192 *Simple tables* (:duref:`ref &lt;simple-tables&gt;`) are easier to write, but
193 193 limited: they must contain more than one row, and the first column cannot
194 194 contain multiple lines. They look like this::
195 195
196 196 ===== ===== =======
197 197 A B A and B
198 198 ===== ===== =======
199 199 False False False
200 200 True False False
201 201 False True False
202 202 True True True
203 203 ===== ===== =======
204 204
205 205
206 206 Hyperlinks
207 207 ----------
208 208
209 209 External links
210 210 ^^^^^^^^^^^^^^
211 211
212 212 Use ```Link text &lt;http://example.com/&gt;`_`` for inline web links. If the link
213 213 text should be the web address, you don't need special markup at all, the parser
214 214 finds links and mail addresses in ordinary text.
215 215
216 216 You can also separate the link and the target definition (:duref:`ref
217 217 &lt;hyperlink-targets&gt;`), like this::
218 218
219 219 This is a paragraph that contains `a link`_.
220 220
221 221 .. _a link: http://example.com/
222 222
223 223
224 224 Internal links
225 225 ^^^^^^^^^^^^^^
226 226
227 227 Internal linking is done via a special reST role provided by Sphinx, see the
228 228 section on specific markup, :ref:`ref-role`.
229 229
230 230
231 231 Sections
232 232 --------
233 233
234 234 Section headers (:duref:`ref &lt;sections&gt;`) are created by underlining (and
235 235 optionally overlining) the section title with a punctuation character, at least
236 236 as long as the text::
237 237
238 238 =================
239 239 This is a heading
240 240 =================
241 241
242 242 Normally, there are no heading levels assigned to certain characters as the
243 243 structure is determined from the succession of headings. However, for the
244 244 Python documentation, this convention is used which you may follow:
245 245
246 246 * ``#`` with overline, for parts
247 247 * ``*`` with overline, for chapters
248 248 * ``=``, for sections
249 249 * ``-``, for subsections
250 250 * ``^``, for subsubsections
251 251 * ``"``, for paragraphs
252 252
253 253 Of course, you are free to use your own marker characters (see the reST
254 254 documentation), and use a deeper nesting level, but keep in mind that most
255 255 target formats (HTML, LaTeX) have a limited supported nesting depth.
256 256
257 257
258 258 Explicit Markup
259 259 ---------------
260 260
261 261 "Explicit markup" (:duref:`ref &lt;explicit-markup-blocks&gt;`) is used in reST for
262 262 most constructs that need special handling, such as footnotes,
263 263 specially-highlighted paragraphs, comments, and generic directives.
264 264
265 265 An explicit markup block begins with a line starting with ``..`` followed by
266 266 whitespace and is terminated by the next paragraph at the same level of
267 267 indentation. (There needs to be a blank line between explicit markup and normal
268 268 paragraphs. This may all sound a bit complicated, but it is intuitive enough
269 269 when you write it.)
270 270
271 271
272 272 .. _directives:
273 273
274 274 Directives
275 275 ----------
276 276
277 277 A directive (:duref:`ref &lt;directives&gt;`) is a generic block of explicit markup.
278 278 Besides roles, it is one of the extension mechanisms of reST, and Sphinx makes
279 279 heavy use of it.
280 280
281 281 Docutils supports the following directives:
282 282
283 283 * Admonitions: :dudir:`attention`, :dudir:`caution`, :dudir:`danger`,
284 284 :dudir:`error`, :dudir:`hint`, :dudir:`important`, :dudir:`note`,
285 285 :dudir:`tip`, :dudir:`warning` and the generic :dudir:`admonition`.
286 286 (Most themes style only "note" and "warning" specially.)
287 287
288 288 * Images:
289 289
290 290 - :dudir:`image` (see also Images_ below)
291 291 - :dudir:`figure` (an image with caption and optional legend)
292 292
293 293 * Additional body elements:
294 294
295 295 - :dudir:`contents` (a local, i.e. for the current file only, table of
296 296 contents)
297 297 - :dudir:`container` (a container with a custom class, useful to generate an
298 298 outer ``&lt;div&gt;`` in HTML)
299 299 - :dudir:`rubric` (a heading without relation to the document sectioning)
300 300 - :dudir:`topic`, :dudir:`sidebar` (special highlighted body elements)
301 301 - :dudir:`parsed-literal` (literal block that supports inline markup)
302 302 - :dudir:`epigraph` (a block quote with optional attribution line)
303 303 - :dudir:`highlights`, :dudir:`pull-quote` (block quotes with their own
304 304 class attribute)
305 305 - :dudir:`compound` (a compound paragraph)
306 306
307 307 * Special tables:
308 308
309 309 - :dudir:`table` (a table with title)
310 310 - :dudir:`csv-table` (a table generated from comma-separated values)
311 311 - :dudir:`list-table` (a table generated from a list of lists)
312 312
313 313 * Special directives:
314 314
315 315 - :dudir:`raw` (include raw target-format markup)
316 316 - :dudir:`include` (include reStructuredText from another file)
317 317 -- in Sphinx, when given an absolute include file path, this directive takes
318 318 it as relative to the source directory
319 319 - :dudir:`class` (assign a class attribute to the next element) [1]_
320 320
321 321 * HTML specifics:
322 322
323 323 - :dudir:`meta` (generation of HTML ``&lt;meta&gt;`` tags)
324 324 - :dudir:`title` (override document title)
325 325
326 326 * Influencing markup:
327 327
328 328 - :dudir:`default-role` (set a new default role)
329 329 - :dudir:`role` (create a new role)
330 330
331 331 Since these are only per-file, better use Sphinx' facilities for setting the
332 332 :confval:`default_role`.
333 333
334 334 Do *not* use the directives :dudir:`sectnum`, :dudir:`header` and
335 335 :dudir:`footer`.
336 336
337 337 Directives added by Sphinx are described in :ref:`sphinxmarkup`.
338 338
339 339 Basically, a directive consists of a name, arguments, options and content. (Keep
340 340 this terminology in mind, it is used in the next chapter describing custom
341 341 directives.) Looking at this example, ::
342 342
343 343 .. function:: foo(x)
344 344 foo(y, z)
345 345 :module: some.module.name
346 346
347 347 Return a line of text input from the user.
348 348
349 349 ``function`` is the directive name. It is given two arguments here, the
350 350 remainder of the first line and the second line, as well as one option
351 351 ``module`` (as you can see, options are given in the lines immediately following
352 352 the arguments and indicated by the colons). Options must be indented to the
353 353 same level as the directive content.
354 354
355 355 The directive content follows after a blank line and is indented relative to the
356 356 directive start.
357 357
358 358
359 359 Images
360 360 ------
361 361
362 362 reST supports an image directive (:dudir:`ref &lt;image&gt;`), used like so::
363 363
364 364 .. image:: gnu.png
365 365 (options)
366 366
367 367 When used within Sphinx, the file name given (here ``gnu.png``) must either be
368 368 relative to the source file, or absolute which means that they are relative to
369 369 the top source directory. For example, the file ``sketch/spam.rst`` could refer
370 370 to the image ``images/spam.png`` as ``../images/spam.png`` or
371 371 ``/images/spam.png``.
372 372
373 373 Sphinx will automatically copy image files over to a subdirectory of the output
374 374 directory on building (e.g. the ``_static`` directory for HTML output.)
375 375
376 376 Interpretation of image size options (``width`` and ``height``) is as follows:
377 377 if the size has no unit or the unit is pixels, the given size will only be
378 378 respected for output channels that support pixels (i.e. not in LaTeX output).
379 379 Other units (like ``pt`` for points) will be used for HTML and LaTeX output.
380 380
381 381 Sphinx extends the standard docutils behavior by allowing an asterisk for the
382 382 extension::
383 383
384 384 .. image:: gnu.*
385 385
386 386 Sphinx then searches for all images matching the provided pattern and determines
387 387 their type. Each builder then chooses the best image out of these candidates.
388 388 For instance, if the file name ``gnu.*`` was given and two files :file:`gnu.pdf`
389 389 and :file:`gnu.png` existed in the source tree, the LaTeX builder would choose
390 390 the former, while the HTML builder would prefer the latter.
391 391
392 392 .. versionchanged:: 0.4
393 393 Added the support for file names ending in an asterisk.
394 394
395 395 .. versionchanged:: 0.6
396 396 Image paths can now be absolute.
397 397
398 398
399 399 Footnotes
400 400 ---------
401 401
402 402 For footnotes (:duref:`ref &lt;footnotes&gt;`), use ``[#name]_`` to mark the footnote
403 403 location, and add the footnote body at the bottom of the document after a
404 404 "Footnotes" rubric heading, like so::
405 405
406 406 Lorem ipsum [#f1]_ dolor sit amet ... [#f2]_
407 407
408 408 .. rubric:: Footnotes
409 409
410 410 .. [#f1] Text of the first footnote.
411 411 .. [#f2] Text of the second footnote.
412 412
413 413 You can also explicitly number the footnotes (``[1]_``) or use auto-numbered
414 414 footnotes without names (``[#]_``).
415 415
416 416
417 417 Citations
418 418 ---------
419 419
420 420 Standard reST citations (:duref:`ref &lt;citations&gt;`) are supported, with the
421 421 additional feature that they are "global", i.e. all citations can be referenced
422 422 from all files. Use them like so::
423 423
424 424 Lorem ipsum [Ref]_ dolor sit amet.
425 425
426 426 .. [Ref] Book or article reference, URL or whatever.
427 427
428 428 Citation usage is similar to footnote usage, but with a label that is not
429 429 numeric or begins with ``#``.
430 430
431 431
432 432 Substitutions
433 433 -------------
434 434
435 435 reST supports "substitutions" (:duref:`ref &lt;substitution-definitions&gt;`), which
436 436 are pieces of text and/or markup referred to in the text by ``|name|``. They
437 437 are defined like footnotes with explicit markup blocks, like this::
438 438
439 439 .. |name| replace:: replacement *text*
440 440
441 441 or this::
442 442
443 443 .. |caution| image:: warning.png
444 444 :alt: Warning!
445 445
446 446 See the :duref:`reST reference for substitutions &lt;substitution-definitions&gt;`
447 447 for details.
448 448
449 449 If you want to use some substitutions for all documents, put them into
450 450 :confval:`rst_prolog` or put them into a separate file and include it into all
451 451 documents you want to use them in, using the :rst:dir:`include` directive. (Be
452 452 sure to give the include file a file name extension differing from that of other
453 453 source files, to avoid Sphinx finding it as a standalone document.)
454 454
455 455 Sphinx defines some default substitutions, see :ref:`default-substitutions`.
456 456
457 457
458 458 Comments
459 459 --------
460 460
461 461 Every explicit markup block which isn't a valid markup construct (like the
462 462 footnotes above) is regarded as a comment (:duref:`ref &lt;comments&gt;`). For
463 463 example::
464 464
465 465 .. This is a comment.
466 466
467 467 You can indent text after a comment start to form multiline comments::
468 468
469 469 ..
470 470 This whole indented block
471 471 is a comment.
472 472
473 473 Still in the comment.
474 474
475 475
476 476 Source encoding
477 477 ---------------
478 478
479 479 Since the easiest way to include special characters like em dashes or copyright
480 480 signs in reST is to directly write them as Unicode characters, one has to
481 481 specify an encoding. Sphinx assumes source files to be encoded in UTF-8 by
482 482 default; you can change this with the :confval:`source_encoding` config value.
483 483
484 484
485 485 Gotchas
486 486 -------
487 487
488 488 There are some problems one commonly runs into while authoring reST documents:
489 489
490 490 * **Separation of inline markup:** As said above, inline markup spans must be
491 491 separated from the surrounding text by non-word characters, you have to use a
492 492 backslash-escaped space to get around that. See `the reference
493 493 &lt;http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup&gt;`_
494 494 for the details.
495 495
496 496 * **No nested inline markup:** Something like ``*see :func:`foo`*`` is not
497 497 possible.
498 498
499 499
500 500 .. rubric:: Footnotes
501 501
502 502 .. [1] When the default domain contains a :rst:dir:`class` directive, this directive
503 503 will be shadowed. Therefore, Sphinx re-exports it as :rst:dir:`rst-class`.
504 504 </textarea></form>
505 505
506 506 <script>
507 507 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
508 508 lineNumbers: true,
509 509 });
510 510 </script>
511 511 <p>The reStructuredText mode supports one configuration parameter:</p>
512 512 <dl>
513 513 <dt><code>verbatim (string)</code></dt>
514 514 <dd>A name or MIME type of a mode that will be used for highlighting
515 515 verbatim blocks. By default, reStructuredText mode uses uniform color
516 516 for whole block of verbatim text if no mode is given.</dd>
517 517 </dl>
518 518 <p>If <code>python</code> mode is available (not a part of CodeMirror 2 yet),
519 519 it will be used for highlighting blocks containing Python/IPython terminal
520 520 sessions (blocks starting with <code>&gt;&gt;&gt;</code> (for Python) or
521 521 <code>In [num]:</code> (for IPython).
522 522
523 523 <p><strong>MIME types defined:</strong> <code>text/x-rst</code>.</p>
524 524 </body>
525 525 </html>
526
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/rst/rst.css to IPython/frontend/html/notebook/static/codemirror/mode/rst/rst.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/rst/rst.js to IPython/frontend/html/notebook/static/codemirror/mode/rst/rst.js
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/mode/xml/index.html to IPython/frontend/html/notebook/static/codemirror/mode/xml/index.html
@@ -1,231 +1,231 b''
1 1 CodeMirror.defineMode("xml", function(config, parserConfig) {
2 2 var indentUnit = config.indentUnit;
3 3 var Kludges = parserConfig.htmlMode ? {
4 4 autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
5 5 "meta": true, "col": true, "frame": true, "base": true, "area": true},
6 6 doNotIndent: {"pre": true, "!cdata": true},
7 7 allowUnquoted: true
8 8 } : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, allowUnquoted: false};
9 9 var alignCDATA = parserConfig.alignCDATA;
10 10
11 11 // Return variables for tokenizers
12 12 var tagName, type;
13 13
14 14 function inText(stream, state) {
15 15 function chain(parser) {
16 16 state.tokenize = parser;
17 17 return parser(stream, state);
18 18 }
19 19
20 20 var ch = stream.next();
21 21 if (ch == "<") {
22 22 if (stream.eat("!")) {
23 23 if (stream.eat("[")) {
24 24 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
25 25 else return null;
26 26 }
27 27 else if (stream.match("--")) return chain(inBlock("comment", "-->"));
28 28 else if (stream.match("DOCTYPE", true, true)) {
29 29 stream.eatWhile(/[\w\._\-]/);
30 30 return chain(inBlock("meta", ">"));
31 31 }
32 32 else return null;
33 33 }
34 34 else if (stream.eat("?")) {
35 35 stream.eatWhile(/[\w\._\-]/);
36 36 state.tokenize = inBlock("meta", "?>");
37 37 return "meta";
38 38 }
39 39 else {
40 40 type = stream.eat("/") ? "closeTag" : "openTag";
41 41 stream.eatSpace();
42 42 tagName = "";
43 43 var c;
44 44 while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
45 45 state.tokenize = inTag;
46 46 return "tag";
47 47 }
48 48 }
49 49 else if (ch == "&") {
50 50 stream.eatWhile(/[^;]/);
51 51 stream.eat(";");
52 52 return "atom";
53 53 }
54 54 else {
55 55 stream.eatWhile(/[^&<]/);
56 56 return null;
57 57 }
58 58 }
59 59
60 60 function inTag(stream, state) {
61 61 var ch = stream.next();
62 62 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
63 63 state.tokenize = inText;
64 64 type = ch == ">" ? "endTag" : "selfcloseTag";
65 65 return "tag";
66 66 }
67 67 else if (ch == "=") {
68 68 type = "equals";
69 69 return null;
70 70 }
71 71 else if (/[\'\"]/.test(ch)) {
72 72 state.tokenize = inAttribute(ch);
73 73 return state.tokenize(stream, state);
74 74 }
75 75 else {
76 76 stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
77 77 return "word";
78 78 }
79 79 }
80 80
81 81 function inAttribute(quote) {
82 82 return function(stream, state) {
83 83 while (!stream.eol()) {
84 84 if (stream.next() == quote) {
85 85 state.tokenize = inTag;
86 86 break;
87 87 }
88 88 }
89 89 return "string";
90 90 };
91 91 }
92 92
93 93 function inBlock(style, terminator) {
94 94 return function(stream, state) {
95 95 while (!stream.eol()) {
96 96 if (stream.match(terminator)) {
97 97 state.tokenize = inText;
98 98 break;
99 99 }
100 100 stream.next();
101 101 }
102 102 return style;
103 103 };
104 104 }
105 105
106 106 var curState, setStyle;
107 107 function pass() {
108 108 for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
109 109 }
110 110 function cont() {
111 111 pass.apply(null, arguments);
112 112 return true;
113 113 }
114 114
115 115 function pushContext(tagName, startOfLine) {
116 116 var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
117 117 curState.context = {
118 118 prev: curState.context,
119 119 tagName: tagName,
120 120 indent: curState.indented,
121 121 startOfLine: startOfLine,
122 122 noIndent: noIndent
123 123 };
124 124 }
125 125 function popContext() {
126 126 if (curState.context) curState.context = curState.context.prev;
127 127 }
128 128
129 129 function element(type) {
130 130 if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));}
131 131 else if (type == "closeTag") {
132 132 var err = false;
133 133 if (curState.context) {
134 134 err = curState.context.tagName != tagName;
135 popContext();
136 135 } else {
137 136 err = true;
138 137 }
139 138 if (err) setStyle = "error";
140 139 return cont(endclosetag(err));
141 140 }
142 141 else if (type == "string") {
143 142 if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
144 143 if (curState.tokenize == inText) popContext();
145 144 return cont();
146 145 }
147 146 else return cont();
148 147 }
149 148 function endtag(startOfLine) {
150 149 return function(type) {
151 150 if (type == "selfcloseTag" ||
152 151 (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
153 152 return cont();
154 153 if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
155 154 return cont();
156 155 };
157 156 }
158 157 function endclosetag(err) {
159 158 return function(type) {
160 159 if (err) setStyle = "error";
161 if (type == "endTag") return cont();
162 return pass();
160 if (type == "endTag") { popContext(); return cont(); }
161 setStyle = "error";
162 return cont(arguments.callee);
163 163 }
164 164 }
165 165
166 166 function attributes(type) {
167 167 if (type == "word") {setStyle = "attribute"; return cont(attributes);}
168 168 if (type == "equals") return cont(attvalue, attributes);
169 169 return pass();
170 170 }
171 171 function attvalue(type) {
172 172 if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
173 173 if (type == "string") return cont(attvaluemaybe);
174 174 return pass();
175 175 }
176 176 function attvaluemaybe(type) {
177 177 if (type == "string") return cont(attvaluemaybe);
178 178 else return pass();
179 179 }
180 180
181 181 return {
182 182 startState: function() {
183 183 return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
184 184 },
185 185
186 186 token: function(stream, state) {
187 187 if (stream.sol()) {
188 188 state.startOfLine = true;
189 189 state.indented = stream.indentation();
190 190 }
191 191 if (stream.eatSpace()) return null;
192 192
193 193 setStyle = type = tagName = null;
194 194 var style = state.tokenize(stream, state);
195 195 if ((style || type) && style != "comment") {
196 196 curState = state;
197 197 while (true) {
198 198 var comb = state.cc.pop() || element;
199 199 if (comb(type || style)) break;
200 200 }
201 201 }
202 202 state.startOfLine = false;
203 203 return setStyle || style;
204 204 },
205 205
206 206 indent: function(state, textAfter) {
207 207 var context = state.context;
208 208 if (context && context.noIndent) return 0;
209 209 if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
210 210 if (context && /^<\//.test(textAfter))
211 211 context = context.prev;
212 212 while (context && !context.startOfLine)
213 213 context = context.prev;
214 214 if (context) return context.indent + indentUnit;
215 215 else return 0;
216 216 },
217 217
218 218 compareStates: function(a, b) {
219 if (a.indented != b.indented || a.tagName != b.tagName) return false;
219 if (a.indented != b.indented) return false;
220 220 for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
221 221 if (!ca || !cb) return ca == cb;
222 222 if (ca.tagName != cb.tagName) return false;
223 223 }
224 224 },
225 225
226 226 electricChars: "/"
227 227 };
228 228 });
229 229
230 230 CodeMirror.defineMIME("application/xml", "xml");
231 231 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
@@ -1,18 +1,19 b''
1 1 .cm-s-default span.cm-keyword {color: #708;}
2 2 .cm-s-default span.cm-atom {color: #219;}
3 3 .cm-s-default span.cm-number {color: #164;}
4 4 .cm-s-default span.cm-def {color: #00f;}
5 5 .cm-s-default span.cm-variable {color: black;}
6 6 .cm-s-default span.cm-variable-2 {color: #05a;}
7 7 .cm-s-default span.cm-variable-3 {color: #0a5;}
8 8 .cm-s-default span.cm-property {color: black;}
9 9 .cm-s-default span.cm-operator {color: black;}
10 10 .cm-s-default span.cm-comment {color: #a50;}
11 11 .cm-s-default span.cm-string {color: #a11;}
12 .cm-s-default span.cm-string-2 {color: #f50;}
12 13 .cm-s-default span.cm-meta {color: #555;}
13 14 .cm-s-default span.cm-error {color: #f00;}
14 15 .cm-s-default span.cm-qualifier {color: #555;}
15 16 .cm-s-default span.cm-builtin {color: #30a;}
16 17 .cm-s-default span.cm-bracket {color: #cc7;}
17 18 .cm-s-default span.cm-tag {color: #170;}
18 19 .cm-s-default span.cm-attribute {color: #00c;}
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/theme/elegant.css to IPython/frontend/html/notebook/static/codemirror/theme/elegant.css
@@ -1,41 +1,40 b''
1 1
2 2
3 3 .cm-s-ipython span.cm-keyword {color: #008000; font-weight: bold;}
4 4 .cm-s-ipython span.cm-number {color: #666666;}
5 5 .cm-s-ipython span.cm-operator {color: #AA22FF; font-weight: bold;}
6 6 .cm-s-ipython span.cm-meta {color: #AA22FF;}
7 7 .cm-s-ipython span.cm-comment {color: #408080; font-style: italic;}
8 8 .cm-s-ipython span.cm-string {color: #BA2121;}
9 9 .cm-s-ipython span.cm-error {color: #f00;}
10 10 .cm-s-ipython span.cm-builtin {color: #008000;}
11 11 .cm-s-ipython span.cm-variable {color: #000000;}
12 12
13 13 /* These classes are not currently used in the python.js mode */
14 14
15 15 /*.cm-s-ipython span.cm-atom {color: #219;}*/
16 16 /*.cm-s-ipython span.cm-def {color: #00f;}*/
17 17 /*.cm-s-ipython span.cm-variable-2 {color: #05a;}*/
18 18 /*.cm-s-ipython span.cm-variable-3 {color: #0a5;}*/
19 19 /*.cm-s-ipython span.cm-property {color: black;}*/
20 20 /*.cm-s-ipython span.cm-qualifier {color: #555;}*/
21 21 /*.cm-s-ipython span.cm-bracket {color: #cc7;}*/
22 22 /*.cm-s-ipython span.cm-tag {color: #170;}*/
23 23 /*.cm-s-ipython span.cm-attribute {color: #00c;}*/
24 24
25 25 /* These are the old styles for our pre-themed version */
26 26
27 27 /*span.py-delimiter {color: #666666;}*/
28 28 /*span.py-special {color: #666666;}*/
29 29 /*span.py-operator {color: #AA22FF; font-weight: bold;}*/
30 30 /*span.py-keyword {color: #008000; font-weight: bold;}*/
31 31 /*span.py-number {color: #666666;}*/
32 32 /*span.py-identifier {color: #000000;}*/
33 33 /*span.py-func {color: #000000;}*/
34 34 /*span.py-type {color: #008000;}*/
35 35 /*span.py-decorator {color: #AA22FF;}*/
36 36 /*span.py-comment {color: #408080; font-style: italic;}*/
37 37 /*span.py-string {color: #BA2121;}*/
38 38 /*span.py-bytes {color: #BA2121;}*/
39 39 /*span.py-raw {color: #BA2121;}*/
40 40 /*span.py-unicode {color: #BA2121;}*/
41
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/theme/neat.css to IPython/frontend/html/notebook/static/codemirror/theme/neat.css
1 NO CONTENT: file renamed from IPython/frontend/html/notebook/static/codemirror-2.12/theme/night.css to IPython/frontend/html/notebook/static/codemirror/theme/night.css
@@ -1,244 +1,246 b''
1 1 <!DOCTYPE HTML>
2 2 <html>
3 3
4 4 <head>
5 5 <meta charset="utf-8">
6 6
7 7 <title>IPython Notebook</title>
8 8
9 9 <link rel="stylesheet" href="static/jquery/css/themes/aristo/jquery-wijmo.css" type="text/css" />
10 10 <!-- <link rel="stylesheet" href="static/jquery/css/themes/rocket/jquery-wijmo.css" type="text/css" /> -->
11 11 <!-- <link rel="stylesheet" href="static/jquery/css/themes/smoothness/jquery-ui-1.8.14.custom.css" type="text/css" />-->
12 12
13 13 <!-- <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" charset="utf-8"></script> -->
14 14 <script type='text/javascript' src='static/mathjax/MathJax.js?config=TeX-AMS_HTML' charset='utf-8'></script>
15 15 <script type="text/javascript">
16 16 if (typeof MathJax == 'undefined') {
17 17 console.log("No local MathJax, loading from CDN");
18 18 document.write(unescape("%3Cscript type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js%3Fconfig=TeX-AMS_HTML' charset='utf-8'%3E%3C/script%3E"));
19 19 }else{
20 20 console.log("Using local MathJax");
21 21 }
22 22 </script>
23 23
24 <link rel="stylesheet" href="static/codemirror-2.12/lib/codemirror.css">
25 <link rel="stylesheet" href="static/codemirror-2.12/mode/rst/rst.css">
26 <link rel="stylesheet" href="static/codemirror-2.12/theme/ipython.css">
27 <link rel="stylesheet" href="static/codemirror-2.12/theme/default.css">
24 <link rel="stylesheet" href="static/codemirror/lib/codemirror.css">
25 <link rel="stylesheet" href="static/codemirror/mode/markdown/markdown.css">
26 <link rel="stylesheet" href="static/codemirror/mode/rst/rst.css">
27 <link rel="stylesheet" href="static/codemirror/theme/ipython.css">
28 <link rel="stylesheet" href="static/codemirror/theme/default.css">
28 29
29 30 <link rel="stylesheet" href="static/prettify/prettify.css"/>
30 31
31 32 <link rel="stylesheet" href="static/css/boilerplate.css" type="text/css" />
32 33 <link rel="stylesheet" href="static/css/layout.css" type="text/css" />
33 34 <link rel="stylesheet" href="static/css/base.css" type="text/css" />
34 35 <link rel="stylesheet" href="static/css/notebook.css" type="text/css" />
35 36 <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" />
36 37
37 38
38 39 </head>
39 40
40 41 <body>
41 42
42 43 <div id="header">
43 44 <span id="ipython_notebook"><h1>IPython Notebook</h1></span>
44 45 <span id="save_widget">
45 46 <input type="text" id="notebook_name" size="20"></textarea>
46 47 <span id="notebook_id" style="display:none">{{notebook_id}}</span>
47 48 <button id="save_notebook"><u>S</u>ave</button>
48 49 </span>
49 50 <span id="kernel_status">Idle</span>
50 51 </div>
51 52
52 53 <div id="main_app">
53 54
54 55 <div id="left_panel">
55 56
56 57 <div id="notebook_section">
57 58 <h3 class="section_header">Notebook</h3>
58 59 <div class="section_content">
59 60 <div class="section_row">
60 61 <span id="new_open" class="section_row_buttons">
61 62 <button id="new_notebook">New</button>
62 63 <button id="open_notebook">Open</button>
63 64 </span>
64 65 <span class="section_row_header">Actions</span>
65 66 </div>
66 67 <div class="section_row">
67 68 <span>
68 69 <select id="download_format">
69 70 <option value="json">ipynb</option>
70 71 <option value="py">py</option>
71 72 </select>
72 73 </span>
73 74 <span class="section_row_buttons">
74 75 <button id="download_notebook">Download</button>
75 76 </span>
76 77 </div>
77 78 <div class="section_row">
78 79 <span class="section_row_buttons">
79 80 <span id="print_widget">
80 81 <button id="print_notebook">Print</button>
81 82 </span>
82 83 </span>
83 84 </div>
84 85 </div>
85 86 </div>
86 87
87 88 <div id="cell_section">
88 89 <h3 class="section_header">Cell</h3>
89 90 <div class="section_content">
90 91 <div class="section_row">
91 92 <span class="section_row_buttons">
92 93 <button id="delete_cell"><u>D</u>elete</button>
93 94 </span>
94 95 <span class="section_row_header">Actions</span>
95 96 </div>
96 97 <div class="section_row">
97 98 <span id="cell_type" class="section_row_buttons">
98 99 <button id="to_code"><u>C</u>ode</button>
99 100 <!-- <button id="to_html">HTML</button>-->
100 101 <button id="to_markdown"><u>M</u>arkdown</button>
101 102 </span>
102 103 <span class="button_label">Format</span>
103 104 </div>
104 105 <div class="section_row">
105 106 <span id="cell_output" class="section_row_buttons">
106 107 <button id="toggle_output"><u>T</u>oggle</button>
107 108 <button id="clear_all_output">ClearAll</button>
108 109 </span>
109 110 <span class="button_label">Output</span>
110 111 </div>
111 112 <div class="section_row">
112 113 <span id="insert" class="section_row_buttons">
113 114 <button id="insert_cell_above"><u>A</u>bove</button>
114 115 <button id="insert_cell_below"><u>B</u>elow</button>
115 116 </span>
116 117 <span class="button_label">Insert</span>
117 118 </div>
118 119 <div class="section_row">
119 120 <span id="move" class="section_row_buttons">
120 121 <button id="move_cell_up">Up</button>
121 122 <button id="move_cell_down">Down</button>
122 123 </span>
123 124 <span class="button_label">Move</span>
124 125 </div>
125 126 <div class="section_row">
126 127 <span id="run_cells" class="section_row_buttons">
127 128 <button id="run_selected_cell">Selected</button>
128 129 <button id="run_all_cells">All</button>
129 130 </span>
130 131 <span class="button_label">Run</span>
131 132 </div>
132 133 <div class="section_row">
133 134 <span id="autoindent_span">
134 135 <input type="checkbox" id="autoindent" checked="true"></input>
135 136 </span>
136 137 <span class="checkbox_label">Autoindent:</span>
137 138 </div>
138 139 </div>
139 140 </div>
140 141
141 142 <div id="kernel_section">
142 143 <h3 class="section_header">Kernel</h3>
143 144 <div class="section_content">
144 145 <div class="section_row">
145 146 <span id="int_restart" class="section_row_buttons">
146 147 <button id="int_kernel">Interrupt</button>
147 148 <button id="restart_kernel">Restart</button>
148 149 </span>
149 150 <span class="section_row_header">Actions</span>
150 151 </div>
151 152 <div class="section_row">
152 153 <span id="kernel_persist">
153 154 <input type="checkbox" id="kill_kernel"></input>
154 155 </span>
155 156 <span class="checkbox_label">Kill kernel upon exit:</span>
156 157 </div>
157 158 </div>
158 159 </div>
159 160
160 161 <div id="help_section">
161 162 <h3 class="section_header">Help</h3>
162 163 <div class="section_content">
163 164 <div class="section_row">
164 165 <span id="help_buttons0" class="section_row_buttons">
165 166 <a id="python_help" href="http://docs.python.org" target="_blank">Python</a>
166 167 <a id="ipython_help" href="http://ipython.org/documentation.html" target="_blank">IPython</a>
167 168 </span>
168 169 <span class="section_row_header">Links</span>
169 170 </div>
170 171 <div class="section_row">
171 172 <span id="help_buttons1" class="section_row_buttons">
172 173 <a id="numpy_help" href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a>
173 174 <a id="scipy_help" href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a>
174 175 </span>
175 176 </div>
176 177 <div class="section_row">
177 178 <span id="help_buttons2" class="section_row_buttons">
178 179 <a id="matplotlib_help" href="http://matplotlib.sourceforge.net/" target="_blank">MPL</a>
179 180 <a id="sympy_help" href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a>
180 181 </span>
181 182 </div>
182 183 <div class="section_row">
183 184 <span class="help_string">run selected cell</span>
184 185 <span class="help_string_label">Shift-Enter :</span>
185 186 </div>
186 187 <div class="section_row">
187 188 <span class="help_string">run in terminal mode</span>
188 189 <span class="help_string_label">Ctrl-Enter :</span>
189 190 </div>
190 191 <div class="section_row">
191 192 <span class="help_string">show keyboard shortcuts</span>
192 193 <span class="help_string_label">Ctrl-m h :</span>
193 194 </div>
194 195 </div>
195 196 </div>
196 197
197 198 </div>
198 199 <div id="left_panel_splitter"></div>
199 200 <div id="notebook_panel">
200 201 <div id="notebook"></div>
201 202 <div id="pager_splitter"></div>
202 203 <div id="pager"></div>
203 204 </div>
204 205
205 206 </div>
206 207
207 208 <script src="static/jquery/js/jquery-1.6.2.min.js" type="text/javascript" charset="utf-8"></script>
208 209 <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script>
209 210 <script src="static/jquery/js/jquery.autogrow.js" type="text/javascript" charset="utf-8"></script>
210 211
211 <script src="static/codemirror-2.12/lib/codemirror.js" charset="utf-8"></script>
212 <script src="static/codemirror-2.12/mode/python/python.js" charset="utf-8"></script>
213 <script src="static/codemirror-2.12/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
214 <script src="static/codemirror-2.12/mode/xml/xml.js" charset="utf-8"></script>
215 <script src="static/codemirror-2.12/mode/javascript/javascript.js" charset="utf-8"></script>
216 <script src="static/codemirror-2.12/mode/css/css.js" charset="utf-8"></script>
217 <script src="static/codemirror-2.12/mode/rst/rst.js" charset="utf-8"></script>
212 <script src="static/codemirror/lib/codemirror.js" charset="utf-8"></script>
213 <script src="static/codemirror/mode/python/python.js" charset="utf-8"></script>
214 <script src="static/codemirror/mode/htmlmixed/htmlmixed.js" charset="utf-8"></script>
215 <script src="static/codemirror/mode/xml/xml.js" charset="utf-8"></script>
216 <script src="static/codemirror/mode/javascript/javascript.js" charset="utf-8"></script>
217 <script src="static/codemirror/mode/css/css.js" charset="utf-8"></script>
218 <script src="static/codemirror/mode/rst/rst.js" charset="utf-8"></script>
219 <script src="static/codemirror/mode/markdown/markdown.js" charset="utf-8"></script>
218 220
219 221 <script src="static/pagedown/Markdown.Converter.js" charset="utf-8"></script>
220 222
221 223 <script src="static/prettify/prettify.js" charset="utf-8"></script>
222 224
223 225 <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script>
224 226 <script src="static/js/utils.js" type="text/javascript" charset="utf-8"></script>
225 227 <script src="static/js/cell.js" type="text/javascript" charset="utf-8"></script>
226 228 <script src="static/js/codecell.js" type="text/javascript" charset="utf-8"></script>
227 229 <script src="static/js/textcell.js" type="text/javascript" charset="utf-8"></script>
228 230 <script src="static/js/kernel.js" type="text/javascript" charset="utf-8"></script>
229 231 <script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
230 232 <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
231 233 <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
232 234 <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
233 235 <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
234 236 <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
235 237 <script src="static/js/leftpanel.js" type="text/javascript" charset="utf-8"></script>
236 238 <script src="static/js/notebook.js" type="text/javascript" charset="utf-8"></script>
237 239 <script src="static/js/notebook_main.js" type="text/javascript" charset="utf-8"></script>
238 240
239 241
240 242 </body>
241 243
242 244 </html>
243 245
244 246
General Comments 0
You need to be logged in to leave comments. Login now